How I Made My First Django App
It’s not easy to start working with your first framework, initially it seems daunting task but trust me you can only learn by doing because this way you know where are you lacking and you can have more clear idea about your problems.
In this post, We’ll learn how one can start working with their first Django project.
Requirments:
- Python -3.6
- Django -2.0
Getting started
I started with Django Documentation, There is an official tutorial on Django’s website and it’s really good point to start. This tutorial covers all your installation process and you can start working on a project as soon as you install all the dependencies.
It is simple CRUD application in which you can create a poll, you can add questions, choices and you can track votes of each choice.
After making Poll app I made my second project which is a blog website. I used Django Girls Tutorial for this project and it helped me to understand Django structure more.
At this point, I’ve made two projects but I was not getting enough confidence in Django so I started working on a project without any tutorial and that’s where actual learning happened. I made basic Contact App where you can simply create contacts, edit and delete them.
Note: I would suggest you to do one of the above tutorial first and then come to this tutorial. By this way It will be easy for you to understand and implement steps in below tutorial.
Contact App
Let’s start making our app
First make a project folder in which our all files will be-
$ mkdir ContactApp
After making project folder we will make virtual environment
~/ContactApp$ python3 -m venv myvenv
Now we’ll activate virtual environment
~/ContactApp$ source myvenv/bin/activate
Now our virtual environment is created, we will install Django for our project.
(myvenv) ~/ContactApp$ pip install django
Collecting django
Cache entry deserialization failed, entry ignored
Using cached https://files.pythonhosted.org/packages/56/0e/afdacb47503b805f3ed213fe732bff05254c8befaa034bbada580be8a0ac/Django-2.0.6-py3-none-any.whl
Collecting pytz (from django)
Cache entry deserialization failed, entry ignored
Using cached https://files.pythonhosted.org/packages/dc/83/15f7833b70d3e067ca91467ca245bae0f6fe56ddc7451aa0dc5606b120f2/pytz-2018.4-py2.py3-none-any.whl
Installing collected packages: pytz, django
Successfully installed django-2.0.6 pytz-2018.4
Now we are done with Django setup and ready to work….
Here I’m using Sublime text editor, you can use any other text editor.
Now we will start our project
(myvenv) ~/ContactApp$ django-admin startproject mysite .#Remember there is space between mysite and .
#If we don't use . then manage.py file will be in mysite folder but we want it to be in our project folder that's why we used above command.
Our project folder will look like this:
ContactApp
|---myvenv
|---mysite
__init__.py
settings.py
urls.py
wsgi.py
|---manage.py
There is a settings.py file in mysite folder, we have to make changes in this file.Make the following changes in settings.py file.
- set ALLOWED_HOSTS = [‘127.0.0.1’]
- Here is the list of time zones, set TIME_ZONE accordingly.
- We also need to add path for static files. Go down to the end of the file, and just underneath the
STATIC_URL
entry, add a new one calledSTATIC_ROOT
:
ALLOWED_HOSTS = ['127.0.0.1']
TIME_ZONE = 'Asia/Kolkata'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
We need to create a database for our app, so go to console and type the following command:
(myvenv) ~/ContactApp$ python manage.py migrate
If everything goes correctly then we will see this —
(myvenv) ~/ContactApp$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
Everything is going according to the plan, now we need to start the web server. For that go to the console and type following command:
(myvenv) ~/ContactApp$ python manage.py runserver
After starting the web server we’ll see Django default congratulation page.
Now we’ll create an application for our contact app, we can have multiple apps in our project but here we will work on creating a single app.
To create an application run following command in console:
(myvenv) ~/ContactApp$ python manage.py startapp app-name##you can choose any name for you app, just type the name of your ##app on the place of app-name.
##I will write 'contact', you can write yours or go with my name.
This command will add folder named “contact” to our project folder and this folder will contain some files.
ContactApp
|---myvenv
|---contact
migrations
__init__.py
admin.py
apps.py
models.py
views.py
tests.py
__init__.py
|---db.sqlite3
|---mysite
__init__.py
settings.py
urls.py
wsgi.py
|---manage.py
Go to settings.py file and add contact to installed apps-
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'contact',
]
Creating a Model
A model.py file is the place where we will store information about our contacts like name, email phone etc. Django saves model in database. Default Django database adapter is SQlite.
Let’s setup our models.py file
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
from django.utils import timezoneclass Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
email = models.EmailField(max_length=250)
phone = PhoneNumberField() def publish(self):
self.published_date = timezone.now()
self.save() def full_name(self):
return '{} {}'.format(self.first_name, self.last_name) def __str__(self):
return self.full_name()
- First we import our Django models, then we import timezone and PhoneNumberField which will help us to store phone number.
- After that we made class Person and add models.Model to notify Django that it’s a Django model.
- Next we want to collect information of a person and that’s where Django fieldtypes comes into the game. what fieldtype will be used depends on what information you want to fill in. You can know more about Django fieldtypes in documentation.
- In this example we want first_name, last_name, email and phone. first_name and last_name are strings, so for string data we used charfield and we can set max_length argument according to our string size, for names 20 is enough.
- For email we used Emailfield and because no PhoneNumberField exist in Django, so we used third party package to store phone number and imported it above. Guide to add phonenumber_field.
- Next we defined three functions: publish, full_name and __str__. Publish function will save person info according to timezone, full_name will give concatenate string of first and last name, __str__ will give string representation of an object.
Now back to console, we have to tell Django about changes. write following command in console
(myvenv) ~/ContactApp$ python manage.py makemigrations contact
Django prepared migration files for us that we have to apply to our database. Type following command to do that:
(myvenv) ~/ContactApp$ python manage.py migrate contact
Setup Admin
We have made our model Person. To add, edit and delete it we will use Django admin.
Go to admin.py file and add this:
from .models import Person
admin.site.register(Person)
Note: Don’t forget to save your files after editing them otherwise it will show previous output or error.
To see our Person model go to console type python manage.py runserver and then Go to your browser and type the address http://127.0.0.1:8000/admin/. You will see a login page.
To login you will need a username and password. For that we will have to create superuser. Go to the console and type following command:
#Press ctrl+c to stop the web server
(myvenv) ~/ContactApp$ python manage.py createsuperuser
Create your username and password and use this to login into admin page. Now you can edit, delete and add new contacts to database. Now go and add some contacts to your app.
Understanding URL and Views
First we will write urls for our contact app. When user type particular url in the browser, the following things happened:
- Django uses URLconf and look for variable urlpatterns which is list of urlpath instances.
- Django goes through each url pattern untill it founds the correct url which is being requested.
- Once the url matched, Django call the view is simple python function. In case or no url matches, Django shows error view.
Let’s write our first URL for our homepage. At homepage user will see the list of contacts.
We will create separate url file in our contact app to keep our work clean. Go to the contact folder and add new file name urls.py. Add following lines in contact/url.py file:
#contact/urls.pyfrom django.urls import path
from . import viewsapp_name = 'contact'urlpatterns = [
path('', views.contact_list, name='contact_list'),
]
I will explain this code but before that we need to include these urls to our mysite/urls.py file to actually make it work. For that we have to add some lines to our mysite/urls.py file. Our mysite/urls.py file look like this:
#mysite/urls.pyfrom django.contrib import admin
from django.urls import path
from django.conf.urls import includeurlpatterns = [
path('admin/', admin.site.urls),
path('', include('contact.urls', namespace='contact'))
]
Let’s understand what’s happening here, first we import path views from django.urls and views. In path we gave empty string as argument so if it gets empty string Django will call view function name contact_list.
Let’s write view function:
from django.shortcuts import render, get_object_or_404, redirect
from .models import Persondef contact_list(request):
persons = Person.objects.all().order_by('first_name')
return render(request, 'contact/contact_list.html', {'persons': persons})
First we import render, get_object_or_404 and redirect function, then we import our class from our models file.
Here contact_list is a function that takes request as argument, then we define persons variable which is list of objects and they are order by first_name. So if user send request to homepage then view function named “contact_list” will be called and it will return render function that will render template contact_list.html.
Templates
Templates are html file that will be saved in contact/templates/contact directory. So first create templates folder inside contact directory and then create contact folder inside templates folder. This is just a useful naming convention which makes your life easy when you are working on several apps in one project. it’s nice to keep your things organised.
Now create contact_list.html file and add these lines:
<!DOCTYPE html>
<html>
<head>
<title>Contact App</title>
</head>
<body>
<div>
{% for person in persons %}
<ul>
<li><a href="#">{{ person.full_name }}</a></li>
</ul>
{% endfor %}
</div>
</body>
</html>
This will show list of all the persons in our contact list on homepage. Now if you want to show detail of the person when user click on that person then you have to follow same process. Go to the urls.py file write the url, write view function and then template.
Forms
If you want to accept input from users then, you have to work with forms. For adding new contacts or edit them, there will be input form user side, so we will use forms here.
There are two type of requests when you are working with forms. One is GET request and other is POST request. Both request are used for different purpose, for example if you want to change the state of system like you want some change in database then it will be a POST request, but if it doesn’t change the state of the system then it will be a GET request.
When you add or edit contact in the database, it will be a post request and if you want information of a person then it will be a GET request.
I would suggest you to read about forms in documentation, here is the link.
Our html form structure will look like this:
<form method="post">
{% csrf_token %}
<div class="form-group">
{{ form.as_p }}
</div>
<input class="btn btn-primary" type="submit" value="Save" />
</form>
Before that we have to make new file called forms.py in our contact folder and add following lines:
from django import forms
from .models import Personclass PersonForm(forms.ModelForm):class Meta:
model = Person
fields = ('first_name', 'last_name', 'email', 'phone')
Now we want to write view function for our add and edit contacts but we will use same template for both function because it will use the same form. View function for add and edit contact will look like this:
def contact_new(request):
if request.method == 'POST':
form = PersonForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
form = PersonForm()
return render(request, 'contact/contact_edit.html', {'form': form})def contact_edit(request, pk):
person = get_object_or_404(Person, pk=pk)
if request.method == 'POST':
form = PersonForm(request.POST, instance=person)
if form.is_valid():
form.save()
return redirect('/person/' + str(person.pk))
else:
form = PersonForm(instance=person)
return render(request, 'contact/contact_edit.html', {'form': form})
Next we will write the view function for deleting the contact. Here, view function is getting the object which is to be deleted, then delete the contact from database and at last it is redirecting user to homepage.
def contact_delete(request, pk):
person = get_object_or_404(Person, pk=pk)
person.delete()
return redirect('/')
I’ve shared the link of my Github repository below. It has entire code of this project. I’ve used bootstrap to make the app looks nice. If you have face any problem during this project, you can see the code and move forward. Here is the link.
I learned many things while doing this project and using documentation to solve problems is one of them. In the beginning I was not comfortable in using documentation and I struggled a lot but later it became easy to search in documentation. It’s also important how you google your problem because you are just one search away from the solution.
My journey of learning Django is going good and I hope this post will also help you in your journey. Keep learning.