Previous Page Next Page

Defining Data Models

Hour 2 mentioned that Django uses data models to define classes of data objects that belong to a particular application. Each application has its own models.py file that contains the Python code that defines that application's data model.

Django has an extensive package, models.django.db, that contains several predefined class field types that help you define data objects as well as a set of options to manage the behavior of those fields.

Did you Know?

Django has a backend engine that runs SQL commands to create tables for each object and relationship.


Understanding Field Types

You can add several different types of fields to your data model. The benefit of having different types of fields is that the Django engine can understand what type of data should be in the field. Django has built-in validation that simplifies the process of verifying that the right type of data is being added to an object in the model. Django also can use the field type to display the field properly in predefined and admin views.

The following sections describe some of the field types that you will use the most.

Text Fields

You will use two main field types for simple text fields.

The CharField type is designed for smaller strings with specific length limitations, such as names or titles. CharField tells Django that the field is expecting text data. It requires that a maximum length be specified using the max_length argument:

name = models.CharField('Name', max_length=100)

The TextField type is designed for larger strings of text, such as a description. TextField tells Django that the field is expecting a variable amount of text. You can specify a maximum size for TextField using the max_length argument, as shown here, but this is not required:

desc = models.TextField('Desc', max_length=1000)

Date and Time Fields

You can use three different types of fields when adding date and time fields to your models. DateField, TimeField, and DateTimeField are designed to accept a date, time, and date with time of day value, respectively:

    bday = models.DateField('Birthday')
    alarm = models.TimeField('Alarm')
    appnt = models.DateTimeField('Appointment')

All three date and time field types accept the following two optional arguments:

EmailField

EmailField is similar to CharField, with two notable differences. Django verifies that the value entered into this field is a valid email address. Also, this field does not accept the max_length argument. The maximum length is automatically set to 75 characters.

File Fields

You will use two types of file fields. The first is the standard FileField, which is used to upload files to the website. FileField requires an upload_to argument that specifies a path, relative to MEDIA_ROOT, on the local file system of the web server to store the file, as shown here:

doc = models.FileField('File', upload_to='documents')

By the Way

The MEDIA_ROOT path is specified in the settings.py file. No path is defined by default, so you must define one.


Did you Know?

The path you specify in upload_to can contain Python's strftime formatting, which is replaced by the data and time of the file upload. This can be useful if you want to control file uploads.


The second type of field is the ImageField. The ImageField is very similar to the FileField except that in validation, the ImageField will validate the file as a valid image file. The ImageField also includes two extra optional arguments, height_field and width_field that contain height and width of the image. These fields are autopopulated when the object is saved.

URLField

URLField is similar to TextField. It also accepts the max_length argument. URLField also accepts the verify_exists argument. If this argument is set to True (the default), Django checks the URL to verify that it exists before accepting it:

location = models.URLField('WebPage', verify_exists=True, max_length=100)

Try It Yourself: Add Fields to a Model

The previous sections have discussed several different types of fields that can be applied to a model for specific purposes. In this section, you apply that knowledge to extend the Person class by adding fields to it.

Follow these steps to add a DateField, EmailField, and URLField to the Person class in the iFriends database:

1.
Make certain that the development server has stopped by pressing Ctrl+Break from the console.

2.
Open the iFriends\People\models.py file in an editor.

3.
Add the following code line to the models.py file to import the User class from Django's authentication model:

from django.contrib.auth.models import User

4.
Add the code shown in Listing 3.2 to the Person class to add a birthday DateField, an email EmailField, and a favorite URL URLField.

Listing 3.2. Full Contents of the iFriends\People\models.py File Showing the New Fields in the Person Model

from django.db import models
from django.contrib.auth.models import User

class Person(models.Model):
    name = models.CharField('name', max_length=200)
    birthday = models.DateField('Birthday')
    email = models.EmailField('Email')
    favoriteURL = models.URLField('myURL')
    desc = models.TextField('Desc', max_length=500)

    def __str__(self):
        return '%s' % (self.name)

    class Admin:
       pass

