DAY-2: Django Model and Admin Site

In the first class you have got familiar with c9 workspace and created a basic Django project. Now we are going to take a closer look at the Django “model”.

1. Django Model

The Django model is the “heart” of your Django application. It represents your data in a very clean and clear way. From this model Django can automatically create your database and a powerful admin GUI that can handle all sorts of insert, update and delete actions.

Let’s take a simple example. Imagine you want to build an “Employee Database” for your company. The requirements are:

  • It should have an online Web GUI to enter new employees, update existing ones, delete ones leaving the company and create lists of all employes.
  • It should have a user and session management (you have to login to enter new employees).
  • It should have complex search functions (searching, filtering, ordering etc.).
  • It should sanitize all input parameters for valid type and length and implement best security practices.
  • An employee has a name, an email, gender, job title, salary and a birthdate.

How long does it take to build this application - including Database design, web frontend etc.? Days? Hours? Minutes?

With Django - in this very simple example - we are talking about minutes. All you have to do is to define your model - and the rest comes for free ...

_images/day-2-orm.png

Figure 2.1: Full feature of Django model

So let’s get back to our Event Website. In our case we store, retrieve and handle information about events. So please checkout the sources for this chapter ...

git checkout -f day-2-step-1

Changes:

  • In events/model.py, the following code is added

    class Event(models.Model):
        title = models.CharField(max_length=200)
        description = models.TextField(default='')
        venue = models.CharField(max_length=100)
        seats = models.IntegerField()
        amount = models.DecimalField(
            max_digits=11,
            decimal_places=2
        )
        date = models.DateTimeField()
    

    This is our event model. From this definition Django knows how to create our database and our Admin GUI. It will create a table “event” with attributes like “title”, “description” etc. In the Admin GUI it will create insert, update and delete functions for this table. It will also know that “seats” can only be a number - and not a string when a user will enter data for it.

1.1 Database Migration

Whenever you make changes to your models.py (of any app), it is required to do a database “migration”. Migration is a process that propagates changes from your model into your database. Technically Django will create all necessary SQL queries to update your database scheme and run them against your database.

To perform a migration, follow these steps:

  1. Make sure you’re in the same directory as manage.py (See Project structure - DAY-1, 4).

  2. Type and following commands in your bash window

    1
    2
    python manage.py makemigrations
    python manage.py migrate
    

What is happening?

  • Line 1 will create a migrations file. Go to your explorer and open events/migrations/0001_initial.py file. You will see migration code like:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.db import models, migrations
    from django.conf import settings
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ]
    
        operations = [
            migrations.CreateModel(
                name='Event',
                fields=[
                    ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
                    ('title', models.CharField(max_length=200)),
                    ('description', models.TextField(default='')),
                    ('venue', models.CharField(max_length=100)),
                    ('seats', models.IntegerField()),
                    ('amount', models.DecimalField(max_digits=11, decimal_places=2)),
                    ('date', models.DateTimeField()),
                ]
            ),
        ]
    

    This might look pretty complex to you ... for now - do not bother understanding this.

  • Line 2 will synchronize the changes into your database. It will create a table events_event

2. Admin Site

The Admin site is a very powerful tool that is generated from your model. Let us set it up, so you can enter and edit your events.

2.1. Create Admin User (optional)

If you have already created a superuser when you ran the project for the first time, you skip this step.

  1. Make sure you’re in the same directory as manage.py

  2. Type following command:
    python manage.py createsuperuser
    
  3. Provide username, email, password, first_name and last_name.

Important

Remember username and password will be used to login in Admin Site

2.2. Register Event Module in Admin Site

In Order to enable editing your events you have to register your module for the admin site

git checkout -f day-2-step-2

Changes:

  • In events/admin.py, following lines are added:
from .models import Event
admin.site.register(Event)

Like this you can manually register a module for your Admin Site. Django also has contributed module (contrib.admin) which will dynamically generate a complete Admin Site for any given model.

Important

Remember the difference between module and model. A module is a Django App, where as model is the representation of your data.

2.3 Login to youre Admin Site

  1. To access your Admin Site, you have to add admin at the end of your project URL. For example http://myevent-slash4-2.c9.io/admin is our admin URL. Your project will have its own URL, See 2.4.

  2. You have to login to access your Admin Site. Please enter the username and password of the superuser you have created.

  3. If you are successfully logged in, you will see a dashboard like:

    _images/django-admin-site-dashbaord.png

    Figure 2.2: Django Admin Site Dashbaord

  4. Click on Events and add some events:

_images/django-admin-event.png

Figure 2.3: Django Admin Site, Event Page

2.4 String representation of Event Object

After you have created a couple of events and display a list of them - you can see that each one is represented as ‘Event Object’ in the event column. That doesn’t make sense. Let us fix it.

git checkout -f day-2-step-3

Changes:

In events/models.py, following function is added

def __str__(self):
    return "%s" % self.title

Reload your Event list. Now, you can see the name of the event instead of “Event Object”. Why?

The __str__() function is a special function in python that defines the “string” representation of an object. Like this we can define how our ojbects “look like”. In this case we have returned the title (return '%s' % self.title) of the object. Of course you could also choose to return any other field - or even concat more than one field.

_images/django-admin-event-2.png

Figure 2.4: Django Admin Site, Event Page with title

2.5 Improve your Lists

