DEV Community

Horace FAYOMI
Horace FAYOMI

Posted on • Updated on

Learn Django: Build a netflix clone

Django and Netflix

Hello, welcome to the first part of this tutorial-course in which you'll learn and understand the basics of Django by building a clone of the popular website Netflix.

This tutorial assumes that you have at least basics knowledge of:

  • Python3 programming language
  • Linux
  • Html and CSS
  • Mysql.

Presentation of Django

Django is one of the most popular Frameworks to build full-stack websites and also APIs. It follows the MVT (Model, views, and template) architecture.

  • What are Models: The models are python object representations of our database. For example, the class User represents the user's table in our database and an instance of that User class is a record in the table users. Then, each attribute of the user class is a column of the table users* and the value of each attribute for a specific instance of User class, is the value of the column related to that attribute. Don't worry if it sounds weird now, you'll understand better in deep before the end of this tutorial when we will play with models.

  • What are Templates: To make it simple, templates are what end-users see (the interface made by HTML and CSS, button, images, text, animations, etc...).

  • What are Views: Views are the listeners to users' actions on the templates. User action might trigger a request to a View. The view will perform an operation related to handling user requests, if required it will interact with the database (throughout models) and return a response to the user if needed. The response could be another template or html page, or a Json response or even another type of response.

  • In addition, an important thing to know for the beginning, is that a Django project is divided into small reusable pieces (python modules) called apps.

Django installation

To install Django on your system, I advise you to:

  1. work on a virtual environnemt or a conda workspace. But first, make sure python is installed on your computer.

  2. Create a requirements.txt file that will contain the list of python libraries and their versions required by our project to work well on any computer. For now, we just need Django so our requirements.txt will just contain one line like this:

Django==4.0.2
Enter fullscreen mode Exit fullscreen mode

At the time of this article, the latest stable version of Django is 4.0.2.

  1. Then run pip install -r requirements.txt or python -m pip install requirements.txt (or it could also be python3 instead of just python or pip3 instead of pip). That will install all the packages listed in the file with the specified versions.

Create the Django project

Let's use django_netflix_clone for the project name. (I used underscore because it improves the readability.

  • Then run: django-admin startproject django_netflix_clone.

Note: django-admin is the Django command-line utility. It’s used for common operations in the Django development phase as we will see in the following.

A new folder named django_netflix_clone will be created.
I advise you to move the requirements.txt file into django_netflix_clone folder, so it will be inside the project.

  • Run: mv requirements.txt django_netflix_clone.

The django_netflix_clone project architecture should looks like this now:

django_netflix_clone project strcucture

You'll notice that Django has created some files and a default folder with the same name as the project django_netflix_clone.
At the root of the project we should have the following:

  • manage.py file: it is a Python file helper used to execute commands related to the project. We will see its uses as we go.

  • django_netflix_clone folder. We said that a Django project is made of apps. That folder is the default app automatically created by Django. It contains some auto-generated files as well. Let's explain a bit them:

  • wsgi.py (Web Server Gateway Interface): When you want to deploy your Django to production in a real server, this file is used as the entrypoint, to allow the application server to connect to your Django project.

  • asgi.py (Asynchronous Server Gateway Interface): To make it simple, it plays the same role as wsgi.py, but is for asynchronous web servers and applications. So it's used in the place of wsgi.py when your project supports asynchronous tasks.

  • settings.py: It's the project configuration file. All the apps and projects settings are defined on it.
    The important settings here are:

    • SECRET_KEY: it's is used to provide a cryptographic signing to the project. It is mostly used to sign session cookies (we will talk about sessions and cookies later in this course). If one were to have this key, they would be able to modify the cookies sent by the application.
    • INSTALLED_APPS: it's an array that contains the list of apps in the project. There are default apps added by Django like django.contrib.admin to manage administration (we will cover it later in this tutorial), django.contrib.auth to manage authentication, etc... (The apps names a self-explanatory)
    • MIDDLEWARE: Middlewares are functions that are executed before each request. Defaults middlewares are added by django like django.middleware.security.SecurityMiddleware to verify the security of request.