5.
Save the file.

6.
Clear the old Person table in the database by using the following SQL command:

drop table people_person;

Watch Out!

You need to remove the Person table in the database because, currently, Django doesn't have a good way to update the data. Any objects that were created in the Person table will be deleted.

7.
Sync the model to the database using the following command from the root directory of the iFriends project:

python manage.py syncdb

8.
Enter the following command to start the development server:

python manage.py runserver

9.
Access the Django admin interface at http://127.0.0.1:8000/admin, and log in as the superuser.

10.
Click the Add button next to Persons in the People section, as shown in Figure 3.8.

Figure 3.8. Add link for Persons on the main page for Django's admin interface.


11.
Figure 3.9 shows that the new fields were added to the Person object.

Figure 3.9. Add page for a Person object in Django's admin interface.



Adding Field Options to a Field Type

Django provides several options that can be applied to fields to control their behavior in the SQL database as well as Django's admin interface. The following sections discuss some of the most common options that can be passed as arguments to field definitions. These arguments are all optional and are available to all Django field types.

null and blank Field Options

Django provides two different options that allow you to leave fields blank when adding new objects. The null option tells Django to store any fields left blank as the NULL in the database:

count = models.Integer('count', null=True)

The blank option tells Django's validation engine to allow the field to be left blank:

count = models.Integer('count', blank=True)

There is a big difference between the null and blank options. The null option is strictly at the database level. The blank option is used by the validation engine on the Django admin site. This means that if you want to allow null values to be stored in the database and accessed in your code, you will need to set both the null and blank options to True.

Watch Out!

Use the null=True argument on only nonstring-type fields such as dates, files, and integers. When you use the blank=True option, Django stores the empty string as the value of the field.


Did you Know?

Both the blank and null options are set to False by default. If you want to allow fields to be left blank in web forms and in the database, you must set these options to True.


default Field Option

The default option allows you to specify a value that will be applied to the field by default:

title = models.Integer('Title', default='<no title>')

choices Field Option

The choices field option allows you to specify a list of two tuples to use as viable values in the field. Django's model validation accepts only values specified in the choices field option when validating form entry. When this option is used, the Django admin interface provides a selection box for you to make your choice.

By the Way

The value of choices doesn't necessarily need to be a list or tuple. It can be any Python iterable object.


This code snippet shows how to add a list of choices to a field definition:

gender_list = (('M', 'Male'), ('F', 'Female' ))
. . .
    gender = models.CharField(max_length=1, choices=gender_list)

core Field Option

The core field option is used when you relate objects to another object in the model. The Django admin interface lets you specify that multiple objects that are related to each other can be edited inline together.

Fields that have core=True set are treated as required fields in the object. When all the fields that have core=True set are cleared in the admin interface, the object is deleted.

editable Field Option

The editable field can be useful if you have a field, such as the modified time stamp shown here, that you do not want to be edited by the admin interface or Django's default forms. Fields are editable by default. However, if you specify editable=False, they cannot be changed in Django's admin interface:

last_modified = models.DateTimeField('Last Modified', auto_now_add=True,
  editable=False)

primary_key Field Option

The primary_key field option allows you to specify which field will be used for the primary key in the database. If you set primary_key=True for a field, blank=False, null=False, and unique=True are implied for the field. Only one primary key is allowed per object.

Did you Know?

If you don't specify a primary key for an object, Django adds the following field behind the scenes:

id=models.AutoField('ID', primary_key=True)


unique Field Options

The unique field option allows you to specify if you want the field's value to be unique throughout the table in the database. When unique=True is set, values are not allowed if they already exist for that field in another object in the database. The unique option is enforced at both the Django admin validation level and the database level.

Django also provides the following field options that allow you to specify uniqueness of objects based on date:

By the Way

The unique_for_date, unique_for_month, and unique_for_year options are enforced only at the Django admin validation level.


Try It Yourself: Add Options to Fields in a Model

