The first Django App

Now we start with the first Django application for our project “cookbook”.

This is how the data model looks like:

An entity–relationship model of the recipes application

  • The name of the app is recipes
  • It has two models: Recipe und Category
  • The id field will be created automatically as primary key by the Django ORM
  • Both models are connected by the n-m relation category
  • Recipe.author is connected to the User model provided by Django’s auth app

Create the app

Because the application will manage recipes we will call it recipes:

$ cd cookbook
$ python manage.py startapp recipes

This command will create a directory recipes containing these four files:

recipes
|-- __init__.py
|-- models.py
|-- tests.py
`-- views.py

Create the Models

Now open the file models.py in a text editor. It contains only a single import:

from django.db import models

To prevent problems with the encoding add the following line before the import:

# encoding: utf-8

A Model for the categories

Now start with the model for the categories:

# encoding: utf-8
from django.db import models


class Category(models.Model):
    """Category model."""
    name = models.CharField('Name', max_length=100)
    slug = models.SlugField(unique=True)
    description = models.TextField('Description', blank=True)

The next step is to extend the class Category:

    class Meta:
        verbose_name = 'Category'
        verbose_name_plural = 'Categories'

    def __unicode__(self):
        return self.name

A Model for the recipes

Let’s start with the second model for the recipes:

class Recipe(models.Model):
    """Recipe model."""
    title = models.CharField('Title', max_length=255)
    slug = models.SlugField(unique=True)
    ingredients = models.TextField('Ingredients',
        help_text='One ingredient per line')
    preparation = models.TextField('Preparation')
    time_for_preparation = models.IntegerField('Time for preparation',
        help_text='Time in minutes', blank=True, null=True)
    number_of_portions = models.PositiveIntegerField('Number of portions')
    difficulty = models.SmallIntegerField('Difficulty',
        choices=DIFFICULTIES, default=DIFFICULTY_MEDIUM)
    category = models.ManyToManyField(Category, verbose_name='Categories')
    author = models.ForeignKey(User, verbose_name='Author')
    photo = models.ImageField(upload_to='recipes', verbose_name='Photo')
    date_created = models.DateTimeField(editable=False)
    date_updated = models.DateTimeField(editable=False)

We habe to add another import for the User class:

from django.contrib.auth.models import User

Add some constants for the difficulty field at the top of the class:

    DIFFICULTY_EASY = 1
    DIFFICULTY_MEDIUM = 2
    DIFFICULTY_HARD = 3
    DIFFICULTIES = (
        (DIFFICULTY_EASY, 'simple'),
        (DIFFICULTY_MEDIUM, 'normal'),
        (DIFFICULTY_HARD, 'hard'),
    )

Again we have to add a Meta class and a __unicode__ method for the Recipe class:

    class Meta:
        verbose_name = 'Recipe'
        verbose_name_plural = 'Recipes'
        ordering = ['-date_created']

    def __unicode__(self):
        return self.title

Because we want to populate the date fields automatically we have to overload the save method:

    def save(self, *args, **kwargs):
        if not self.id:
            self.date_created = now()
        self.date_updated = now()
        super(Recipe, self).save(*args, **kwargs)

At the end of the save method we call the super function to call the parent method.

Finally we have to add the now function at the top of the file:

from django.utils.timezone import now

Note

PEP 8, the Python documentation and this short article provide more information about the import statement.

The complete file

When everything is complete, the file models.py should look as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# encoding: utf-8
from django.contrib.auth.models import User
from django.db import models
from django.utils.timezone import now


class Category(models.Model):
    """Category model."""
    name = models.CharField('Name', max_length=100)
    slug = models.SlugField(unique=True)
    description = models.TextField('Description', blank=True)

    class Meta:
        verbose_name = 'Category'
        verbose_name_plural = 'Categories'

    def __unicode__(self):
        return self.name


class Recipe(models.Model):
    """Recipe model."""
    DIFFICULTY_EASY = 1
    DIFFICULTY_MEDIUM = 2
    DIFFICULTY_HARD = 3
    DIFFICULTIES = (
        (DIFFICULTY_EASY, 'simple'),
        (DIFFICULTY_MEDIUM, 'normal'),
        (DIFFICULTY_HARD, 'hard'),
    )
    title = models.CharField('Title', max_length=255)
    slug = models.SlugField(unique=True)
    ingredients = models.TextField('Ingredients',
        help_text='One ingredient per line')
    preparation = models.TextField('Preparation')
    time_for_preparation = models.IntegerField('Time for preparation',
        help_text='Time in minutes', blank=True, null=True)
    number_of_portions = models.PositiveIntegerField('Number of portions')
    difficulty = models.SmallIntegerField('Difficulty',
        choices=DIFFICULTIES, default=DIFFICULTY_MEDIUM)
    category = models.ManyToManyField(Category, verbose_name='Categories')
    author = models.ForeignKey(User, verbose_name='Author')
    photo = models.ImageField(upload_to='recipes', verbose_name='Photo')
    date_created = models.DateTimeField(editable=False)
    date_updated = models.DateTimeField(editable=False)

    class Meta:
        verbose_name = 'Recipe'
        verbose_name_plural = 'Recipes'
        ordering = ['-date_created']

    def __unicode__(self):
        return self.title

    def save(self, *args, **kwargs):
        if not self.id:
            self.date_created = now()
        self.date_updated = now()
        super(Recipe, self).save(*args, **kwargs)

Activating the app

Open the file settings.py and add the name of our new application at the end of the INSTALLED_APPS setting.

Now INSTALLED_APPS looks like this:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'recipes',
)

Table Of Contents

Previous topic

A new Django Project

Next topic

The Admin application

This Page

Languages

Support

If you love django-workshop, consider making a small donation on Flattr:

Useful Links