We will explain others settings as we go.

  • urls.py: This file describes all the paths that could be accessed in the project. By default it contains one path (admin):
urlpatterns = [
    path('admin/', admin.site.urls),
]
Enter fullscreen mode Exit fullscreen mode

At this step, we can say that the allowed URLs on our app are http://my_project_url and http://my_project_url/admin/

Then enter the project:

  • cd django_netflix_clone
  • Open the project in a code editor (Me I use VSCode or visual studio code) code .

Image description

Create our working app

The default app is meant to be a centralizes app. Let's create another app named netflix to handle our Netflix features.

  • On VS code open a new terminal by clicking Terminal -> New terminal from the top horizontal bar menu. It should open a terminal at the root project directory.
  • Then type this command: django-admin startapp netflix. A new folder named netflix will be created:

Image description

  • open the settings.py file and add netflix app into INSTALLED_APPS setting as described above: Image description This will register our netflix app to the project. Without that, the app is created but not linked to the project.

We won't explain all the files and folders that are newly created under netflix app folder now. Let's just explain views.py and models.py:

  • views.py: it is the file that will contain our views described at the top. Each view is a class, and we will cover them in deep later in the course.
  • models.py: It's the file that contains our models. As described above, in Django our database is represented by Django classes.

Design our database

We have created our project and added our main app. Now let's design our database according to our features. Remember, each model is a python class and inherits from the internal Django class django.db.models.Model.

  • Open the models.py file that is inside netflix directory.

  • We have users that will register and watch movies. By default, Django have what we call contribs which are pre-made modules to ease our work. From those contribs we have a default User model. You can customize the default Django User model as described here. But, in this tutorial, we will just use the default one.

Movie models

  • We will have movies to watch. Let's create a model class to represent a movie.
class Movie(models.Model):
    """Movie model class."""

Enter fullscreen mode Exit fullscreen mode

That means, we will have a table named Movie in our database.

Each movie will have a name, let's add it:

CHARS_MAX_LENGTH: int = 150

class Movie(models.Model):
    """Movie model class."""

    name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True)
Enter fullscreen mode Exit fullscreen mode

The name column should be a string that why we used the Django model field named CharField. We've decided to limit the name length to 150 chars.
With the line CHARS_MAX_LENGTH: int = 150 we define a constant to avoid using magic numbers in our code that we will use.
With line name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True). we ask Django to add a column named name into our movies table and each record of movie should not have a name with more than 150 chars. blank=True means that, when we want to create or modify a record of the movie, we don't need to provide the name value. You'll understand more in the following.

  • Each movie could have a description, let's add it with this line:

description = models.TextField(blank=True, null=True)

For it we use TextField instead of CharField as the description length is not predictable, but we know movies names are not that long.
Note null=True means that we can create a Movie without specifying a value for the description. If null=True was not specified like for name, trying to create a movie without providing description will raise an exception.
We might need to keep the creation date of the movie, let do it:
date_created = models.DateTimeField(auto_now_add=True).

Not that we used DateTimeField because it's a date and we set attribute auto_now_add to True so the creation date will automatically be set by Django during object creation.

Our models.py should looks like this now:

from django.utils import timezone
from django.db import models


class Movie(models.Model):
    """Movie model class."""

    name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True)
    description = models.TextField(blank=True, null=True)
    date_created = models.DateTimeField(default=timezone.now)
Enter fullscreen mode Exit fullscreen mode
  • Each movie should have only one category. It's better to store categories in the database as well so we can manage them. Let's create a Category model before the Movie model with name and description (the category creation date is not really useful):
class Category(models.Model):
    """Category model class."""

    name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True)
    description = models.TextField(blank=True, null=True)
Enter fullscreen mode Exit fullscreen mode
  • We will suppose for this tutorial that a movie must belong to one and only one category. That defines what we call a OneToMany relationship. In Django it's represented by django.db.models.ForeignKey. Let's add it: category = models.ForeignKey( Category, models.CASCADE )

