5: Creating Django Models, Using Admin site and Dynamic Templates
Hi, welcome back to this part of the series, in this post we will learn what a model and learn more about Creating Django models, write a model for tickets and learn about exiting bit of Django called Admin site. After that, we will load data from database and display them on templates. If you have not been following please go through all previous chapters here.
The must-read
As we talked about MVT earlier we are now on the model part. Models describe how our data is structured and stored in the database. Django uses models.py for this. If you are familiar with Object-Oriented Programming (OOP) then one Model is just an object.
An object in OOP is an instance of a class. In real life, objects are just things we can see like Person, Cars e.t.c. Take Person, for example, a person object will have person properties and actions. i.e tall, dark, handsome, and a person can talk, walk, run, sleep etc. objects can also have ways of relating with other objects, for example, a person can eat and eat will have an object called human food human food can have its own properties like cooked, fried, raw etc
Person
---------
Dark
Tall
Slim
Handsome
Walk()
Talk()
Sleep()
Eat(human food)
Human Food
-----------
Cooked
Dried
Raw
As you can tell the once with () are actions or behaviours of the object and those without it are the properties.
In programing we represent the above with fields and methods Also remember an object is an instance of a class.
If you didn’t understand the above explanations don’t worry let us implement it in Django and you will understand. If it is still hard don’t give up the more you do it it’ll automatically make sense someday.
Now each model maps to a database table. If you have used PHP before or java there’s a probability that you were creating a Database manually and adding tables with their fields manually. We are lucky today since Django will be doing most of the work for us, we only need to do two things.
- Set the database we will be using in settings.py by default Django sets this for us to sqlite3 if you didn’t change it in settings.py you should have this:
- Give Django Model classes in models.py which is in our app’s root directory (our app is called ticketing). Currently, it should be like this:
Let us plan how our models will look like.
Our first model is Ticket which should have the following fields :
-
- Opened_by: The person opening the ticket
- opened_on: Date that the ticket was opened
- closed_on: Date the ticket was closed
- office_description: Assuming we have many offices you can specify where i.e second floor left
- type: type of the ticket i.e Network issue, phone issue etc.
- description: the one who opened the ticket can describe the issue more here
- done_by: the support team who worked on the ticket
- closed_by: the person who closed the ticket
- status: Status of the ticket eg closed, pending, in progress
As you can see type field should be a choice field but wait, this is a field that will keep being updated whenever there is a new type of issue. For that, we should not have it hardcoded so we will create a table for types too. so our second model is Type and has:
- name: type name
- added_by: for easy audit
That is it. Django by default will create id field for us.
Let’s open our project in your favorite editor, mine is vs code. Let’s start creating models in Django.
ticketing/models.py
[snippet slug=model lang=python]Line 1,2,3: We import some dependencies we’ll use.
Line 4 (ignoring whitespace): We are creating a model Type, Python classes here maps to a table in the database and the attributes inside that class are the database fields. So we will create a table called Type.
Line 5 and 6: These are the fields that our fields will have. In this case, all are Character fields but we’ll change added_by to ForeginKey later on.
Line 7: We are declaring a method, this method will ensure that whenever each object is called from this model what we see is type_name and not Object(1) etc. You will see its importance in a few. it is not necessary though
Let us Create the next Model:
class Ticket(models.Model):
STATUS_CHOICES = (
('pending', 'Pending'),
('inprogress', 'Inprogress'),
('closed', 'Closed'),
)
opened_by = models.CharField(max_length=100)
opened_on = models.DateTimeField(default=timezone.now)
closed_date = models.DateTimeField(null=True)
office_description = models.CharField(null=True, max_length=100)
ticket_type = models.ForeignKey(
'Type',
on_delete=models.CASCADE,
)
description = models.TextField()
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='pending')
done_by = models.CharField(max_length=100)
closed_by = models.CharField(max_length=100)
def __str__(self):
return str(self.id)
Here I’ll highlight a few things :
Line 2: We are defining a choice that we will use in the status field. A ticket can only be in one of the above statuses at any given time.
Line 11: We have a relation here. ForeignKey, meaning one Type can have several tickets. and one ticket can only have one type.
Final models.py:
from django.conf import settings
from django.db import models
from django.utils import timezone
class Type(models.Model):
type_name = models.CharField(max_length=50)
added_by = models.CharField(max_length=20)
def __str__(self):
return self.type_name
class Ticket(models.Model):
STATUS_CHOICES = (
('pending', 'Pending'),
('inprogress', 'Inprogress'),
('closed', 'Closed'),
)
opened_by = models.CharField(max_length=100)
opened_on = models.DateTimeField(default=timezone.now)
closed_date = models.DateTimeField(null=True)
office_description = models.CharField(null=True, max_length=100)
ticket_type = models.ForeignKey(
'Type',
on_delete=models.CASCADE,
)
description = models.TextField()
status = models.CharField(max_length=10,
choices=STATUS_CHOICES,
default='pending')
done_by = models.CharField(max_length=100)
closed_by = models.CharField(max_length=100)
def __str__(self):
return str(self.id)
Awesome. Lets now make migrations and migrate, I hope you have activated your virtual environment
python manage.py makemigrations ticketing
migrate:
python manage.py migrate
my results:
(venv) symons@symons-macbookair:~/STICKETING$ python manage.py makemigrations ticketing
Migrations for 'ticketing':
ticketing/migrations/0001_initial.py
- Create model Type
- Create model Ticket
(venv) symons@symons-macbookair:~/STICKETING$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, ticketing
Running migrations:
Applying ticketing.0001_initial... OK
(venv) symons@symons-macbookair:~/STICKETING$
That has created a database and tables Ticketing and Type in it, with the fields we specified. If you are so curious you can check migrations folder and open 0001_initial.py it contains the SQL commands it fired. Its autogenerated file so, don’t change anything in it!
ticketing/migrations/0001_initial.py:
You can also use SQLite studio to open db.sqlite3 that was created.
Admin site
Django Ships with amazing administration site that will help us insert, read, delete and update our ticket and types.
Open ticketing/admin.py and have the following:
from django.contrib import admin
from .models import Type, Ticket
admin.site.register(Type)
admin.site.register(Ticket)
Then go to terminal and do:
python manage.py createsuperuser
You will be asked to enter the username, email and password. note that password is not visible as you type.
(venv) symons@symons-macbookair:~/STICKETING$ python manage.py createsuperuser
Username (leave blank to use 'symons'): symons
Email address: info@omborisymons.com
Password:
Password (again):
Superuser created successfully.
Now runserver and let us visit http://127.0.0.1:8000/admin
you should be prompted to log in. use the credentials you created earlier:
Now You can see our Models here. You can click on add Types and add like two or more then add tickets too.
Currently, just fill all the fields. There are some fields we will make null=True and blank= True
If you click on types You should see where the method we had in medels.py is used. They are listed with their names.
You can explore this admin interface more.
Loading data dynamically in templates.
To load data we go to views. py. That is where we do the queries and pass the result to the template. For now, we want to populate the table in http://127.0.0.1:8000/support/home
with tickets from the database.
Got to views.py and update the support method to match this:
def support(request):
tickets = Ticket.objects.all() #storying query results on tickets variable
return render(request, 'support/home.html', {'tickets': tickets})
Now in templates, we will loop through tickets and print properties we want.
templates/support/home.html
{% for ticket in tickets%}
<tr>
<td>{{ticket.id}}</td>
<td>{{ticket.opened_by}}</td>
<td>{{ticket.opened_on}}</td>
<td>Take | View</td>
</tr>
{%endfor%}
That should do the magic. you can read about jinja templating.
The whole page is
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="card">
<div class="card-body">
<h6>Tickets</h6>
<div class="container">
<table class="table table-striped">
<thead>
<tr>
<th>Ticket No.</th>
<th>Opened By:</th>
<th>Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for ticket in tickets%}
<tr>
<td>{{ticket.id}}</td>
<td>{{ticket.opened_by}}</td>
<td>{{ticket.opened_on}}</td>
<td>Take | View</td>
</tr>
{%endfor%}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock content %}
That is all about creating models in django.
Let us meet in the next chapter, I feel I said a lot give me your feedback.
Get the code from github
You may join my whatsapp group
or Contact me personally info@omborisymons.com
1 Comment
Symons
October 7, 2021fd