- Django projects
- Django apps
- View and Templates
- Integrate a database
- Model forms and CRUD operations
- Configure static files
- User authentication and authorization
- Credits
This document serves as a personal guide to assist Team Alpha while working with the Django framework. Throughout this guide, I have documented the steps necessary to setup, run and customize a Django application, and for each step I have included a short explaination to give you more context on how the process works.
First of all, we have to setup our development environment for our Django project. This can be done by following these steps on windows (for Mac it should be similar).
- create a folder named "dev" on your desktop and travel to it through the cmd
- run the command
pip install virtualenv
to install a package for declaring virtual environments
Now let's work with virtual environments
- Create your custom virtual environment with the command
virtualenv <your_env_name>
- Activate your environment with the command
your_env_name\Scripts\activate
. Now all packages installed are constricted to this virtual environment. - To deactivate the virtual environment run the command
your_env_name\Scripts\deactivate
Finally, let's install Django
- Within the virtual environment folder in the cmd, run the command
pip install django
- To create your django project, run the command
django-admin startproject <project_name>
- Finally, open the dev folder via your editor of choice, I used VScode
Throughout the development of your Django project, you will have manage the status of your local server. Here is how you can do it.
- Travel to the folder with the same name as your project name
- Run the command
python manage.py runserver
- You should be able to access your app on LOCALHOST or the port displayed in the cmd message
...http://127.0.0.1:8000/
- Paste that url in your browser and run it, you should see a django placeholder app (with a rocket animation)
- Stop the server with by hitting
CTRL+C
in the cmd
After successfully creating your Django project and opening it via your editor of choice, you should familiarise yourself with the file structure below.
- db.sqlite3 - a default sqlite database plugged into our app
- manage.py - used to run admin tasks, a control centre for the app
- Inside the project folder named <project_name>
- init.py - ensures python treats this directory as a module
- asgi.py - used for async development and actions
- settings.py - Django config file for our project
- urls.py - store all the routes configured on our app (/home, /login, /dashboard etc.)
- wsgi.py - used forwarding requests from web servers to a python web framework
A Django project is a collection of settings, configurations and apps and we can have one or multiple apps within a project. A Django app serves a unique purpose (microservices-like architecture, altough django projects are still monolithic) such as a blog app where users can record their thoughts.
To configure a Django app within your project, follow the steps below.
-
Run command
django-admin startapp <app_name>
-
Configure the app via the settings.py file in your project folder by adding the entry <your_app_name> into the INSTALLED_APPS list.
-
Migrate all files associated with the Django default INSTALLED_APPS to the app you just created by running the command
python manage.py migrate
Once you have successfully created your Django app, you should be able to recognise the file tree described below.
- admin.py - config file for our admin page, where we can carry out admin actions on our app
- models.py - where we define models, such as DB tables defined with python classes
- views.py - where we setup the business logic for our app
- init.py - ensures this folder is treated like a python module
- apps.py - information file about our application
- test.py - where we can carryout testing for our Django app - important!
Views are python functions or classes used to respond to a particular request.
Now that you have your Django project and app setup, let's look at the steps necessary to create a basic request-response cycle.
- Define a urls.py file in the crm folder or your project folder
Inside the newly created file:
-
Write the lines
import path from django.urls
andimport HttpResponse from django.http
-
Inside the views.py file define a View in the urls.py file, via a function with name of "route", such as
def register(request)
which returns an HttpResponse message. -
Create a urlpatterns list to encapsulate all urls used in the application
-
Enter the line
path(routename, view_to_return)
in urls.py file, i.e.urlpatterns = [path('route_name', 'view_name')]
-
Within the same file run the line
from django.urls import include
link the app's urls.py to the projects urls.py -
Within the
urlpatterns
list, add a path with empty route and view, such aspath('', include('projectname.urls')
-
To setup the app's views.py and urls.py
- Run the import
from . import views
in the urls.py file - Add the following path to urlpatterns list -
path('register', views.register),
- Run the import
-
To configure the default page for our app
- In urls.py, define an empty
path('', views.home_view)
- In views.py define a function or View for the home page
- In urls.py, define an empty
Templates are structured files written using Django templating language (DTL) and allow different webpages to share the same structure, but with customizable content
To configure templates in your app:
- Travel to you app folder, create a "templates" folder and within that create a folder called "app_name" to avoid namespace issues
- Within the last created folder, create a home.html template file and add some basic markup
- In the views.py file, call the render function within the View/function for the homepage -
render(request, 'crm/index.html')
, now the template is rendered when user hits that route
Template inheritance allows you to define components in a parent template that children template can use, without redefining it themselves Elements are components of a template which can be reused - such as button, or a headers
Template inheritance can be setup with the following steps
- Create a base template in templates/app_name - i.e. base.html
- Define a unique space for this template with
{% block content %} custom data here {% endblock %}
- everything outside this block will be inherited by child templates - Link this parent template by going to any other template and doing the following
- Add this line at the very top of the template
{% extends "crm/base.html" %}
- Wrap the content you want to display on a child template with the
{% block content %} custom data here {% endblock %}
operator
- Add this line at the very top of the template
- DTL is a mini language to write logic within our templates and render data through your templates, using data passed to the template via the views in views.py for example
- You can pass data to your template by
- Passing a dictionary as the 3rd parameter of the render function for the template you are trying to populate
- Within the template, declare
{{ key_name }}
anywhere you wanna display the data associated with the key_name key in the dictionary you passed to the template - You can enforce conditional rendering with the following syntax
{% if condition %} content A {% else %} content B {% endif %}
- Similarly, you can loop over data using a for-loop like syntax
{% for n in list_to_iterate %} <p> {{ n }} </p> {% endfor %}
- Django apps come with a built-in SQLite relational database. Throughout this section, we will go through the steps to carry out CRUD operations on this database.
- The Django Admin Panel can be accessed by running your server and visiting the /admin route. The DAP allows you to manage the underlying SQLite database that comes with your app. To access the DAP, you will need login credentials, which can be accessed with the following steps:
- Run the command
python manage.py createsuperuser
- Fill in the prompts as you go along, careful to type matching passwords as they won't be displayed on screen.
- Re-start your server and login.
- Django models are a feature used by Django to create tables along with their fields. Think of these as classes which represent database tables.
To create a model in Django, use the following steps:
- Head over to models.py and declare a model with the following syntax
class Name(models.Model): your_fields
- make sure to consult the different datatypes allowed by Django here - Migrate your created model by running the command
python manage.py makemigrations
in your cmd - Push the model to your database by running the command
python manage.py migrate
After you declared your Django model, we got to register it on our Django app using the DAP. Follow these steps.
- Open the admin.py file
- Run the line
from .models import Name
- Run the line
admin.site.register(Name)
to register the model on the DAP - Login into the DAP, and you should see the Model registered as Name(s)
Now we have a look at how we can link multiple models using the concept of foreign keys.
- Open the models.py and create a second model which you will link to an existing one.
- Write the following line as an attribute to the newly created model
model_linked_name = modelsForeignKey(model_linked_name, on_delete=models.CASCADE)
- models.CASCADE ensures that all connections to a model are deleted once that particular instance is deleted. - Migrate and register this model as done with the previous one
- ORM (Object relational mapping) is used to perform Django database queries. Follow the steps below to run a simple query to the Django SQLite database.
- In the views.py file, run the following line
from .models import Model_name
- Inside the function/view you want to execute the query in, run the following line
query_data_all = Model_name.objects.all()
- this example fetches all the instances of the Model_name class - Pass the query results to your template via a context dictionary and render it onto your view.
- NOTE - please google to find the appropriate query method to complete your task.
- A Model Form is a class used to convert a Django model into a Django form. This form can then be rendered on the front-end to collect user input.
- To create a Model Form follow these steps:
- Inside your app forlder, create the forms.py file.
- Run the line
from django.forms import ModelForm
, this class is the 'parent' class which every form you create will inherit from. - Run the line
from .models import <model>
- model comes from models.py - Define the model form class with the following syntax
class <model>Form(ModelForm): class Meta: model = <model> fields = '__all__'
- the Meta class allows us to specify which model and which model attributes the Form will model. - Define a template for the form we just defined :
- Inside templates/<app_name> create a .html file and populate it accordingly
- Inside the views.py file, we must setup the View to be rendered (see above for a refresher) and then connect this View inside the urls.py file.
- Now we must create the View to be rendered:
- Run the line
from .forms import <model>Form
inside the views.py file - Inside the last View function you defined, instantiate the class you just imported
- create a context dictionary
{ "form" : instance_created }
and returnrender(...)
as done with other views. - Finally, go to the last .html file you created and populate it to display the form model you passed in as a context dictionary. Here is an example below :
<form method="POST" autocomplete="off" enctype="multipart/form-data" {% csrf_token %} {{ form.as_p }} <input type="submit" value="Submit"> </form>
- as_p helps with formatting and labels of attribute names
- C - CREATE
- To create a new model instance, follow the steps outlined below.
- Go to the views.py file, and define a view/function named
def create_<model_instance>(request): pass
if not there already - Import the
redirect
method from thedjango.shortcuts
package - Inside the method defined in step 1 :
- Check what the form action is with
if request.method == "POST"
- If that's the case, reassign the form with
form = TaskForm(request.POST)
- Then we check if the form data is valid with
if form.is_valid():
- If the data is valid we save the object and redirect the user to the input page which triggered the CREATE action -
form.save() return redirect('task')
- if the request method is not POST, simply
return render(...)
- R - READ
- To read a model instance from the database using an instance id for example, follow the steps outlined below.
- If you would like to get all instances from the database, use the
.all()
method to query, otherwise use the.get(id=...)
method to fetch an object based on its creation id.
- U - UPDATE
- To update an existing model instance, follow the steps outlined below.
- create a new View called
update-<model>.html
and populate it with thebase.html
components and a title to distinguish it. - Set up your view in
views.py
and add the url to urlpatterns inurls.py
.
-
Note that to make a url dynamic we use the following format
path('url/<str:pk>',...),
-
Similarly, the view you just declared takes in request and pk as parameters.
-
Inside the view you defined, follow a similar process to the one in the CREATE section above:
- fetch the object from the database based on pk input -
obj = <Model>.objects.get(id=pk)
- define a form object
form = <Model>Form(instance=obj)
- check if the method is POST, if it is
form = <Model>Form(request.post, instance=task)
- check if the form data is valid, if it is then save and redirect.
- Inline with the POST if statement, define a context dictionary with the form defined and return
render(request, view_name, context)
- fetch the object from the database based on pk input -
-
In order to allow users to access the edit page of a particular object, we can use a link tag on the frontend which directs the user to the page for that specific object, for example
<a href = "{% url 'update-task' task.id %}"> Update task </a>
is displayed on theall-tasks.html
page using a for loop. -
Finally, update the data loaded in the field and it should update it.
- D - DELETE
- create a template called
delete-<model>.html
, then add connectbase.html
and add the following form inside<form method="POST" autocomplete="off" enctype="multipart/form-data" {% csrf_token %} <input type="submit" value="Delete"> </form>
- set up functionality in views.py with a dynamic-url view and connect it to urls.py
- to delete the task given the
pk
id, simply check if the form method is POST and then fetch the object with<Model>.objects.get(id=pk)
and then delete it with<obj>.delete()
. - redirect the user after operation
- Static files such as css and JS files remain unchanged during a website's operation. They are directly sent to the user's web browser without being modified.
- To configure any static file, follow the process below.
- create a
static
folder in the project root directory - in your app's settings.py files, type the following after the STATIC_URL variable -
STATICFILES_DIRS = [ BASE_DIR / 'static' ]
to let django know where to find our static files. - create
css
andjs
subfolders in thestatic
folder, to house our static css and Javascript files. - create a
style.css
file in the css folder, and write some code for testing purposes. - to connect your static files to the frontend, write
{% load static %}
at the very top of your app'sbase.html
file. - To connect your css static files, define a
head
tag in yourbase.html
and within that, the following tag<link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}">
- Similarly, create an
app.js
file in static/js and use ascript
tag to connect the static javascript files<script src="{% static 'js/app.js' %}"></script>
- User Authentication is concerned with ensuring that login/signup procedures work as intended for registering and returning app users. User Authrorization is concered with what a logged in user can and cannot do on the application. To setup user auth in your app, follow the steps below.
- Inside forms.py import the following
from django.contrib.auth.forms import UserCreationForm
, followed by the default User model importfrom django.contrib.auth.models import User
- Define a new class
CreateUserForm(UserCreationForm):
and within this class define theMeta
class, where you can cherrypick the fields which will make up the User objects. - Inside the views.py file, import the class you just defined, then within the
register
view
- Create a
form
variable to instantiate the class imported. - Check if the form method is POST and the form data is valid, in which case save the form and return an HttpResponse with a suitable message.
- Create the context dictionary
context = { 'RegistrationForm' : form }
and pass it to therender(...)
method. - Inside the
register.html
template, define the basic form syntax to send POST requests in django - Within the form, under the csrf token, type
{{ RegistrationForm.as_p }}
to display the registration form.
- To setup user authentication, follow the steps below. We assume you have completed all the above steps up to this point.
- Create a login.html and a dashboard.html file in the templates/crm folder
- Populate the login.html template with the same contents as register.html and remove all unrelated code, then populate the dashboard.html page with basic text
- Next, we configure the views.py and urls.py files in the same way done before.
- In the forms.py file, import
AuthenticationForm
fromdjango.contrib.auth.forms
andfrom django import forms
andfrom django.forms.widgets import PasswordInput, TextInput
- Still in forms.py, create a LoginForm class which inherits the
AuthenticationForm
class, as set the its attributes as follows :
username = forms.CharField(widget=TextInput())
password = forms.CharField(widget=PasswordInput())
- Inside views.py import the LoginForm model class just declared and instantiate it within the login view declared before.
- check for the POST method and if that's the case assign
form = LoginForm(request.POST, data=request.POST)
. - run the following at the top of views.py -
from django.contrib.auth.models import auth
andfrom django.contrib.auth import authenticate, login, logout
- Now we check if the form input matches a record in the data, and either login the user or prompt them to try again. An example of the full login view/function is provided.
def login(request): form = LoginForm() if request.method == "POST": form = LoginForm(request.POST, data=request.POST) if form.is_valid(): username = request.POST.get('username') password = request.POST.get('password') user = authenticate( request, username=username, password=password ) if user is not None: auth.login(request, user) return redirect('dashboard') context = { 'LoginForm' : form } return render(request, 'crm/login.html', context)
- Finally, we populate the login.html file with
{{ LoginForm.as_p }}
and add a login url in the base.html file. - Modify the register view so that the user is redirected to the login url when they register a new account
Now we look at how to setup user logout and protecting the Views on our app with authorization.
- create a logout view in views.py and configure it in urls.py
- Inside this view, logout the user with
auth.logout(request)
and redirect them where best suited. - Add a logout link in dashboard.html
- We can protect views in our app by importing
from django.contrib.auth.decorators import login_required
- a decorator function which takes in a redirec parameter in cas of failed auth. For example@login_required(login_url='login')
The material for this document has been gathered while studying the course Python Django - Ultimate beginners course on Udemy, authored by Arno Pretorius.