The attribute models.CASCADE mean that if the category is deleted, all its movies should be deleted to avoid data invalid values (For example having some movie with non-existant category).

Your code should looks like this now:

class Movie(models.Model):
    """Movie model class."""

    name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True)
    description = models.TextField(blank=True, null=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)  # <----------- Add this line
    date_created = models.DateTimeField(auto_now_add=True)
Enter fullscreen mode Exit fullscreen mode
  • Each movie will have one or more tags. It's better to store tags as well in the database. Let's create a Tag model before the Movie model with name and description (the category creation date is not really useful):
class Tag(models.Model):
    """Tag model class."""

    name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True)
    description = models.TextField(blank=True, null=True)
Enter fullscreen mode Exit fullscreen mode
  • We will suppose for this tutorial that a movie could have many tags and a tag could be associated to many categories. So that defines what we call a ManyToMany relationship. In django it's represented by django.db.models.ManyToManyField. Let's add it: tags = models.ManyToManyField(Tag). Your code should then looks like this:
class Movie(models.Model):
    """Movie model class."""

    name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True)
    description = models.TextField(blank=True, null=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag)  #  <--- Add this line
    date_created = models.DateTimeField(auto_now_add=True)
Enter fullscreen mode Exit fullscreen mode

Note: The attribute models.CASCADE mean that if a tag is deleted, all it's related movies will also be deleted to avoid data invalid values (For example having some movies with non-existant tag).

  • We might need some statistics about each movie like the number of people who watched it. Let's add it:
    watch_count = models.IntegerField(default=0).
    Here, as it is a number, we used IntegerField and default = 0 means that the default value is 0. And plus, as we defined a default value, even if we don't provide that attribute, django won't raise an exception, but set the attribute to 0.

  • Naturally, we need to store the movie video file. For that
    Nice there we go. We have all the minimal information for our database.

Managing static files

Before that, we will explain how Django manages files. By django serve all files related to the website (html, css, js, images) to the value of STATIC_URL parameter in settings.py file. And the default value is /static/.
We also need to define the static root folder which is also static/:

STATIC_URL = 'static/'
STATIC_ROOT = 'static/'  # Add this line
Enter fullscreen mode Exit fullscreen mode

You can change it with another value, but I recommend you to keep it only if you have a good reason to change it.

During development, Django recommends storing those files are stored in a folder called static inside each app.

Managing media files

Now the files that are uploaded into the projects (like our movies videos) are served to the value of MEDIA_URL parameter in settings.py. That setting is not there by default, but it recommended value is /media/ so we have to add it (we could add it right after STATIC_URL):

MEDIA_URL = 'media/'
Enter fullscreen mode Exit fullscreen mode

By default, media files are not stored in the database but in a folder defined by the settings MEDIA_ROOT. That setting also was not there so we have to define it.

import os # Add this at the top of the settings.py file
...
...
STATIC_URL = 'static/'
MEDIA_URL = 'media/' 
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') # Add this line too
Enter fullscreen mode Exit fullscreen mode


.
That means, our movies will be uploaded into a folder named media at the root of the directory. We used os.path.join and BASE_DIR (defined at the top of the file) to get the full path of the folder in the system. That folder didn't exists, so let's create it:
Make sure to be at the root of the project and run:
mkdir media.

  • The last part to finalize the setup of static and media files is to add their values to the path. Open urls.py file like this:
from django.contrib import admin
from django.urls import path
from django.conf import settings            # Add this line
from django.conf.urls.static import static  # Add this line

urlpatterns = [
    path('admin/', admin.site.urls),
]

# Add the lines below
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Enter fullscreen mode Exit fullscreen mode

We have finished to set up static and media files for our project.

We can then use django.db.models.FileField to store the link to our movie (media) like this:

file = models.FileField(upload_to='movies/')
Enter fullscreen mode Exit fullscreen mode


.

  • A last thing, we need a preview picture for our movie. As it's a picture, Let use django.db.models.ImageField like this:
preview_image = models.ImageField(upload_to='preview_images/')
Enter fullscreen mode Exit fullscreen mode


