Starting the project#
Introduction#
Let's start this tutorial in earnest.
In this chapter:
- we'll set up everything we'll need to start coding (our virtual environment and our project directories)
- we'll learn how to structure a Django project, how to create applications, how to change settings
- we'll write several models, create a database, use the famed Django admin, and finally get our app running locally.
Virtual environment#
Before doing anything else, we need to create our virtual environment.
We're working with conda
(tutorial), but you can use your favourite virtual lib, like virtualenv
(tutorial).
1 2 3 |
|
Now, you have a virtual environment with django
and faker
installed.
Project layout and folder structure#
We'll be following a simplified version of the folder structure described in the Two Scoops of Django by Daniel and Audrey Feldroy.
We want our folder structure to look something like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Before we get there, however, we need to go through the Django defaults.
Let's create a folder for our project: we'll name it django_tutorial
. After that, we'll create our project, conduit
, inside django_tutorial
:
1 2 3 |
|
Advice
We strongly recommend you use git when going through this tutorial.
Our folder structure should look like this at this point:
1 2 3 4 5 6 7 8 |
|
We'll move all the files in the conduit
folder into the django_tutorial/config
folder, as we explained above. The project layout should now be:
1 2 3 4 5 6 7 8 9 |
|
Because we're deviating from Django's generic project layout, we'll have to update some lines in the settings. You might wonder why we have to fiddle with the settings before even starting to code, but this small effort has the benefit of making the structure of our project easier to understand, and of separating the config from the code, which is a good habit to get into.
In config/asgi.py
, config/wsgi.py
, and ./manage.py
, we update the location of our settings.py
file:
1 2 3 4 |
|
We do the same in config/settings.py
:
1 2 3 4 5 6 7 |
|
Done! We have implemented a project layout that separates the config (in the config
folder) from the code (in the conduit
folder) and told Django to take this into account.
Our app will have a lot of moving parts (articles, profiles, tags, etc.). To keep the structure of our app clear, we'll host the logic for each of these parts in separate folders.
We'll build Conduit step by step.
articles
application#
The most basic function that the Conduit app should have is the ability to post and read articles. Let's start with that (you'll notice that this part is basically a repeat of DjangoGirls tutorial's blog app).
We'll create an articles
application (a package that provides a specific set of features) that will hold all the logic that is related to dealing with articles.
1 2 3 |
|
Our folder structure now looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Because of our folder structure, we will need to make a small adjustment in the file articles/apps.py
:
1 2 3 4 5 6 7 |
|
We also add the articles
application to the INSTALLED_APPS
setting in config/settings.py
, in order to let Django know about our new app articles
:
1 2 3 4 5 6 7 8 9 |
|
users
app and User
model#
The Django docs warn you: “If you're starting a new project, it's highly recommended to set up a custom user model, even if the default User model is sufficient for you. […] Changing AUTH_USER_MODEL after you've created database tables is significantly more difficult […]. This change can't be done automatically and requires manually fixing your schema, moving your data from the old user table, and possibly manually reapplying some migrations.”.
Scary stuff. Let's just follow the advice.
First, we need to create the app where we'll put all the logic that has to do with users.
1 |
|
We remember to take into account our folder structure in users/apps.py
:
1 2 3 4 5 6 7 |
|
And we add the new users
application to our INSTALLED_APPS
in config/settings.py
:
1 2 3 4 5 |
|
Now, in users/models.py
, add the following:
1 2 3 4 5 6 7 8 |
|
What we're doing here is exactly what the Django docs advise us to do: we take the AbstractUser
model and save it as is, which will provide us with a custom user model. This way, we can add any modifications that we need later on.
Finally, we need to tell Django that we're not using the default User
model. In config/settings.py
, point AUTH_USER_MODEL
to it:
1 2 |
|
Great, our user
application and our custom User
model are ready.
Create a database#
Django uses a SQLite database by default: it's versatile, simple, and sufficient for our needs. Django also supports other databases, notably PostgreSQL, which is what we would want to use if our app was expected to grow fast, but for now we will stay with SQLite.
Info
We would arguably learn more by setting up a PosgreSQL database: SQLite is a “set it and forget it”, “just works” type of thing. Since learning more is the point of this tutorial, we might shift to PostgreSQL at some point.
After any change to a model, we need to sync the database so that the changes can be propagated into the database schema. If you don't yet know what that means, no worries: we'll have a much closer look at what exactly is in our database, and what happens when we run migrations.
Specifically in this case, we want Django to create an Article
table that will hold our articles.
Since we changed the Articles
model, we will run the following commands:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
We'll be doing this many times throughout the tutorial: if your app refuses to run at some point, the most likely error (from experience) is that you forgot to migrate, so make sure you keep on top of it.
Create a superuser#
One of Django's greatest advantages is its admin app: it is considered so helpful that you probably will see it mentioned in most discussions about Django.
To be able to access the admin app (which we will do in a later section), we need a superuser. Run the following and fill the values (you don't need a real email or a strong password here):
1 2 3 4 5 6 |
|
Profile
model#
In users/models.py
we also need to create a Profile
model: we'll explain it in more detail later, but suffice it to say that the Profile
will deal with everything about our users that is not authentication (ie logging in and out).
1 2 3 4 5 6 7 8 9 |
|
We'll go through the code step by step:
- The docs for the
OneToOneField
model field read: “A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object. This is most useful as the primary key of a model which “extends” another model in some way”. This is exactly we need, because eachUser
has one associatedProfile
, and eachProfile
corresponds to a singleUser
. on_delete
is a required argument forOneToOneField
and specifies what happens when the model instance is deleted.- the
__str__
method tells Django what the string representation of the model should be: this is how specific model instances will be represented in the Django admin app, in the shell, in the error messages, in the templates, etc. Here, we specify that we want our profiles to be referenced by the associated user's username.
Now that we have a Profile
model, we want to create one for our existing user (the admin
superuser). Later on, we will automate the creation of a profile for every new user, but this is not implemented yet, so we need to do it manually. Well, thankfully Django allows us to interact with it through a Python shell.
1 |
|
And now that we're in the IPython shell, we will interact with the Django ORM: we will get our admin
user from the User
objects and then create a Profile
instance.
1 2 3 4 5 6 7 |
|
You might wonder why we're importing get_user_model
instead of the User
model directly: this is best practice and ensures we're working with the currently active user model.
However, if you've been following up to now… you should have gotten an error above. Namely, you should have gotten:
OperationalError: no such table: users_profile
90% of programming is writing code, and the other 90% of programming is debugging, as the saying goes, so we might as well learn to deal with Django's errors while learning Django. The error above says that our database has no table users_profile
: why might that be? Because we didn't sync our database after modifying our models!
Open a new terminal session and run migrations:
1 2 3 4 5 6 7 8 9 |
|
Now return to the previous session and rerun the shell command: there should be no error this time.
Start the server#
We have everything we need to actually run our app. Let's start the server!
1 |
|
You should see this:
Our app, Conduit, is online!
Article
model#
We'll start by making a model for our articles.
When creating a model, we need to think of what fields the model will need. Let's take 2 seconds to think. Any article needs:
- a title
- a body (the text)
- a description
- an author
- a creation date.
Let's implement that in articles/models.py
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Let's explain everything step by step:
- the article's
title
will be used asdb_index
: when we do queries on articles in our database, we'll often be looking at thetitle
, so having this field as index will speed the queries description
andbody
are self-explanatoryauthor
is a bit more complicated:- the
ForeignKey
model field allows us to have a many-to-one relationship: multiple articles for every profile - we have seen
on_delete
, but notrelated_name
:related_name="articles"
allows us to access a user's (or rather profile's) articles through anarticles
attribute (for example,User.articles.all()
to get theadmin
user's articles) auto_now_add
simply records the time of creation forcreated_at
- the
__str__
method says that the string representation of an article will be its title
Let's sync the database again:
1 2 3 4 5 6 7 8 9 |
|
Using the Django admin#
In order to have something to work with for the rest of the tutorial, we need to create some posts. Because we can't yet do it through Conduit, we will do so through Django admin.
In order for the Django admin to have access to the Article
model, we need to register it in articles/admin.py
:
1 2 3 4 |
|
That's it, the Article
model is now editable through the Django admin. The server should still be running (otherwise restart it). We will go to the Django admin app (http://127.0.0.1:8000/admin/) and log in as the superuser (admin
in my case) that we created earlier.
Once we're logged in, we will create three articles in Django admin:
- click “:heavy-plus-sign: Add” in the
Articles
section - specify a title, a description, a body, and the author (you) for the article
- click “Save and add another”