Ok - now we are having a list of all events. But it only displays the name of the event. Next we try to add the other columns to have a better view on our data.

git checkout -f day-2-step-4

Changes:

  1. In events/admin.py,

    following line is removed:

    admin.site.register(Event)
    

    following lines are added:

    1
    2
    3
    4
    5
    class EventAdmin(admin.ModelAdmin):
        list_display = ('title', 'venue', 'date')
    
    
    admin.site.register(Event, EventAdmin)
    
    • Line 1: We have defined a custom admin class which is inherited from admin.ModelAdmin
    • Line 2: We have defined fields that are shown in Admin List Page. Here, you can include any field that exists in your model.
    • Line 3: We have registered the Admin Site for your Event model with a custom admin class i.e. EventAdmin

Reload your event list browser window and see the results.

_images/django-admin-site-event-column.png

Figure 2.5: Event List with more columns

2.6 Making Changes to the Model

Ok - let’s take a short break. In agile development teams it is completely normal that your database scheme is going to be changed a couple of times before have your final model. But changing the heart of your application can cause a lot of effort - many places where code has to be changed. In Django though, changing the model is pretty easy in most of the cases. This really supports agile development methods. Just update your model and hit migrate.

So ... how long does an event last? Ah, we forget that. But no worry, we always can add additional information. For this we need to make changes in our Event model. Let us add the duration field.

git checkout -f day-2-step-5

Changes:

Open events/model.py, and see that the following line is added

duration = models.CharField(
    max_length=20,
    help_text='e.g. 3 hours, 5 days'
)

Let’s migrate:

Make sure you’re in the same directory as manage.py and type following command:

python manage.py makemigrations events

It will prompt you with:

You are trying to add a non-nullable field 'duration' to event without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py
 Select an option:

Type 1 and press enter key. It will again prompt:

Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now()
>>>

Type 0 and press enter key.

It will add 0 value for duration for all the events that already exist in the database (events_event table).

Finally, migrate the changes:

python manage.py migrate

This will add a duration field to the events_event table in the database. ► Run project and add new event in your Admin Site. You will see that a duration field was added.

Why did we not migrate when we added __str__ function (2.4)?

Migration is applicable only when we make changes on properties (fields). In step 2.4, we have added a function - wich does not change anything to the data structure (only to it’s representation), and here we added a property (field), duration. So the database needs to change that we can store this additional property.

2.7 Adding Search Functionality

To have a more comfortable Admin frontend we want to add search functionalities to the lists.

git checkout -f day-2-step-6

Following line is added in events/admin.py:

search_fields = ('title', )

Reload your Admin Site Event list and you will see a search field

_images/django-admin-event-search.png

Figure 2.6: Event List with search field

3 Django Model APIs

Let’s play with the model. Django has an interactive Python shell mode which lets you play with the model quickly.

Type following command to enter into the interactive Python Shell

python manage.py shell

Note

Make sure you are in same directory as manage.py

  1. Import your Event model:

    from events.models import Event
    
  2. Create an event

    Event.objects.create(
      title="Tech Open Air 2015",
      description="Tech Open Air is a three-day Interdisciplinary Technology Festival held in Berlin 15 -16 -17 July, 2015. Europe's coolest tech conference.",
      venue="Alte Teppichfabrik Berlin",
      seats="300",
      amount="100.50",
      date="2015-07-18 10:00:00",
    )
    

    In the background the API generates the following SQL and runs it against your database:

    INSERT INTO events_event
          (title,
           description,
           venue,
           seats,
           amount,
           date)
    VALUES
        ("tech open air 2015",
        "tech open air is a three-day interdisciplinary technology festival held in berlin 15 -16 -17 july, 2015. europe's coolest tech conference.",
        "alte teppichfabrik berlin",
        "300",
        "100.50",
        "2015-07-18 10:00:00")
    
  3. Repeat #2 to create more (at least 5) events, of course with different names, dates, venues ....

  4. Query all events

Event.objects.all()
  1. Query all events, limit 2
Event.objects.all()[:2]
  1. Get an event based on it’s ID
Event.objects.get(id=1)
  1. Print details of a specific Event, edit and save it
my_event = Event.objects.get(id=1)
print my_event.title
print my_event.date

my_event.title = "This is my new title"
my_event.save()

Note

You can also use “TAB-Completition” in your interactive shell. Try this ... type:

print my_event.

And then hit the TAB key twice. It will show you a list of all attributes and methods that your object is offering. Feel free to play a little bit with your object.

  1. Query event sorting on date field in ASC order
Event.objects.all().order_by('date')
  1. Query event sorting on date field in DESC order
Event.objects.all().order_by('-date')

Exit the Python Enteractive Shell by typing exit() and press enter.

4. Assignments

  1. Please add a couple of events from your Admin Site. We’ll need it later.
  2. Play with the Admin Site. Use the search. Try to reorder the lists.
  3. Try to enter invalid data (e.g. try to put a string into a number field).
  4. Delete events.
  5. Checkout the history function of events.

In Django you can also use fixture files to prepoulate your databases with test-data (instead of entering them manually). We have created a fixture file with six events for you.

  1. Checkout the solution by typing following command:
git checkout -f day-3-solution-1

Open the file events/fixtures/event.json.

  1. To Import fixtures type the following command:
python manage.py loaddata events.json