.

Our final Movie class file looks like this:

class Movie(models.Model):
    """Movie model class."""

    name = models.CharField(max_length=CHARS_MAX_LENGTH, blank=True)
    description = models.TextField(blank=True, null=True)
    categories = models.ForeignKey(Category, on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag)
    watch_count = models.IntegerField(default=0)
    file = models.FileField(upload_to='movies/')
    preview_image = models.ImageField(upload_to='preview_images/')
    date_created = models.DateTimeField(default=timezone.now)

Enter fullscreen mode Exit fullscreen mode

There we go

Django Migrations

We have finished to set up our basic database. Now we need to create what we call migrations. Migrations are Python files containing the definition and history of changes in your models. To create migration we should run the command:
python manage.py makemigrations. Note that we have used the project command tool manage.py.

After running the command, we should get this error:

Image description
It's because it's a module required by ImageField to work that is not yet installed in our environment. So we can add it to our requirements.txt file like this:

django==4.0.2
Pillow==9.0.1 # Add this line into requirements.txt
Enter fullscreen mode Exit fullscreen mode


.
Then run pip install -r requirements.txt again (it will only install missing modules, in our case pillow).

Then run again: python manage.py makemigrations.
You should have this result:
Image description.

That will generate some files (migrations) into migrations folder under netflix module. Those files contain descriptions of our models that will be used to physically create and/update our database.

Migrate database

To physically create our database, we need to specify the database type in the settings. If you open the settings.py file, you'll see:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
Enter fullscreen mode Exit fullscreen mode

'ENGINE': 'django.db.backends.sqlite3' means our database is SQLite and 'NAME': BASE_DIR / 'db.sqlite3', is named db.sqlite3 and should be at the root of the project. Django support multiple others backend like MysQL that we will see in Part5 of this course. For the time being we will stick to the defaults settings.

Now that we see that our database was already set up but understood which setting handle it, let's populate our db.sqlite3 database with our models throughout migrations. Run python manage.py migrate. You'll see a message like this:

Image description

The model Manager

Each Django model has something called Manager and comes with a default one named objects. It allows us to perform queries to the database from our model. For example, basic queries we can do on the Movie model are:

  • Create a movie: it's achieved with Movie.objects.create(name="Avatar")
  • Get all movies: it's achieved with Movie.objects.all().
  • *Filter all movies whose name starts with uppercase A *: it's achieved with Movie.objects.filter(name__startswith="A").
  • Filter all movies whose name starts with a no matter the case (A or a): it's achieved with Movie.objects.filter(name__istartswith="a"). If it is still a bit fuzzy for you, it's okay, it will become clear after you learn how to play with the manager in the right next section.

Django Shell: play with our data

To quickly test our models and the manager, Django provides a very useful tool called Django Shell.

  • Open a terminal on VSCode (by default it will be opened ad the root of the project).
  • Run: python manage.py shell. A new command prompt will be shown.
    Image description

  • Import our models: type

from netflix.models import Category, Movie, Tag
Enter fullscreen mode Exit fullscreen mode

and press enter.

  • Let's try to create a movie named Dracula3: run
Movie.objects.create(name="Dracula")
Enter fullscreen mode Exit fullscreen mode

You should have an error similar to this:

sqlite3.IntegrityError: NOT NULL constraint failed: netflix_movie.category_id
Enter fullscreen mode Exit fullscreen mode

And it is normal, because, we cannot create a Movie without a Category. Remember that a movie should belong to only one category because of the relationship category = models.ForeignKey(Category, ....

So we need first to create a category. Let's create a category named tech. Run the following command:

tech_category = Category.objects.create(name="Tech")
Enter fullscreen mode Exit fullscreen mode

The new created category is then assigned to the shell
variable tech_category.
We can verify it informations.

  • In the terminal type just tech_category and press enter and it should display this:
>>> tech_category
<Category: Category object (1)>
Enter fullscreen mode Exit fullscreen mode

Note that Category object (1) is the default name used by python to render an object instance. We can customize the name by overriding the method __str__ of our models class.
For the Category model we can return the category's name instead like this:

class Category(models.Model):
    ...
    # Add the function below
    def __str__(self):
        return self.name
Enter fullscreen mode Exit fullscreen mode

We can return also do the name for Category and Tag models.

class Movie(models.Model):
    ...
    # Add this function
    def __str__(self):
        return self.name
Enter fullscreen mode Exit fullscreen mode
class Tag(models.Model):
    ...
    # Add this function
    def __str__(self):
        return self.name
Enter fullscreen mode Exit fullscreen mode
  • Now, close django shell by executing exit() command and reopen it with python manage.py shell.

  • Let's import our models again

>>> from netflix.models import Category, Tag, Movie
>>> 
Enter fullscreen mode Exit fullscreen mode
  • Let retrieve our category. To do so we have several ways:
    • you can run
tech_category = Category.objects.get(name="Tech")
Enter fullscreen mode Exit fullscreen mode

Here we made a direct access. The particularity here is that if there is was category with name Tech, it will throws an excpetion. To verify run

Category.objects.get(name="NonExistentName")
Enter fullscreen mode Exit fullscreen mode

You'll get this:

>>> Category.objects.get(name="NonExistentName")
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/horacefayomi/.local/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/horacefayomi/.local/lib/python3.10/site-packages/django/db/models/query.py", line 650, in get
    raise self.model.DoesNotExist(
netflix.models.Category.DoesNotExist: Category matching query does not exist.
Enter fullscreen mode Exit fullscreen mode
- you can also access the object by it primary key, which is even better than using any other keys
Enter fullscreen mode Exit fullscreen mode
tech_category = Category.objects.get(pk=1)
Enter fullscreen mode Exit fullscreen mode
- you can access the category using `filter` method that we saw in previous point:
Enter fullscreen mode Exit fullscreen mode
tech_category = Category.objects.filter(name="Tech").first()
Enter fullscreen mode Exit fullscreen mode

Note that Category.objects.filter(name="Tech") return an array of the the matching categories.
You can verify by running:

>>> Category.objects.filter(name="Tech")
<QuerySet [<Category: Tech>]>
Enter fullscreen mode Exit fullscreen mode

Then chaining with .first() return the first element of the list.

Now you would have notice that now the category is display like

<Category: Tech>
Enter fullscreen mode Exit fullscreen mode


instead of

<Category: Category object (1)>
Enter fullscreen mode Exit fullscreen mode

That means our __str__ methods works well ^_^.

We then created our first category instance.

  • In the terminal, if you type tech_category.pk and press enter you will see:
>>> tech_category.pk
1
Enter fullscreen mode Exit fullscreen mode

That means the value of the primary key of our moel is 1.
It's because, as we have seen before, in Django the default database is sqlite, and in sqlite like most of others relational databases, the primary key is by default an integer auto-generated, starting from 1.

  • We can also check the category name in the terminal by typing tech_category.name. Here should be the output:
>>> tech_category.name
'Tech'
Enter fullscreen mode Exit fullscreen mode
  • Now we should be able to finally create our first movie:
movie = Movie.objects.create(name="Dracula", category=tech_category)
Enter fullscreen mode Exit fullscreen mode

Now we can verify the attributes of our movie

>>> movie = Movie.objects.create(name="Dracula", category=tech_category)
>>> movie.pk
1
>>> movie.name
'Dracula'
>>> movie.category
<Category: Tech>
>>> movie.date_created
datetime.datetime(2022, 11, 7, 16, 54, 11, 259483, tzinfo=datetime.timezone.utc)
Enter fullscreen mode Exit fullscreen mode

Awesome, our first movie is also well created.

  • We can list all the current movies of our database to see:
>>> Movie.objects.all()
<QuerySet [<Movie: Dracula>]>
Enter fullscreen mode Exit fullscreen mode
  • We can also create a movie in another way. Execute
new_movie = Movie(name="Harry potter3")
Enter fullscreen mode Exit fullscreen mode
  • set the movie category
new_movie.category = tech_category
Enter fullscreen mode Exit fullscreen mode

At this step the movie object is created, but the movie is not yet save into the database. To save it we should call the save() method of the model instance

new_movie.save()
Enter fullscreen mode Exit fullscreen mode

And there we go. You can lost again all the movies to see that the new movie is among the list:

>>> Movie.objects.all()
<QuerySet [<Movie: Dracula>, <Movie: Harry potter3>]>
Enter fullscreen mode Exit fullscreen mode

Nice.

  • You can check that the watch_count of the new_movie movie is 0.
>>> new_movie.watch_count
0
Enter fullscreen mode Exit fullscreen mode
  • We can update the count to any number.
>>> new_movie.watch_count = 10
>>> new_movie.save()
>>>
Enter fullscreen mode Exit fullscreen mode

Now running new_movie.watch_count should display 10

>>> new_movie.watch_count
10
Enter fullscreen mode Exit fullscreen mode
  • To see the number of movies in the database you can run Movie.objects.count() and it should print 2:
>>> Movie.objects.count()
2
Enter fullscreen mode Exit fullscreen mode
  • You can also remove a movie by calling it delete(). Let's remove new_movie:
>>> new_movie.delete()
(1, {'netflix.Movie': 1})
Enter fullscreen mode Exit fullscreen mode
  • We can check that the count is now 1
>>> Movie.objects.count()
1
Enter fullscreen mode Exit fullscreen mode

I hope you enjoyed palying with the models in Django shell.
We just learn the basics operations that you'll use to perform on your models. We will see more in the coming parts of this course.

Django ORM

Django models are class abstractions that represents our database, Even if we perform operations using either the default model manager (Movie.objects.create()) or on the model instance new_movie.save(), all those operations are translated in background into SQL queries by Django ORM (Object-Relational Mapper). Django's ORM is just a pythonical way to create SQL to queries, manipulate our database and get results in a pythonic fashion. Awesome right !!!

Register Admin

Now that you know how to manipulate your data on the shell, let's see how to manipulate it through a graphical interface.
Django allows us to easily administrate our database with a powerful tool called Django Admin. Basically, it provided an administration interfaces where we can easily list, create, modify, view, and delete items of our database. And to set up the admin features is easy like eating a cake.
Reminder, it's the contrib 'django.contrib.admin' that allows provide us that powerful feature.

Open the admin.py file under netflix folder. And add those lines:

from netflix.models import Movie
from netflix.models import Category
from netflix.models import Tag

admin.site.register(Movie)
admin.site.register(Category)
admin.site.register(Tag)
Enter fullscreen mode Exit fullscreen mode

That's all.

Note: The admin interface is customizable but we won't cover this in this tutorial.

Create a superuser

To manage our admin site we need to create a super user. It's a user with enough privilege to access the administration interface. By default, a created user is not a superuser. We will dive deep into Django authentication and roles in the next parts of this tutorial course.
To create a superuer run in a porject temrinal in VScode:

  • python manage.py createsuperuser. It will ask to enter some values. Let use admin for username, admin@admin.com for the email, and type admin, for the password. It will print some warnings:
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create a user anyway? [y/N]:
Enter fullscreen mode Exit fullscreen mode

Press Y and continue, we will come back later on that in the next parts of the tutorial.

There we Go.

Start development server and add some data

Django comes with an internal light development server. To start it, open a new terminal in the project inside VScode as usual and run:
python manage.py runserver. You'll see this message:

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
February 27, 2022 - 02:28:29
Django version 4.0.2, using settings 'django_netflix_clone.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Enter fullscreen mode Exit fullscreen mode

That means, the server has started and is available at host http://127.0.0.1:8000/. You can specify your own port with python manage.py runserver 0.0.0.0:<your_port>.

Login to the Admin interface and play with data

  • Open your favorite browser (me I use chrome).
  • Type the development URL, you should see this page

Image description

  • Open the admin page: got to http://127.0.0.1:8000/admin/ on the browser. It looks like this:

Image description
-It's the login page. Enter the credentials for the super user (username = "admin", password = "admin") and validate the form.

  • You'll be redirected to the admin dashboard presented below:

Image description

We will come back later on User and Group. Let's play with our Media, Category, and Tag. Click on Category and add some categories. The interface is intuitive. You have the Add button at the top right corner.

  • Add Tags with the name Trending, Popular. Set the description you want.

Image description

  • Add categories named Action , Adventure, Romance, Thriller.

Image description

  • Add Spider-Man: No Way Home movie:
    • Add Spider-Man: No Way Home for the name and description
    • Select the category
    • Select tags (To select multiple tags as a movie could have more that one tag, keep this pressed down and select the tags with right mouse clicks)
    • Download the image from the internet to your computer and add it to the preview-image field.

Currently, the movie page looks like this:
Image description
We can a bit customize Django admin to allow super users to see the preview_image and description of a movie.

  • Open admin.py file
  • Remove line admin.site.register(Movie) And add these code:
from django.utils.html import format_html # Add this line
...
...
# add the lines below
class MovieAdmin(admin.ModelAdmin):

    def preview(self, movie):
        """Render preview image as html image."""

        return format_html(
            f'<img style="height: 200px" src="/media/{movie.preview_image}" />'
        )

    def video(self, movie):
        """Render movie video as html image."""

        return format_html(
            f"""
            <video width="320" height="240" controls>
                <source src="/media/{movie.file}" type="video/mp4">
                Your browser does not support the video tag.
            </video>"""
        )

    preview.short_description = 'Movie image'
    video.short_description = 'Movie video'
    list_display = ['name', 'preview', 'video', 'description']

admin.site.register(Movie, MovieAdmin)
Enter fullscreen mode Exit fullscreen mode
  • We used the Django class django.contrib.admin.ModelAdmin to customize how our Movie will be displayed. We used the django formatter django.utils.html.format_html to render the preview_image and file video as HTML.
  • With list_display = ['name', 'preview', 'video', 'description'] we ask django to display the computed preview and video and also the name and description attributes of each Movie record of the database.

And this is the result:

Image description

NB: The full source code is available here: https://github.com/fayomihorace/django-netflix-clone

Congratulations.

We are at the end of this first part.

Summary

In this tutorial you've learned:

  • what is Django
  • how to create a Django project
  • how to create an app and link it to the project
  • the basics Django files architectures
  • the basics Django settings
  • what is a model and how to create models
  • How to use the basic Django model fields
  • what is Django ORM
  • what is a Django Model manager and how to perform basic database operations on them
  • How to use Django Shell to easily play with our models
  • what are migrations, and how to create them
  • How to start a Django development server
  • what are statics files and media files and how to set up them
  • How to register your models with Django admin and create a superuser
  • How to manage our database using the Django admin interface.

If you faced any blocker or error while following this tutorial, please drop a comment, I'll reply to help you as soon as possible. Excited to have you in part 2 of this tutorial-course.

Top comments (14)

Collapse
 
yvan_koabiloa_c95508b4ff profile image
Yvan KOA BILOA

When you do the python command manage.py makemigrations for the Django migrations topic, you get two categories:

  • Create Model Movie
  • Create Model Category I don't get this. I only get init.py. What is the problem for me?

But also in Media, you have two sub-files that appear movies and preview_images. I don't get those categories either. Can you also explain to me where my problem might be?
Image description

Collapse
 
fayomihorace profile image
Horace FAYOMI

Hey Yvan, it's not normal indeed. Are you sure you've added the models code into your models.py file.

Collapse
 
yvan_koabiloa_c95508b4ff profile image
Yvan KOA BILOA

yes, I added the models code in my models.py file but it didn't work. And I can't go further when I try to replicate your model for the database. Could you help me please ?

Thread Thread
 
fayomihorace profile image
Horace FAYOMI • Edited

Yes, you could either:
1- push the current state of your code on github and send me the link so I'll pull and debug for you
Or
2- we could schedule a live pair programming debugging session
Which one works best for you ?

Anyways, here is my github email: fayomihorace@gmail.com

Ans if you go for the pair programming, write me to this email folahanfayomi@gmail.com.

Collapse
 
fayomihorace profile image
Horace FAYOMI

For the two sub-files in media folder don't worry, it's not required at this step of the tutorial even though it is in the final source code.

Collapse
 
yvan_koabiloa_c95508b4ff profile image
Yvan KOA BILOA

Thank you

Collapse
 
footroot profile image
El_Taller

Hello everybody, I'm a bit stack here.

Django Shell: play with our data
To quickly test our models and the manager, Django provides a very useful tool called Django Shell.


Open a terminal on VSCode (by default it will be opened ad the root of the project).
----------C:\shared\netflix_django\django_netflix_clone>
---------- I can open a terminal on VSCode but when I Run -------
Run: python man shell. A new command prompt will be shown.
---------- I've got the error:
C:\shared\netflix_django\django_netflix_clone>python man shell

python: can't open file 'C:\shared\netflix_django\django_netflix_clone\man': [Errno 2] No such file or directory

Also, I don't understand this line........
Import our Movie models: from netflix.models import Movie

any help, explain, πŸ’©πŸ’©

Collapse
 
fayomihorace profile image
Horace FAYOMI • Edited

Also the line:
from netflix.models import Movie is a module importation. It's more a python stuff here. We have a class called Movie inside the file models.
Remember that to be able to use a function or class that is not available in a given file, you should import that function or class from it source inside the file that should use it.
Let take a simple exemple, guess you have this architechure:

- root
     |--- file1.py
     |--- file2.py 
Enter fullscreen mode Exit fullscreen mode

And file1.py contains this:

# inside file1.py
def util_function(value):
     """Here is an utils function."""
     print(value)
     # Do usefull stuff with the value...

class UtilClass:
    """Here is a util class."""
    def __init__(self, name):
        pass
Enter fullscreen mode Exit fullscreen mode

and then you want to use the util_function of the UtilClass inside file2.py,
you can import them like this:

# inside file2.py
from .file1 import util_function, UtilClass

# we can use them
util_function(56)
utlil_class = UtilClass()
Enter fullscreen mode Exit fullscreen mode

I fyou got that, you should also know that, as we need to import a class or function or module in order to use it in another file, we should import them into django shell too. That why we need to import Movie model if we want to test it into django shell. And becasue the django shell root folder is the project root folder django_netflix_clone, which contains all our app folders modules (netflix included), and also because Movie is inside the path django_netflix_clone/netflix/models.py to import it we do from netflix/models import Movie.
Hope that help you.

Collapse
 
fayomihorace profile image
Horace FAYOMI

Hello Taller. That might happen because you're on windows instead of linux.
Let me test it on windows and give you a feedback soon.

Collapse
 
footroot profile image
El_Taller

Hello all,
I setup the virtual environment so I've got the folder estructure. I'm using VScode.
I set up the virtual environment on my xampp server.
everything was working, folders and files structure.
I stopped before to do the migrations.
but when I disconnected the ftp from the server and open the project again some of the files had disappeared.
there is only two folders and two files:
django_netflix_clone
django_netflix_clone/
settings.py
netflix/
models.py
requirements.txt

can anybody tell me why?

thanks

Collapse
 
fayomihorace profile image
Horace FAYOMI

Are you sure you saved the files before you deconnected from FTP ?
Do you have auto save enabled on VScode ?

Collapse
 
footroot profile image
El_Taller

Hello Orace,
Well, yes, I do have auto save enabled on my VScode, and yes I always check if everything has been saved on my server via FTP.
Any other ideas?
Thx

Collapse
 
fayomihorace profile image
Horace FAYOMI

Hum, I used to work with git, never worked directly with a remote server.
Currently I have no cluefor you.
But I recommends you to not work directly on the server, work locally on git, and progressivlely commit your changes to git and pull the working branch on your sever.

Collapse
 
footroot profile image
El_Taller

Hello,
What is the way to put this app on a server.
Let's say....
Www.clone.xx
Which is my local server
Thanks