Introduction Welcome to the second part of our Django Tutorial! In the previous lesson, we installed everything that we needed. Hopefully, you are all setup with Python 3.6 installed and Django 1.11 running inside a Virtual Environment.
We already created the project we are going to play around. In this lesson, we are going to keep writing code in the same project.
In the next section, we are going to talk a little bit about the project we are going to develop, so to give you some context. Then after that, you are going to learn all the Django fundamentals: models, admin, views, templates, and URLs. Web Board Project I don’t know about you, but personally, I learn much more by seeing practical examples and code snippets. For me, it’s difficult to process a concept where in the examples you read Class A and Class B, or when I see the classical foo(bar) examples.
In your Mac OS X or Linux console, you should run the following command. Don't forget to add the period (or dot). Command-line (myvenv) ~/djangogirls$ django-admin startproject mysite. Is crucial because it tells the script to install Django in your current directory (for which the period. Is a short-hand reference).
I don’t want to do that with you. So, before we get into the fun part, playing with models, views, and everything. Let’s just take a moment and discuss very briefly about this project we are going to develop. If you already have experience with Web development and feel it’s too much detail, you can just skim through the pictures to have an idea what we are going to build and then jump to the Models section of this tutorial. But if you are new to Web development, I highly suggest that you keep reading. It will give you some good insights on modeling and design of Web applications.
Web development, and software development in general, is not just about coding. Use Case Diagram Our project is a discussion board (a forum). The whole idea is to maintain several boards, which will behave like categories.
Then, inside a specific board, a user can start a new discussion by creating a new topic. In this topic, other users can engage in the discussion posting replies. We will need to find a way to differentiate a regular user from an admin user because only the admins are supposed to create new boards. Below, an overview of our main use cases and the role of each type of user: Figure 1: Use case diagram of the core functionalities offered by the Web Board Class Diagram From the Use Case Diagram, we can start thinking concerning the entities of our project.
The entities are the models we will create, and it’s very closely related to the data our Django app will process. For us to be able to implement the use cases described in the previous section, we will need to implement at least the following models: Board, Topic, Post, and User. Figure 2: Draft of the class diagram of the Web Board It’s also important to take the time to think about how do models will relate to each other. What the solid lines are telling us is that, in a Topic, we will need to have a field to identify which Board it belongs to. Similarly, the Post will need a field to represent which Topic it belongs so that we can list in the discussions only Posts created within a specific Topic. Finally, we will need fields in both the Topic to know who started the discussion and in the Post so we can identify who is posting the reply.
We could also have an association with the Board and the User model, so we could identify who created a given Board. But this information is not relevant for the application.
There are other ways to track this information, you will see later on. Now that we have the basic class representation, we have to think what kind of information each of those models will carry. This sort of thing can get complicated very easily.
So try to focus on the important bits. The information that you need to start the development. Later on, we can improve the model using migrations, which you will see in great detail in the next tutorial. But for now, this would be a basic representation of our models’ fields: Figure 3: Class diagram emphasizing the relationship between the classes (models) This class diagram has the emphasis on the relationship between the models.
Those lines and arrows will eventually be translated into fields later on. For the Board model, we will start with two fields: name and description.
The name field has to be unique, so to avoid duplicated board names. The description is just to give a hint of what the board is all about. The Topic model will be composed of four fields: subject, last update date which will be used to define the topics ordering, topic starter to identify the User who started the Topic, and a field called board to define which Board a specific Topic belongs to. The Post model will have a message field, which will be used to store the text of the post replies, a created at date and time field mainly used to order the Posts within a Topic, an updated at date and time field to inform the Users when and if a given Post has been edited. Like the date and time fields, we will also have to reference the User model: created by and updated. Finally, the User model. In the class diagram, I only mentioned the fields username, password, email and is superuser flag because that’s pretty much all we are going to use for now.
It’s important to note that we won’t need to create a User model because Django already comes with a built-in User model inside the contrib package. We are going to use it. Regarding the multiplicity in the class diagram (the numbers 1, 0., etc.), here’s how you read it: A Topic must be associated with exactly one ( 1) Board (which means it cannot be null), and a Board may be associated with many Topics or none ( 0.). Which means a Board may exist without a single Topic.
A Topic should have at least one Post (the starter Post), and it may also have many Posts ( 1.). A Post must be associated with one, and only one Topic ( 1). A Topic must have one, and only one User associated with: the topic starter User ( 1). And a User may have many or none Topics ( 0.). A Post must have one, and only one User associated with: created by ( 1).
A User may have many or none Posts ( 0.). The second association between Post and User is a direct association (see the arrow at the end of the line), meaning we are interested only in one side of the relationship which is what User has edited a given Post. It will be translated into the updated by field. The multiplicity says 0.1, meaning the updated by field may be null (the Post wasn’t edited) and at most may be associated with only one User.
Another way to draw this class diagram is emphasizing the fields rather than in the relationship between the models. Figure 4: Class diagram emphasizing the attributes (fields) of the classes (models) The representation above is equivalent to the previous one, and it’s also closer to what we are going to design using the Django Models API.
In this representation, we can see more clearly that in the Post model the associations topic, created by, and updated by became model fields. Another interesting thing to note is that in the Topic model we have now an operation (a class method) named posts. We are going to achieve this by implementing a reverse relationship, where Django will automatically execute a query in the database to return a list of all the Posts that belongs to a specific Topic. Alright, enough UML for now!
To draw the diagrams presented in this section I used the tool. Wireframes After spending some time designing the application models, I like to create some wireframes to define what needs to be done and also to have a clear picture of where we are going. Then based on the wireframes we can gain a deeper understanding of the entities involved in the application. First thing, we need to show all the boards in the homepage. Figure 9: Reply topic screen To draw your wireframes you can use the service, it’s free. Models The models are basically a representation of your application’s database layout.
What we are going to do in this section is create the Django representation of the classes we modeled in the previous section: Board, Topic, and Post. The User model is already defined inside a built-in app named auth, which is listed in our INSTALLEDAPPS configuration under the namespace django.contrib.auth. We will do all the work inside the boards/models.py file. Here is how we represent our class diagram (see ). In a Django application: from django.db import models from django.contrib.auth.models import User class Board ( models.
Model ): name = models. CharField ( maxlength = 30, unique = True ) description = models.
CharField ( maxlength = 100 ) class Topic ( models. Model ): subject = models. CharField ( maxlength = 255 ) lastupdated = models. DateTimeField ( autonowadd = True ) board = models. ForeignKey ( Board, relatedname = 'topics' ) starter = models. ForeignKey ( User, relatedname = 'topics' ) class Post ( models.
Model ): message = models. TextField ( maxlength = 4000 ) topic = models. ForeignKey ( Topic, relatedname = 'posts' ) createdat = models. DateTimeField ( autonowadd = True ) updatedat = models.
DateTimeField ( null = True ) createdby = models. ForeignKey ( User, relatedname = 'posts' ) updatedby = models.
ForeignKey ( User, null = True, relatedname = '+' ) All models are subclass of the django.db.models.Model class. Each class will be transformed into database tables. Each field is represented by instances of django.db.models.Field subclasses (built-in Django core) and will be translated into database columns. The fields CharField, DateTimeField, etc., are all subclasses of django.db.models.Field and they come included in the Django core – ready to be used. Here we are only using CharField, TextField, DateTimeField, and ForeignKey fields to define our models. But Django offers a wide range of options to represent different types of data, such as IntegerField, BooleanField, DecimalField, and many others. We will refer to them as we need.
Some fields have required arguments, such as the CharField. We should always set a maxlength. This information will be used to create the database column. Django needs to know how big the database column needs to be. The maxlength parameter will also be used by the Django Forms API, to validate user input.
More on that later. In the Board model definition, more specifically in the name field, we are also setting the parameter unique=True, as the name suggests, it will enforce the uniqueness of the field at the database level.
In the Post model, the createdat field has an optional parameter, the autonowadd set to True. This will instruct Django to set the current date and time when a Post object is created. One way to create a relationship between the models is by using the ForeignKey field. It will create a link between the models and create a proper relationship at the database level. The ForeignKey field expects a positional parameter with the reference to the model it will relate to.
For example, in the Topic model, the board field is a ForeignKey to the Board model. It is telling Django that a Topic instance relates to only one Board instance. The relatedname parameter will be used to create a reverse relationship where the Board instances will have access a list of Topic instances that belong to it. Django automatically creates this reverse relationship – the relatedname is optional. But if we don’t set a name for it, Django will generate it with the name: (classname)set.
For example, in the Board model, the Topic instances would be available under the topicset property. Instead, we simply renamed it to topics, to make it feel more natural. In the Post model, the updatedby field sets the relatedname='+'.
This instructs Django that we don’t need this reverse relationship, so it will ignore it. Below you can see the comparison between the class diagram and the source code to generate the models with Django. The green lines represent how we are handling the reverse relationships. At this point, you may be asking yourself: “what about primary keys/IDs”? If we don’t specify a primary key for a model, Django will automatically generate it for us. So we are good for now.
In the next section, you will see better how it works. Migrating the Models The next step is to tell Django to create the database so we can start using it. Open the Terminal Command Line Tools, activate the virtual environment, go to the folder where the manage.py file is, and run the commands below: python manage.py makemigrations As an output you will get something like this: Migrations for 'boards': boards/migrations/0001initial.py - Create model Board - Create model Post - Create model Topic - Add field topic to post - Add field updatedby to post At this point, Django created a file named 0001initial.py inside the boards/migrations directory.
It represents the current state of our application’s models. In the next step, Django will use this file to create the tables and columns.
The migration files are translated into SQL statements. If you are familiar with SQL, you can run the following command to inspect the SQL instructions that will be executed in the database: python manage.py sqlmigrate boards 0001 If you’re not familiar with SQL, don’t worry. We won’t be working directly with SQL in this tutorial series. All the work will be done using just the Django ORM, which is an abstraction layer that communicates with the database.
The next step now is to apply the migration we generated to the database: python manage.py migrate The output should be something like this: Operations to perform: Apply all migrations: admin, auth, boards, contenttypes, sessions Running migrations: Applying contenttypes.0001initial. OK Applying auth.0001initial. OK Applying admin.0001initial. OK Applying admin.0002logentryremoveautoadd.
OK Applying contenttypes.0002removecontenttypename. OK Applying auth.0002alterpermissionnamemaxlength. OK Applying auth.0003alteruseremailmaxlength.
OK Applying auth.0004alteruserusernameopts. OK Applying auth.0005alteruserlastloginnull.
OK Applying auth.0006requirecontenttypes0002. OK Applying auth.0007altervalidatorsadderrormessages. OK Applying auth.0008alteruserusernamemaxlength. OK Applying boards.0001initial. OK Applying sessions.0001initial.
OK Because this is the first time we are migrating the database, the migrate command also applied the existing migration files from the Django contrib apps, listed in the INSTALLEDAPPS. This is expected. The line Applying boards.0001initial. OK is the migration we generated in the previous step. Our database is ready to be used.
Note: It's important to note that SQLite is a production-quality database. SQLite is used by many companies across thousands of products, like all Android and iOS devices, all major Web browsers, Windows 10, macOS, etc. It's just not suitable for all cases. SQLite doesn't compare with databases like MySQL, PostgreSQL or Oracle. High-volume websites, write-intensive applications, very large datasets, high concurrency, are some situations that will eventually result in a problem by using SQLite. We are going to use SQLite during the development of our project because it's convenient and we won't need to install anything else. When we deploy our project to production, we will switch to PostgreSQL.
For simple websites this work fine. But for complex websites, it's advisable to use the same database for development and production. Experimenting with the Models API One of the great advantages of developing with Python is the interactive shell. I use it all the time. It’s a quick way to try things out and experiment libraries and APIs. You can start a Python shell with our project loaded using the manage.py utility: python manage.py shell.