Table of Content
Preparing environnement
mkdir project_name && cd $_ |
Create project folder and navigate to it
|
python -m venv env_name |
Create venv for the project
|
source env_name\bin\activate |
Activate environnement (Replace "bin" by "Scripts" in Windows)
|
pip install django |
Install Django (and others dependencies if needed)
|
pip freeze > requirements.txt |
Create requirements file
|
pip install -r requirements.txt |
Install all required files based on your pip freeze command
|
git init |
Version control initialisation, be sure to create appropriate gitignore
|
Create project
django-admin startproject mysite (or I like to call it config) |
This will create a mysite directory in your current directory the manage.py file
|
python manage.py runserver |
You can check that everything went fine
|
Database Setup
Open up
mysite/settings.py |
It’s a normal Python module with module-level variables representing Django settings.
|
ENGINE – 'django.db.backends.sqlite3' , 'django.db.backends.postgresql' , 'django.db.backends.mysql' , or 'django.db.backends.oracle' |
If you wish to use another database, install the appropriate database bindings and change the following keys in the DATABASES 'default' item to match your database connection settings
|
NAME – The name of your database. If you’re using SQLite, the database will be a file on your computer; in that case, NAME should be the full absolute path, including filename, of that file. |
The default value,
BASE_DIR / 'db.sqlite3' , will store the file in your project directory. |
If you are not using SQLite as your database, additional settings such as
USER , PASSWORD , and HOST must be added. |
For more details, see the reference documentation for DATABASES.
|
Creating an app
python manage.py startapp app_name |
Create an app_name directory and all default file/folder inside
|
INSTALLED_APPS = [ |
Apps are "plugable", that will "plug in" the app into the project
|
urlpatterns = [ |
Into urls.py from project folder, inculde app urls to project
|
Creating models
Class ModelName(models.Model) |
Create your class in the app_name/models.py file
|
title = models.CharField(max_length=100) |
Create your fields
|
def __str__(self): |
It’s important to add __str__() methods to your models, because objects’ representations are used throughout Django’s automatically-generated admin.
|
Database editing
python manage.py makemigrations (app_name) |
By running makemigrations, you’re telling Django that you’ve made some changes to your models
|
python manage.py sqlmigrate #identifier |
See what SQL that migration would run.
|
python manage.py check |
This checks for any problems in your project without making migrations
|
python manage.py migrate |
Create those model tables in your database
|
python manage.py shell |
Hop into the interactive Python shell and play around with the free API Django gives you
|
Administration
python manage.py createsuperuser |
Create a user who can login to the admin site
|
admin.site.register(ModelName) |
Into app_name/admin.py, add the model to administration site
|
Open a web browser and go to “/admin/” on your local domain
|
Management
mkdir app_name/management app_name/management/commands && cd $_ |
Create required folders
|
touch your_command_name.py |
Create a python file with your command name
|
from django.core.management.base import BaseCommand |
Edit your new python file, start with import
|
class Command(BaseCommand): |
Create the Command class that will handle your command
|
python manage.py my_custom_command |
And this is how you execute your custom command
|
Django lets you create your customs CLI commands
Write your first view
from django.http import HttpResponse |
Open the file app_name/views.py and put the following Python code in it.
This is the simplest view possible. |
from django.urls import path |
In the app_name/urls.py file include the following code.
|
View with argument
def detail(request, question_id): |
Exemple of view with an arugment
|
urlpatterns = [ |
See how we pass argument in path
|
{% url 'app_name:view_name' question_id %} |
We can pass attribute from template this way
|
View with Template
app_name/templates/app_name/index.html |
This is the folder path to follow for template
|
context = {'key': value} |
Pass values from view to template
|
return render(request, 'app_name/index.html', context) |
Exemple of use of render shortcut
|
{% Code %} |
Edit template with those. Full list here
|
<title>Page Title</title> |
you can put this on top of your html template to define page title
|
Add some static files
'django.contrib.staticfiles' |
Be sure to have this in your INSTALLED_APPS
|
STATIC_URL = 'static/' |
The given exemples are for this config
|
mkdir app_name/static app_name/static/app_name |
Create static folder associated with your app
|
{% load static %} |
Put this on top of your template
|
<link rel="stylesheet" type="text/css" href="{% static 'app_name/style.css' %}"> |
Exemple of use of static.
|
Raising 404
raise Http404("Question does not exist") |
in a try / except statement
|
question = get_object_or_404(Question, pk=question_id) |
A shortcut
|
Forms
app_name/forms.py |
Create your form classes here
|
from django import forms |
Import django's forms module
|
from .models import YourModel |
import models you need to work with
|
class ExempleForm(forms.Form): |
For very simple forms, we can use simple Form class
|
class ExempleForm(forms.ModelForm): |
A ModelForm maps a model class’s fields to HTML form <input> elements via a Form. Widget is optional. Use it to override default widget
|
TextInput, EmailInput, PasswordInput, DateInput, Textarea |
Most common widget list
|
if request.method != "POST": |
Create a blank form if no data submitted
|
form = ExempleForm(data=request.POST) |
The form object contain's the informations submitted by the user
|
is form.isvalid() |
Form validation. Always use redirect function
|
{% csrf_token %} |
Template tag to prevent "cross-site request forgery" attack
|
Render Form In Template
{{ form.as_p }} |
The most simple way to render the form, but usualy it's ugly
|
{{ field|placeholder:field.label }} |
The | is a filter, and here for placeholder, it's a custom one. See next section to see how to create it
|
{% for field in form %} |
You can extract each fields with a for loop.
Or by explicitly specifying the field |
Custom template tags and filters
app_name\templatetags\__init__.py |
Create this folder and this file. Leave it blank
|
app_name\templatetags\filter_name.py |
Create a python file with the name of the filter
|
{% load filter_name %} |
Add this on top of your template
|
from django import template |
To be a valid tag library, the module must contain a module-level variable named register
that is a template.Library instance |
@register.filter(name='cut') |
Here is an exemple of filter definition.
See the decorator? It registers your filter with your Library instance. You need to restart server for this to take effects |
Here is a link of how to make a placeholder custom template tag
|
Setting Up User Accounts
Create a "users" app
|
Don't forget to add app to settings.py and include the URLs from users.
|
app_name = "users" |
Inside app_name/urls.py (create it if inexistent),
this code includes some default authentification URLs that Django has defined. |
{% if form.error %} |
Basic login.html template
Save it at save template as users/templates/registration/login.html We can access to it by using <a href="{% url 'users:login' %}">Log in</a> |
{% if user.is_authenticated %} |
Check if user is logged in
|
{% url "users:logout" %} |
Link to logout page, and log out the user
save template as users/templates/registration/logged_out.html |
path("register/", views.register, name="register"), |
Inside app_name/urls.py, add path to register
|
from django.shortcuts import render, redirect |
We write our own register() view inside users/views.py
For that we use UserCreationForm, a django building model. If method is not post, we render a blank form Else, is the form pass the validity check, an user is created We just have to create a registration.html template in same folder as the login and logged_out |
Allow Users to Own Their Data
... |
Restrict access with @login_required decorator
If user is not logged in, they will be redirect to the login page To make this work, you need to modify settings.py so Django knows where to find the login page Add the following at the very end # My settings |
... |
Add this field to your models to connect data to certain users
When migrating, you will be prompt to select a default value |
user_data = ExempleModel.objects.filter(owner=request.user) |
Use this kind of code in your views to filter data of a specific user
request.user only exist when user is logged in |
... |
Make sure the data belongs to the current user
If not the case, we raise a 404 |
new_data = form.save(commit=false) |
Don't forget to associate user to your data in corresponding views
The "commit=false" attribute let us do that |
Paginator
from django.core.paginator import Paginator |
In app_name/views.py, import Paginator
|
exemple_list = Exemple.objects.all() |
In your class view, Get a list of data
|
paginator = Paginator(exemple_list, 5) # Show 5 items per page. |
Set appropriate pagination
|
page_number = request.GET.get('page') |
Get actual page number
|
page_obj = paginator.get_page(page_number) |
Create your Page Object, and put it in the context
|
{% for item in page_obj %} |
The Page Object acts now like your list of data
|
<div class="pagination"> |
An exemple of what to put on the bottom of your page
to navigate through Page Objects |
Deploy to Heroku
Make a Heroku account
|
|
https://devcenter.heroku.com:articles/heroku-cli/
|
Install Heroku CLI
|
pip install psycog2 pip install django-heroku pip install gunicorn |
install these packages
|
pip freeze > requirements.txt |
updtate requirements.txt
|
# Heroku settings. import django_heroku django_heroku.settings(locals(), staticfiles=False) if os.environ.get('DEBUG') == "TRUE": DEBUG = True elif os.environ.get('DEBUG') == "FALSE": DEBUG = False |
At the very end of settings.py, make an Heroku ettings section
import django_heroku and tell django to apply django heroku settings The staticfiles to false is not a viable option in production, check whitenoise for that IMO |