The previous sections have discussed several different options that can be applied to fields that control the behavior of the fields in the admin interface and also in the database. In this section, you apply that knowledge to modify the Person class by adding options to fields.

Follow these steps to force the email field to be unique, to allow the birthday and desc fields to be blank in the admin interface and the database, and to add a gender choice field to the class:

1.
Make certain that the development server has stopped by pressing Ctrl+Break from the console.

2.
Open the iFriends\People\models.py file in an editor.

3.
Modify the email field to make certain that it is unique in the table:

email = models.EmailField('Email', max_length=100, unique=True)

4.
Modify the birthday and desc fields to allow them to be left blank in the admin interface and NULL in the database:

birthday = models.DateField('Birthday', blank=True, null=True)
desc = models.TextField('Desc', max_length=500, null=True)

5.
Add the following code snippet to add a gender choice field to the Person class:

gender_list = (('M', 'Male'), ('F', 'Female' ))
. . .
    gender = models.CharField(max_length=1, choices=gender_list)

6.
Save the file. Listing 3.3 shows the results.

Listing 3.3. Full Contents of the iFriends\People\models.py File with New Options in the Fields

from django.db import models
from django.contrib.auth.models import User

gender_list = (('M', 'Male'), ('F', 'Female' ))

class Person(models.Model):
    name = models.CharField('name', max_length=200)
    birthday = models.DateField('Birthday', blank=True, null=True)
    gender = models.CharField(max_length=1, choices=gender_list)
    email = models.EmailField('Email', max_length=100, unique=True)
    favoriteURL = models.URLField('myURL')
    desc = models.TextField('Desc', max_length=500, null=True)

    def __str__(self):
        return '%s' % (self.name)

    class Admin:
       pass

7.
Clear the old Person table in the database by using the following SQL command:

drop table people_person;

Watch Out!

You need to remove the Person table in the database because currently Django doesn't have a good way to update the data. Any objects that were created in the table will be lost.

8.
Sync the model to the database using the following command from the root directory of the iFriends project:

python manage.py syncdb

9.
Enter the following command to start the development server:

python manage.py runserver

10.
Access the Django admin interface at http://127.0.0.1:8000/admin, and log in as the superuser.

11.
Click the Add button next to Persons in the People section (see Figure 3.8).

12.
Figure 3.10 shows that the new fields were added to the Person object.

Figure 3.10. Add page for a Person object in Django's admin interface, with new fields added.


You should see the Gender field now available in the admin interface. Also, the Birthday field label is no longer bold, which means that this field may be left blank. The Desc field is bold because the blank option was not set to True. Remember that you don't need to set the blank option for CharField, because Django allows a zero-length string.


Adding Relationships to Models

As you begin to develop more complex websites using Django, you will find it necessary to link classes within models and also link classes in other models. Django provides a simple but effective means of accomplishing class relationships. The following sections discuss how to define class relationships within models.

Many-to-One Relationships

Arguably the most common type of relationship you will deal with is the many-to-one relationship, in which one object can be related to several others.

Many-to-one relationships are defined by adding a ForeignKey field to a class and specifying a second class as the key. For example, our sample website currently has a Person class defined. If we were to add a Hometown class, several people might come from the same hometown. The code used to define the many-to-one relationship would be similar to the following:

class Hometown(models.model):
. . .
class Person(models.Model):
    hometown = models.ForeignKey(Hometown)

By the Way

If a module has not yet been defined, you can also specify the name of the object instead of the object itself as the argument to ForeignKey. For example:

class Person(models.Model):
    hometown = models.ForeignKey('Hometown')
. . .
class Hometown(models.model):


Did you Know?

You can create a recursive relationship within an object by specifying self as the argument to ForeignKey:

. . . models.ForeignKey('self')


The following are some of the more common optional arguments that you will use with ForeignKey:

Many-to-Many Relationships

