Building the course models

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.

Registering the models in the administration site

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.

Providing initial data for models

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:

Providing initial data for models

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.

Note

Fixtures are not only useful for initial data but also to provide sample data for your application or data required for your tests.

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset