Our e-Learning platform will offer courses in various subjects. Each course will be divided into a configurable number of modules, and each module will contain a configurable number of contents. There will be contents of various types: text, file, image, or video. The following example shows what the data structure of our course catalog will look like:
Subject 1 Course 1 Module 1 Content 1 (image) Content 3 (text) Module 2 Content 4 (text) Content 5 (file) Content 6 (video) ...
Let's build the course models. Edit the models.py
file of the courses
application and add the following code to it:
from django.db import models from django.contrib.auth.models import User class Subject(models.Model): title = models.CharField(max_length=200) slug = models.SlugField(max_length=200, unique=True) class Meta: ordering = ('title',) def __str__(self): return self.title class Course(models.Model): owner = models.ForeignKey(User, related_name='courses_created') subject = models.ForeignKey(Subject, related_name='courses') title = models.CharField(max_length=200) slug = models.SlugField(max_length=200, unique=True) overview = models.TextField() created = models.DateTimeField(auto_now_add=True) class Meta: ordering = ('-created',) def __str__(self): return self.title class Module(models.Model): course = models.ForeignKey(Course, related_name='modules') title = models.CharField(max_length=200) description = models.TextField(blank=True) def __str__(self): return self.title
These are the initial Subject
, Course
, and Module
models. The Course
model fields are as follows:
owner
: The instructor that created this course.subject
: The subject that this course belongs to. A ForeignKey
field that points to the Subject
model.title
: The title of the course.slug
: The slug of the course. This will be used in URLs later.overview
: This is a TextField
column to include an overview about the course.created
: The date and time when the course was created. It will be automatically set by Django when creating new objects because of auto_now_add=True
.Each course is divided into several modules. Therefore, the Module
model contains a ForeignKey
field that points to the Course
model.
Open the shell and run the following command to create the initial migration for this app:
python manage.py makemigrations
You will see the following output:
Migrations for 'courses': 0001_initial.py: - Create model Course - Create model Module - Create model Subject - Add field subject to course
Then, run the following command to apply all migrations to the database:
python manage.py migrate
You should see an output including all applied migrations, including those of Django. The output will contain the following line:
Applying courses.0001_initial... OK
This tells us that the models of our courses
app have been synced to the database.
We are going to add the course models to the administration site. Edit the admin.py
file inside the courses
application directory and add the following code to it:
from django.contrib import admin from .models import Subject, Course, Module @admin.register(Subject) class SubjectAdmin(admin.ModelAdmin): list_display = ['title', 'slug'] prepopulated_fields = {'slug': ('title',)} class ModuleInline(admin.StackedInline): model = Module @admin.register(Course) class CourseAdmin(admin.ModelAdmin): list_display = ['title', 'subject', 'created'] list_filter = ['created', 'subject'] search_fields = ['title', 'overview'] prepopulated_fields = {'slug': ('title',)} inlines = [ModuleInline]
The models for the course application are now registered in the administration site. We use the @admin.register()
decorator instead of the admin.site.register()
function. Both provide the same functionality.
Sometimes you might want to pre-populate your database with hard-coded data. This is useful to automatically include initial data in the project setup instead of having to add it manually. Django comes with a simple way to load and dump data from the database into files that are called fixtures.
Django supports fixtures in JSON, XML, or YAML formats. We are going to create a fixture to include some initial Subject
objects for our project.
First, create a superuser using the following command:
python manage.py createsuperuser
Then, run the development server using the following command:
python manage.py runserver
Now, open http://127.0.0.1:8000/admin/courses/subject/
in your browser. Create several subjects using the administration site. The list display page should look as follows:
Run the following command from the shell:
python manage.py dumpdata courses --indent=2
You will see an output similar to the following:
[ { "fields": { "title": "Programming", "slug": "programming" }, "model": "courses.subject", "pk": 1 }, { "fields": { "title": "Mathematics", "slug": "mathematics" }, "model": "courses.subject", "pk": 2 }, { "fields": { "title": "Physics", "slug": "physics" }, "model": "courses.subject", "pk": 3 }, { "fields": { "title": "Music", "slug": "music" }, "model": "courses.subject", "pk": 4 } ]
The dumpdata
command dumps data from the database into the standard output, serialized in JSON by default. The resulting data structure includes information about the model and its fields for Django to be able to load it into the database.
You can provide names of applications to the command or specify models for outputting data using the app.Model
format. You can also specify the format using the --format
flag. By default, dumpdata
outputs the serialized data to the standard output. However, you can indicate an output file using the --output
flag. The --indent
flag allows you to specify indentation. For more information on dumpdata
parameters, run python manage.py dumpdata --help
.
Save this dump to a fixtures file into a fixtures/
directory in the orders
application using the following commands:
mkdir courses/fixtures python manage.py dumpdata courses --indent=2 --output=courses/fixtures/subjects.json
Use the administration site to remove the subjects you created. Then load the fixture into the database using the following command:
python manage.py loaddata subjects.json
All Subject
objects included in the fixture are loaded into the database.
By default, Django looks for files in the fixtures/
directory of each application, but you can specify the complete path to the fixture file for the loaddata
command. You can also use the FIXTURE_DIRS
setting to tell Django additional directories to look for fixtures.
You can read about how to use fixtures for testing at https://docs.djangoproject.com/en/1.8/topics/testing/tools/#topics-testing-fixtures.
If you want to load fixtures in model migrations, take a look at Django's documentation about data migrations. Remember that we created a custom migration in Chapter 9, Extending Your Shop to migrate existing data after modifying models for translations. You can find the documentation for migrating data at https://docs.djangoproject.com/en/1.8/topics/migrations/#data-migrations.