Many-to-many relationships are defined by adding a ManyToMany field to a class and specifying a second class as the key. For example, our sample website currently has a Person class defined. If we were to add a Blog class, we might have several persons who belong to several blogs and several blogs that have several people using them. The code used to define the many-to-many relationship would be similar to the following:

class Blog(models.model):
. . .
class Person(models.Model):
    blogs = models.ManyToManyField(Blog)

Did you Know?

You can create a recursive relationship within an object by specifying self as the argument to ManyToMany:

friends = models.ManyToManyField('self')


The following are some of the more common optional arguments you will use with ManyToManyField:

One-to-One Relationships

Quoted from djangoproject.com: "The semantics of one-to-one relationships will be changing soon, so we don't recommend that you use them."

One-to-one relationships are defined by adding a OneToOne field to a class and specifying a second class as the key. For example, our sample website currently has a Person class defined. If we were to add an Alias class that limits each person to have only one Alias, the code used to define the one-to-one relationship would be similar to the following:

class Alias(models.model):
. . .
class Person(models.Model):

Try It Yourself: Add Many-to-One and Many-to-Many Relationships to a Model

The preceding section discussed the different types of relationships that you can add between objects. This section takes you through the steps of adding some relationships to the People model in your iFriends application.

In this section, you will add a many-to-one relationship between the Person class and the User class in Django's authentication system. You also will create a recursive relationship between the Person class and itself, as well as a many-to-many relationship between the Person class and a new Blog class.

1.
Make certain that the development server has stopped by pressing Ctrl+Break from the console.

2.
Open the iFriends\People\models.py file in an editor.

3.
Add the following code snippet to the models.py file to import the User class from Django's authentication model:

from django.contrib.auth.models import User

4.
Add the following code to the Person class to add a many-to-one relationship to the User class in Django's authentication model:

userID = models.ForeignKey(User, unique=True)

5.
Add the following code to the Person class to add a many-to-many recursive relationship between the Person class and itself:

friends = models.ManyToManyField('self', blank=True)

6.
Add the code shown in Listing 3.4 to the People model to add a many-to-many relationship between the Person class and a new Blog class.

Listing 3.4. Full Contents of the iFriends\People\models.py File Adding Many-to-One and Many-to-Many Relationships to a Model

from django.db import models
from django.contrib.auth.models import User

gender_list = (('M', 'Male'), ('F', 'Female' ))

class Blog(models.Model):
    title = models.CharField('Title', maxlength=200)
    text = models.TextField('Text', maxlength=2048)

class Person(models.Model):
    userID = models.ForeignKey(User, unique=True)
    name = models.CharField('name', maxlength=200)
    birthday = models.DateField('Birthday', blank=True, null=True)
    gender = models.CharField(maxlength=1, choices=gender_list)
    email = models.EmailField('Email', maxlength=100, unique=True)
    favoriteURL = models.URLField('myURL')
    desc = models.TextField('Desc', maxlength=500, null=True)
    friends = models.ManyToManyField('self', blank=True)
    blogs = models.ManyToManyField(Blog, blank=True)

    def __str__(self):
        return '%s' % (self.name)

    class Admin:
       pass

7.
Save the file.

8.
Clear the old Person table in the database by using the following SQL command:

drop table people_person;

9.
Sync the model to the database using the following command from the root directory of the iFriends project:

python manage.py syncdb

10.
Enter the following command to start the development server:

python manage.py runserver

11.
Access the Django admin interface at http://127.0.0.1:8000/admin, and log in as the superuser.

12.
Click the Add button next to Persons in the People section, as shown in Figure 3.11.

Figure 3.11. Add link for Persons on the main page for Django's admin interface.


13.
Figure 3.12 shows that the new fields were added to the Person object.

Figure 3.12. Add page for a Person object in Django's admin interface, with more fields added.


In this example, you imported the User class from django.contrib.auth.models so that you can use it as the ForeignKey field. Using the ForeignKey field in this way allows you to access the Django User object from a Person object. You will see this in action later in the book.


Previous Page Next Page