Django is an advanced Python Web framework that supports rapid development and a clean and useful design. This article is a review of the Official Django documentation and takes a look at some of the things you need to know to get started:
- Create projects using Django.
- Path matching, how a request path is mapped to the corresponding callback function.
- Model, for manipulating databases in an object-oriented manner.
- View, which receives a Web request and returns a Web response.
Create projects using Django
1. Preparation
Install Python and use the MySQL database.
See the previous articles getting Started with Python and getting Started with MySQL in this section. I won’t repeat it here.
The corresponding Python version that the different Django versions can use
Database installation (including other databases except MySQL)
2. Install Django
Create a virtual environment and switch to it to make sure Django is installed in that virtual environment.
mkvirtualenv demo_env
Copy the code
Install the official release:
pip3 install Django
Copy the code
To see the downloaded version of Django, use the following command:
python3 -m django --version
Copy the code
(Download Django 3.2.7 here.)
3. Create projects
CD to the location where you want to save the code, execute the following command:
django-admin startproject demo
Copy the code
It automatically generates some code for your Django project.
Django-admin is a named line application for Django administration tasks.
Manage. py is a file created automatically for each Django project. Like Django-admin, manage.py also sets the DJANGO_SETTINGS_MODULE environment variable, This environment variable points to your project’s settings.py file and tells Django which Settings you need to use.
Django-admin and manage.py, Settings.
4. Configure the database
(1) Install mysqlClient API driver:
pip3 install mysqlclient
Copy the code
(2) Create a database named Demo in the database service
create database demo;
Copy the code
1. Demo.settings. py DATABASES:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql'.'NAME': 'demo'.'USER': 'root'.'PASSWORD': 'secret'.'HOST': '127.0.0.1'.'PORT': '3306'}}Copy the code
Database Setup
5. Run the development server
CD demo to create the project directory, execute the following command to run the development server:
python3 manage.py runserver
Copy the code
Open http://127.0.0.1:8000/ in your browser to see a screen.
6. Create the App
We just created a project called Demo by executing Django-admin startProject demo. A project may contain multiple applications (apps), and an application may be in multiple projects.
Execute in the manage.py file path:
python3 manage.py startapp todo
Copy the code
To create an application called Todo. After the demo project is created, add todo application information to INSTALLED_APPS in the Demo. Settings file to indicate that the Demo project contains the Todo application:
INSTALLED_APPS = [
...
'todo.apps.TodoConfig',]Copy the code
The toDO application will implement the following interfaces:
(1) Create/update a to-do list
(2) Obtain to-do list details
(3) Get the to-do list
Path matching
So far, the project’s file directory looks like this:
. ├ ─ ─ the sqlite3 ├ ─ ─ demo │ ├ ─ ─ just set py │ ├ ─ ─ __pycache__ │ │ ├ ─ ─ just set retaining - 37. Pyc │ │ ├ ─ ─ Settings. Retaining to 37. Pyc │ │ ├ ─ ─ urls. Retaining - 37. Pyc │ │ └ ─ ─ wsgi. Retaining - 37. Pyc │ ├ ─ ─ asgi. Py │ ├ ─ ─ Settings. Py │ ├ ─ ─ Urls. Py │ └ ─ ─ wsgi. Py ├ ─ ─ the manage. Py └ ─ ─ todo ├ ─ ─ just set py ├ ─ ─ admin. Py ├ ─ ─ apps. Py ├ ─ ─ migrations │ └ ─ ─ just set py ├── ├─ ├─ exercisesCopy the code
The demo/settings.py file contains the Settings for the project, and the settings.py file sets the ROOT_URLCONF:
ROOT_URLCONF = 'demo.urls'
Copy the code
When an interface to a site is requested, Django finds a variable called URlPatterns in a module set by ROOT_URLCONF and converts the patterns in that order. This means finding the Python code (either a Python function or a class-based View) to execute for the interface of a pattern.
1. Url without parameters
Add the following contents to the views folder:
from django.http import HttpResponse
def temp(request) :
return HttpResponse(' Temporary code to demonstrate URL matching
')
Copy the code
This is a function that simply returns an HttpResponse object. In the list of urlpatterns in demo.urls, add the following:
from django.urls import path
from todo import views as todo_views
urlpatterns = [
path('temp/', todo_views.temp),
]
Copy the code
In the browser to http://127.0.0.1:8000/temp/, you can see the returned HTML entities.
Todo_views.temp (request) is called when an interface such as temp/ is matched. Request is an HttpRequest object that contains information about the request.
2. Url containing parameters
Modify the temp function as follows:
Def temp(request, **kwargs): return HttpResponse(f'<h1> <p> {STR (kwargs)}</p>')Copy the code
Modify the urlpatterns in demo.urls as follows:
from django.urls import path
from todo import views as todo_views
urlpatterns = [
path('temp/<int:temp_id>/', todo_views.temp),
]
Copy the code
In the browser to http://127.0.0.1:8000/temp/123/, we can see:
In
, int is the converter type, indicating that the matching part is an integer. The converters that come with Django are STR (the default type when no converters are set), int, slug, UUID, and PATH. You can also customize the converter.
3. Name the URL pattern
Using the name parameter in path() or re_path() can name URL patterns so that reverse() can be easily used to retrieve urls during unit testing. Such as:
urlpatterns = [
path('temp/<int:temp_id>/', todo_views.temp, name='index'),]Copy the code
During the unit test, use the following method to test whether the interface returns the status code 200.
from django.urls import reverse
response = client.get(reverse('index'))
self.assertEqual(response.status_code, 200)
Copy the code
4. Make structural adjustments
So far, the URL pattern for our Todo application is written in the project’s urls file. If there are multiple applications, it is not clear that they are all in the same file. Create a new urls.py file in the todo folder and add the following:
from django.urls import path
from . import views
urlpatterns = [
path('temp/<int:temp_id>/', views.temp, name='index'),]Copy the code
Modify the demo project’s urls file as follows:
from django.urls import path, include
urlpatterns = [
path('todo/',include('todo.urls')),]Copy the code
In the browser to http://127.0.0.1:8000/todo/temp/123/ can see figure – 1 the same page.
5.URL name namespace
Path (‘temp/
/’, views.temp, name=’index’); Either use another-index names to avoid collisions, or use namespaces:
. app_name ='todo'
urlpatterns = [
path('temp/<int:temp_id>/', views.temp, name='index'),]Copy the code
Use self. Client. Get (reverse (‘ todo: index)).
Official website details: URL Dispatcher
Model (Model)
The model contains the basic fields and behavior of the stored data, and typically, one model corresponds to one database table.
1. Create the Model
Before you create the model, think about the table structure of the database.
from django.db import models
class Todo(models.Model) :
content = models.CharField('To-do List', max_length=200)
remark = models.CharField('note', max_length=500)
PRIORITY_CHOICES = [
(1.'Low priority'),
(2.'Low to medium priority'),
(3.'Medium priority'),
(4.'Medium high priority'),
(5.'High priority'),
]
priority = models.IntegerField('Priority', choices=PRIORITY_CHOICES, default=1)
completed = models.BooleanField('Completed or not', default=False)
created_time = models.DateTimeField('Creation time', auto_now_add=True)
modified_time = models.DateTimeField('Last update time', auto_now=True)
Copy the code
Field type.
In Choices, the first value of the tuple is the value that is actually assigned to a field, and the second value is something that is easy to read.
(1) Execute the following command to store changes to model as migration.
python3 manage.py makemigrations todo
Copy the code
You will notice that there is a 0001_initial.py file under the migrations folder where todo is applied, which is the stored migration file.
└ ─ ─ todo ├ ─ ─ just set p y... ├ ─ ─ admin. Py ├ ─ ─ apps. Py ├ ─ ─ migrations │ ├ ─ ─ 0001 _initial. Py │ ├ ─ ─ just set py │ └ ─ ─ __pycache__ ├ ─ ─ models. PyCopy the code
(2) Execute the following instructions:
python3 manage.py sqlmigrate todo 0001
Copy the code
Query the SQL statement corresponding to the change to model (0001_initial.py SQL corresponding to the migration file) :
python3 manage.py sqlmigrate todo 0001
--
-- Create model Todo
--
CREATE TABLE `todo_todo` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, `content` varchar(200) NOT NULL, `remark` varchar(500) NOT NULL, `priority` integer NOT NULL, `completed` bool NOT NULL, `created_time` datetime(6) NOT NULL, `modified_time` datetime(6) NOT NULL);
Copy the code
You can see that in the models.py file we did not declare the ID field, but the corresponding SQL created the ID field as a self-increment primary key. You can also set a field as the primary key yourself by setting primary_key=True.
As you can see from CREATE TABLE todo_todo, Django combines the lower case of the application name todo with the model name as the TABLE name. To customize the corresponding TABLE name, use the db_TABLE attribute in the Meta option:
class Todo(models.Model) :
content = models.CharField('To-do List', max_length=200)... modified_time = models.DateTimeField('Last update time', auto_now=True)
class Meta:
db_table = 'todo'
Copy the code
Run PYTHon3 Manage. py MakemigBar todo, and store the new changes as 0002_ALTER_todo_table. Python3 manage.py sqlmigrate todo 0002
--
-- Rename table for todo to todo
--
RENAME TABLE `todo_todo` TO `todo`;
Copy the code
(3) Execute migrate to the actual database:
python3 manage.py migrate
Copy the code
If you look in the database, you will see that a new TODO table has been created.
2. Add data
Once the data model is created, Django automatically assigns a database abstraction API for adding, deleting, and reviewing data. A model class represents a database table, and a model class instance represents a record in a database table.
Use the python3 manage.py shell command to call up the Python command line and execute the code on the Python command line to see the effect.
(1) You can save the data to the database by instantiating a model class and calling save() :
>>> from todo.models import Todo
>>> todo = Todo(content='The first thing I do is write.', remark='Writing makes people happy', priority=3)
>>> todo.save()
Copy the code
Select * from MySQL;
use demo;
select * from todo limit 20;
Copy the code
It has been found that one piece of data has appeared:
(2) Use the objects create() method.
To get objects from the database, one Manager of the model class is used to construct a QuerySet, which represents a collection of objects from the database. Every model has at least one Manager, and by default, it is called Objects.
>>> from todo.models import Todo
>>> Todo.objects.create(content='The second thing I do is play video games', remark='Playing games also makes you happy', priority=3)
<Todo: Todo object (2) >Copy the code
Select * from todo limit 20; Find the data and get:
3. Find the data
(1) Use all() to find all data:
>>> Todo.objects.all()
<QuerySet [<Todo: Todo object (1)>, <Todo: Todo object (2) > >]Copy the code
Here we find the print-out less intuitive, add a __str__ method to the model class:
class Todo(models.Model) :
content = models.CharField('To-do List', max_length=200)...def __str__(self) :
return self.content
Copy the code
Ctrl + D to exit the Python command line and run python3 manage.py shell to reset and re-execute the code:
>>> from todo.models import Todo
>>> Todo.objects.all() <QuerySet [<Todo: the first thing is to write >, <Todo: the second thing is to play games >]>Copy the code
(2) Use filter to return the result set containing objects matching query parameters:
>>> Todo.objects.filter(created_time__year=2021) <QuerySet [<Todo: the first thing is to write >, <Todo: the second thing is to play games >]>Copy the code
Find data created in 2021.
Exclude returns a result set that does not contain the given query parameters:
>>> Todo.objects.exclude(created_time__year=2021)
<QuerySet []>
Copy the code
Find data that was not created in 2021.
(4) Use get() to return the only object matched.
>>> Todo.objects.get(pk=1Todo: the first thing Todo is to write.Copy the code
Find data with primary key 1.
(5) Limit the query result set
>>> Todo.objects.all(to)1:5] <QuerySet [<Todo: the second thing is to play games >]>Copy the code
Equal to OFFSET 1 LIMIT 5, returns the first 5 entries starting at OFFSET 1.
Official website details: field search
4. Update data
(1) Update an object using save()
>>> todo = Todo.objects.get(pk=1)
>>> todo.completed = True
>>> todo.save()
Copy the code
(2) Update one or more objects using update()
Update is a QuerySet method, only the result set has an update method, because get() gets an object, so there is no update method.
>>> Todo.objects.filter(pk=2).update(completed=True)
1
Copy the code
Update returns the number of rows that match.
5. Delete data
Delete all rows of a QuerySet using delete(), which returns the number of deleted rows and a dictionary containing information about the number of each object type deleted.
Todo.objects.filter(pk=2).delete()
(1, {'todo.Todo': 1})
Copy the code
Details: Field types, Model instances, QuerySet APIS, queries, data models
View (View)
A view is a Python function that receives a Web request and returns a Web response. The response could be the HTML content of a Web page, a redirect, a 404 error, an XML document, an image, and so on. For details on requests and responses, see the documentation: Request and Response Objects.
You can use templates to dynamically generate HTML as a response, but because of the separation of the front and back ends, templates are rarely used, so in this exercise you just implement the interface and observe it in Postman, not interface interaction.
The View function
We have written the following code in the previous exercise:
from django.http import HttpResponse
def temp(request, **kwargs) :
return HttpResponse(F '<h1> shows temporary code for URL matching </h1><p> passed parameters{str(kwargs)}</p>')
Copy the code
The URL pattern looks like this:
urlpatterns = [
path('temp/<int:temp_id>/', views.temp, name='index'),]Copy the code
Views. temp is the function to be called after the URL is matched.
No matter what method of request (GET, POST, PUT…) /
/;}
def temp(request, **kwargs) :
if request.method == 'GET':
# GET request processing
elif request.method == 'POST':
# POST request processing
Copy the code
We can use a class-based view, which organizes the different methods rather than manually writing if… Elif.
Class-based View
All class-based views inherit from views.
class Temp(View) :
def get(self, request, **kwargs) :
return HttpResponse(F: '< p > get request,{str(kwargs)}</p>')
def post(self, request, **kwargs) :
return HttpResponse(F 'post request,{str(kwargs)}')
Copy the code
CSRF cookie not set: HttpResponse cookie not set Use the CSRF_Exempt decorator to set the interface to not be protected by CSRF (just to simplify the exercise).
Change the contents of todo.urls to:
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .views import Temp
app_name = 'todo'
urlpatterns = [
path('temp/<int:temp_id>/', csrf_exempt(Temp.as_view()), name='index'),]Copy the code
Class-based views contain an as_view() method that returns the callback function to be called when a URL is matched.
The Postman with a GET request to http://127.0.0.1:8000/todo/temp/123/, we GET:
Use a POST request to http://127.0.0.1:8000/todo/temp/123/, we get:
Implement the interface to the manifest list
Implement the following interface with class-based View:
(1) Create/update a to-do list
(2) Obtain to-do list details
(3) Get the to-do list
from django.core import serializers
from django.http import HttpResponse, JsonResponse, QueryDict
from django.views import View
from .models import Todo
import json
class TodoView(View) :
List POST: Creates a list; Put: Updates the list; Get: Get list details.
def format_request_data(self, request_data) :
Collate the data passed by the request.
todo_data = {}
todo_data['content'] = request_data.get('content'.' ')
todo_data['remark'] = request_data.get('remark'.' ')
todo_data['priority'] = int(request_data.get('priority'.1))
return todo_data
def get(self, request, pk) :
try:
todo = Todo.objects.filter(pk=pk)
todo_list_str = serializers.serialize('json', todo) Serialize QuerySet to JSON data
todo_list = json.loads(todo_list_str)
todo_data = todo_list[0] ['fields']
return JsonResponse(todo_data, status=200)
except Exception as e:
return HttpResponse(F 'failed to get the list,{e.__str__()}', status=400)
def post(self, request) :
try:
data = QueryDict(request.body)
todo_data = self.format_request_data(data)
todo = Todo(**todo_data)
todo.save()
return HttpResponse('List created successfully', status=201)
except Exception as e:
return HttpResponse(F 'failed to create the list,{e.__str__()}', status=400)
def put(self, request, pk) :
try:
data = QueryDict(request.body)
todo_data = self.format_request_data(data)
Todo.objects.filter(pk=pk).update(**todo_data)
return HttpResponse('Update list succeeded', status=200)
except Exception as e:
return HttpResponse(F 'failed to update the list,{e.__str__()}', status=400)
class TodoListView(View) :
List list get: Get list list
def get(self, request) :
try:
todo_list = Todo.objects.all()
todo_list_str = serializers.serialize('json', todo_list) Serialize QuerySet to JSON data
todo_list_data = json.loads(todo_list_str)
res_data = []
for todo in todo_list_data:
todo_data = { **todo.get('fields') }
todo_data.update(id=todo.get('pk'))
res_data.append(todo_data)
return JsonResponse(res_data, safe=False, status=200) # Set safe to False to return non-dictionary data
except Exception as e:
return HttpResponse(F 'failed to get the list,{e.__str__()}', status=400)
Copy the code
Modify the todo/urls.py file as follows:
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .views import TodoView, TodoListView
app_name = 'todo'
urlpatterns = [
path('create/', csrf_exempt(TodoView.as_view()), name='create'),
path('edit/<int:pk>/', csrf_exempt(TodoView.as_view()), name='edit'),
path('<int:pk>/', csrf_exempt(TodoView.as_view()), name='detail'),
path('list/', csrf_exempt(TodoListView.as_view()), name='list'),]Copy the code
Test interface: http://127.0.0.1:8000/todo/create/, http://127.0.0.1:8000/todo/edit/1/, http://127.0.0.1:8000/todo/1/, http://127.0.0.1:800 0 / todo list /.
Request the interface in Postman and check if the data is correct in the MySQL database. This exercise implements the most simplified content, and you can refer to it and improve the code yourself.
Simply implement the list interface using generic.listview (not much different than using Django.views.view) :
from django.core import serializers
from django.views import generic
from django.http import JsonResponse
from .models import Todo
import json
class TodoListView(generic.ListView) :
model = Todo
def render_to_response(self, context) :
todo_list = context.get('object_list')
todo_list_str = serializers.serialize('json', todo_list) Serialize QuerySet to JSON data
todo_list_data = json.loads(todo_list_str)
res_data = []
for todo in todo_list_data:
todo_data = { **todo.get('fields') }
todo_data.update(id=todo.get('pk'))
res_data.append(todo_data)
return JsonResponse(res_data, safe=False, status=200) # Set safe to False to return non-dictionary data
Copy the code
Built-in class-based Views API, CSRF, convenience functions, serialization of Django objects