Django learning notes and project production process

Posted by yeldarb on Wed, 05 Jan 2022 03:34:03 +0100

 pip install django

Create project

Enter the d:\projects directory and execute Django admin startproject bysms

Create the following directory structure:

bysms / project root

        manage.py is a tool script used for project management

The bysms / directory is a python package. It contains important configuration files of the project.

                __init__.py

                settings.py# configuration file for Django project Contains very important configuration items

                urls.py stores a table that declares various http requests sent by the front end

                wsgi.py

web backend system based on wsgi specification

wsgi web server} and wsgi web application

Run django web Service

Execute the command Python manage at d:\projects\bysms \ py runserver 0.0.0.0:80

Enter the loopback address 127.0.0.1 in the browser

Add another domain name address:

Create project app

Enter the root directory of d:\projects and execute Python manage Py startapp sales command

An app with a directory named sales will be created

Return page content to browser

In views Write in PY

from django.http import HttpResponse

def listorders(request):

        return HttpResponse("Here are all the order information in the system...")

Add url routing record

from django.contrib import admin
from django.urls import path

# Don't forget to import the listorders function
from sales.views import listorders

urlpatterns = [
    path('admin/', admin.site.urls),

    # Add the following routing record
    path('sales/orders/', listorders),
]

Login view

Login browser input

Web address http://127.0.0.1/sales/orders/

Simplify routing table and split routing table

All routing tables are written in URLs Py will be a lot and cumbersome

So create a new file sales \ URLs. In the sales directory py 

Then in sales \ URLs Py file input:

from django.urls import path

from sales.views import listorders

urlpatterns = [
    path('orders/', listorders),
]

In the total urls file, you need to modify the routing path

Databases and tables

sqlite does not have a separate database service process. Django can be used directly without building data services first.

The database configuration in the project is in bysms / settings Py, here

There is usually a DB in the root directory SQLite3 file, but it is 0KB,

Then create the database and execute Python manage Py migrate command, there is something in it

Then download the database tool sqlitestudio, address:

SQLiteStudiohttps://sqlitestudio.pl/

Just go in and open it

ORM

To define a database table is to define a table that inherits from Django db. models. Class of model

Defining the fields (columns) in this table is to define some attributes in this class

Class is the processing method of the data in the table, including data addition, deletion, modification and query

Define database

First create an application directory named common, enter the root directory and execute Python manage Py startapp common command

In common / models Py, define the tables required by our business.

max_length indicates the maximum length of the varchar field.

from django.db import models

class Customer(models.Model):
    # Customer name
    name = models.CharField(max_length=200)  

    # contact number
    phonenumber = models.CharField(max_length=200)

    # address
    address = models.CharField(max_length=200)

Create database tables

In the project's configuration file, click settings Py, installed_ Add the following content to the APS configuration item

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Add the line below
    'common.apps.CommonConfig',
]

Execute D: \ projects \ bysms > Python manage. In the root directory of the project Py makemigrations common command

Then 0001 automatically appears under the common\migrations directory_ initial. Py is the corresponding database operation code.

Then execute D: \ projects \ bysms > Python manage. In the project root directory Py migrate command

If you need to update a data later,

For example, adding a QQ requires adding two parameters null = true and blank = true

Then execute Python manage Py makemigrations common command and python manage Py migrate command

Create administrator Admin

The root directory of the project, execute D: \ projects \ bysms > Python manage Py createsuperuser command

Then enter your login name, email and password in the black window (the password must be at least 8 characters)

You need to modify the administrator configuration file common / Admin. In the application Py, register the model class we defined

from django.contrib import admin

from .models import Customer

admin.site.register(Customer)

Then run Python manage py runserver 0.0.0.0:80

Go to the browser and visit http://127.0.0.1/admin/

You can add information directly here. You can delete, add and modify user information by viewing the database

If you want to change the website language, click settings in the configuration file Py , midview , finally add the following configuration

 # admin interface language localization
    'django.middleware.locale.LocaleMiddleware',

Read database data

When the browser accesses sales/customers /, the server returns all customer records in the system to the browser.

In the file sales / views Py, define a listcustomers function (don't write the parent directory of views wrong)

# Import Customer object definition
from  common.models import  Customer

def listcustomers(request):
    # Returns a QuerySet object containing all table records
    # Each table record is a dict object,
    # key is the field name and value is the field value
    qs = Customer.objects.values()

    # Define return string
    retStr = ''
    for customer in  qs:
        for name,value in customer.items():
            retStr += f'{name} : {value} | '

        # <br>Indicates a line break
        retStr += '<br>'

    return HttpResponse(retStr)

Pay attention to adding routing requests, and modify {sales / URLs Py is OK. The route has been split.

Add path ('customers / ', list customers), and don't forget to import

Then enter the following web address in the browser: http://127.0.0.1/sales/customers/

If you have edited customer

Will get

Filter database information

When the user enters / sales / customers /? Phonenumber = 130000000001, it is required to return the customer record with telephone number of 130000000001.

Modify sales / views Py code

def listcustomers(request):
    # Returns a QuerySet object containing all table records
    qs = Customer.objects.values()

    # Check whether there is a parameter phonenumber in the url
    ph =  request.GET.get('phonenumber',None)

    # If yes, add filter criteria
    if ph:
        qs = qs.filter(phonenumber=ph)

    # Define return string
    retStr = ''
    for customer in  qs:
        for name,value in customer.items():
            retStr += f'{name} : {value} | '
        # <br>Indicates a line break
        retStr += '<br>'

    return HttpResponse(retStr)

request.GET is to get a dictionary, request GET. Get is to find the value whose key is the first parameter. If not, it returns None

qs = qs.filter(phonenumber=ph), which is similar to the SQL statement of Django to execute the query, plus the where clause to filter the query

Now enter the following url in the browser: http://127.0.0.1/sales/customers/?phonenumber=1354784574

Will get

Front and rear end separation architecture

The code generates HTML directly

Scheme 1: String splicing

Modify sales / views Py code

# Define the HTML template first
html_template ='''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>full name</th>
        <th>Telephone number</th>
        <th>address</th>
        </tr>
        
        %s
        
        
        </table>
    </body>
</html>
'''

def listcustomers(request):
    # Returns a QuerySet object containing all table records
    qs = Customer.objects.values()

    # Check whether there is a parameter phonenumber in the url
    ph =  request.GET.get('phonenumber',None)

    # If yes, add filter criteria
    if ph:
        qs = qs.filter(phonenumber=ph)

    # Generate the html fragment content to be inserted in the html template
    tableContent = ''
    for customer in  qs:
        tableContent += '<tr>'

        for name,value in customer.items():
            tableContent += f'<td>{value}</td>'

        tableContent += '</tr>'

    return HttpResponse(html_template%tableContent)

After the replacement, visit again http://127.0.0.1/sales/customers/

A page of table type will appear

Scheme 2: use template

Modify sales / views Py code

# Define the HTML template first
html_template ='''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>full name</th>
        <th>Telephone number</th>
        <th>address</th>
        </tr>

        {% for customer in customers %}
            <tr>

            {% for name, value in customer.items %}            
                <td>{{ value }}</td>            
            {% endfor %}
            
            </tr>
        {% endfor %}
                
        </table>
    </body>
</html>
'''

from django.template import engines
django_engine = engines['django']
template = django_engine.from_string(html_template)

def listcustomers(request):
    # Returns a QuerySet object containing all table records
    qs = Customer.objects.values()

    # Check whether there is a parameter phonenumber in the url
    ph =  request.GET.get('phonenumber',None)

    # If yes, add filter criteria
    if ph:
        qs = qs.filter(phonenumber=ph)

    # Pass in the parameters required by the rendering template
    rendered = template.render({'customers':qs})

    return HttpResponse(rendered)

Then, visit the browser and you can get the same result.

The back end does not involve HTML,

If the front-end and back-end architecture is adopted for development, the back-end is hardly responsible for any display interface, and is only responsible for data management.

Create mgr application directory

For requests from administrator users,

In the previous section, we created a special application sales for {salesperson user} to handle related requests.

Then create an application mgr specifically for the administrator user mgr to process related requests.

Execute Python manage Py startapp Mgr command

Add processing request module and url routing

In the bysms/mgr application, add a new file customer Py file

Define a function in this file to distribute the path

In customer Py defines the following dispatcher functions

from django.http import JsonResponse
import json

def dispatcher(request):
    # Put the request parameters into the params attribute of the request to facilitate subsequent processing

    # The GET request parameter is in the url and is obtained through the GET attribute of the request object
    if request.method == 'GET':
        request.params = request.GET

    # The POST/PUT/DELETE request parameters are obtained from the body attribute of the request object
    elif request.method in ['POST','PUT','DELETE']:
        # According to the interface, the message bodies of POST/PUT/DELETE requests are in json format
        request.params = json.loads(request.body)


    # Assign different functions for processing according to different action s
    action = request.params['action']
    if action == 'list_customer':
        return listcustomers(request)
    elif action == 'add_customer':
        return addcustomer(request)
    elif action == 'modify_customer':
        return modifycustomer(request)
    elif action == 'del_customer':
        return deletecustomer(request)

    else:
        return JsonResponse({'ret': 1, 'msg': 'The type is not supported http request'})

Modify routing table

In bysms / URLs Py, modify the route of api/mgr /

# If the url starts with api/mgr,
# According to Mgr The child routing table in URLs is used for routing
path('api/mgr/', include('mgr.urls')),

Then go to the mgr directory and add URLs Py routing file

from django.urls import path

from mgr import customer

urlpatterns = [

    path('customers', customer.dispatcher),
]

All API requests with url of / api/mgr/customers , are dispatched by the dispatch function defined above

At Mgr / customers Write function in PY

def listcustomers(request):
    # Returns a QuerySet object containing all table records
    qs = Customer.objects.values()

    # Convert QuerySet object to list type
    # Otherwise, it cannot be converted to JSON string
    retlist = list(qs)

    return JsonResponse({'ret': 0, 'retlist': retlist})

Import required at the beginning

# Import Customer 
from common.models import Customer

The last data returned is in this format.

Add customer

At Mgr / customers Write function in PY

def addcustomer(request):

    info    = request.params['data']

    # Get the information of the customer to be added from the request message
    # And insert it into the database
    # The return value is the object corresponding to the inserted record 
    record = Customer.objects.create(name=info['name'] ,
                            phonenumber=info['phonenumber'] ,
                            address=info['address'])


    return JsonResponse({'ret': 0, 'id':record.id})

Customer. objects. The create} method can add a record in the customer table.

Temporarily cancel CSRF verification

For simplicity, we will cancel the CSRF verification mechanism temporarily and open it later if necessary.

In the project's configuration file, @ bysms / settings Note 'Django' in the midview configuration item in py MIDDLEWARE. csrf. CsrfViewMiddleware’

Modify customer

At Mgr / customers Write function in PY

def modifycustomer(request):

    # Obtain the information of modifying the customer from the request message
    # Find the customer and modify it
    
    customerid = request.params['id']
    newdata    = request.params['newdata']

    try:
        # Find the corresponding customer record from the database according to the id
        customer = Customer.objects.get(id=customerid)
    except Customer.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id by`{customerid}`Customer does not exist'
        }


    if 'name' in  newdata:
        customer.name = newdata['name']
    if 'phonenumber' in  newdata:
        customer.phonenumber = newdata['phonenumber']
    if 'address' in  newdata:
        customer.address = newdata['address']

    # Note that you must execute save to save the modification information to the database
    customer.save()

    return JsonResponse({'ret': 0})

Delete customer

At Mgr / customers Write function in PY

def deletecustomer(request):

    customerid = request.params['id']

    try:
        # Find the corresponding customer record from the database according to the id
        customer = Customer.objects.get(id=customerid)
    except Customer.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id by`{customerid}`Customer does not exist'
        }

    # The delete method deletes the record from the database
    customer.delete()

    return JsonResponse({'ret': 0})

And front-end integration

Front end system: Click here to downloadhttp://cdn1.python3.vip/files/django/z_dist.zip , unzip to the root directory of the file

In bysms / URLs Py file, add one at the end

+ static("/", document_root="./z_dist")

And add a statement

# Static file service
from django.conf.urls.static import static

Restart and enter Python manage py runserver 80

Then open the browser and enter the following web address: http://localhost/mgr/index.html

Realize login

Create a code file {sign in the mgr directory_ in_ out. py

from django.http import JsonResponse

from django.contrib.auth import authenticate, login, logout

# Login processing
def signin( request):
    # Get user name and password parameters from HTTP POST request
    userName = request.POST.get('username')
    passWord = request.POST.get('password')

    # Use the methods in Django auth library to verify the user name and password
    user = authenticate(username=userName, password=passWord)
    
    # If the user can be found and the password is correct
    if user is not None:
        if user.is_active:
            if user.is_superuser:
                login(request, user)
                # Save user type in session
                request.session['usertype'] = 'mgr'

                return JsonResponse({'ret': 0})
            else:
                return JsonResponse({'ret': 1, 'msg': 'Please log in with an administrator account'})
        else:
            return JsonResponse({'ret': 0, 'msg': 'The user has been disabled'})
        
    # Otherwise, the user name and password are incorrect
    else:
        return JsonResponse({'ret': 1, 'msg': 'Wrong user name or password'})


# Logout processing
def signout( request):
    # Use logout method
    logout(request)
    return JsonResponse({'ret': 0})

Create url route

Because in the total routing file, {bysms / URLs Py} added routing record

Therefore, you only need the sub route file {URLs. Under the mgr directory Add content to PY

 path('signin', sign_in_out.signin),
 path('signout', sign_in_out.signout),

And import

from mgr import sign_in_out

Then log in with the browser http://127.0.0.1/mgr/sign.html

test

Test login and logout interface

Create a new directory test in the root directory, and create a new py file tc001 py

import  requests,pprint

payload = {
    'username': 'jiang',
    'password': '123qwe456'
}

response = requests.post('http://localhost/api/mgr/signin',
              data=payload)

pprint.pprint(response.json())

Testing lists the customer's interfaces

Create a new py file in the test directory, ts001 py

import  requests,pprint

response = requests.get('http://localhost/api/mgr/customers?action=list_customer')

pprint.pprint(response.json())

Test add customer interface

Create a new py file in the test directory, ts002 py

import  requests,pprint

# Build a message body to add customer information in json format
payload = {
    "action":"add_customer",
    "data":{
        "name":"Wuhan Qiaoxi hospital",
        "phonenumber":"13345679934",
        "address":"Wuhan Qiaoxi Hospital North Road"
    }
}

# Send request to web Service
response = requests.post('http://localhost/api/mgr/customers',
              json=payload)

pprint.pprint(response.json())

# Build a message body to view customer information
response = requests.get('http://localhost/api/mgr/customers?action=list_customer')

# Send request to web Service
pprint.pprint(response.json())

session scheme

Solve the problem that users may skip login and directly access subsequent addresses

Modify Mgr / customer Py's dispatcher function, preceded by

    # Judge whether the user is the logged in administrator user according to the session
    if 'usertype' not in request.session:
        return JsonResponse({
            'ret': 302,
            'msg': 'Not logged in',
            'redirect': '/mgr/sign.html'}, 
            status=302)

    if request.session['usertype'] != 'mgr' :
        return JsonResponse({
            'ret': 302,
            'msg': 'User non mgr type',
            'redirect': '/mgr/sign.html'} ,
            status=302)

Close and reopen the black window, and enter Python manage py runserver 80

Then open the browser and enter the following web address: http://localhost/mgr/index.html

Press F12 and you will find that you are not logged in

Database association

In common / models Py delete previously created QQ

On the console, enter Python manage py makemigrations common

And python manage py migrate

One to many

The {one to many} relationship between tables is the} foreign key} association relationship ForeignKey

In common / models Py new drug category

class Medicine(models.Model):
    # Drug name
    name = models.CharField(max_length=200)
    # Drug number
    sn = models.CharField(max_length=200)
    # describe
    desc = models.CharField(max_length=200)

In common / models Py define Order table Order

import datetime
class Order(models.Model):
    # Order name
    name = models.CharField(max_length=200,null=True,blank=True)

    # Creation date
    create_date = models.DateTimeField(default=datetime.datetime.now)

    # customer
    customer = models.ForeignKey(Customer,on_delete=models.PROTECT)
  • CASCADE

Delete the primary key record and the corresponding foreign key table record.

For example, we want to delete the customer Zhang San. When we delete the record of Zhang San in the customer table, we also delete all the Order records of Zhang San in the Order table

  • PROTECT

Deleting records is prohibited.

For example, we want to delete customer Zhang San. If there is Zhang San's Order record in the Order table, the Django system will throw an exception of ProtectedError type. Of course, it is forbidden to delete customer records and related Order records.

Unless we delete all Zhang San's Order records in the Order table first, we can delete Zhang San's records in the customer table.

  • SET_NULL

Delete the primary key record and set the value of the foreign key field of the foreign key record to null. Of course, the premise is that the foreign key field should be set to a value, and null is allowed.

For example, when we want to delete customer Zhang San, when we delete the customer Zhang San record, the customer field value in all Zhang San records in the Order table will be set to null. However, we did not set the customer field to have a parameter setting of {null=True}, so the value cannot be SET_NULL.

On the console, enter Python manage py makemigrations common

And python manage py migrate

one-on-one

Implement one-to-one relationship with OneToOneField object in Django

class Student(models.Model):
    # full name
    name = models.CharField(max_length=200)
    # class
    classname = models.CharField(max_length=200)
    # describe
    desc = models.CharField(max_length=200)


class ContactAddress(models.Model):
    # One to one student 
    student = models.OneToOneField(Student, on_delete=models.PROTECT)
    # family
    homeaddress = models.CharField(max_length=200)
    # Telephone number
    phone = models.CharField(max_length=200)

Many to many

Django represents many to many relationships through the {ManyToManyField} object

A new table common will be created_ ordermedicine

A new table that uses the keys of two tables to establish a relationship

In common / models Py NEW

 # The drugs purchased by order and the Medicine table have a many to many relationship
    medicines = models.ManyToManyField(Medicine, through='OrderMedicine')


class OrderMedicine(models.Model):
    order = models.ForeignKey(Order, on_delete=models.PROTECT)
    medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT)

    # Quantity of drugs in the order
    amount = models.PositiveIntegerField()

On the console, enter Python manage py makemigrations common

And python manage py migrate

Drug Administration

Create a new medicine. Under the mgr directory py

from django.http import JsonResponse

# Import Medicine object definition
from  common.models import  Medicine

import json

def dispatcher(request):
    # Judge whether the user is the logged in administrator user according to the session
    if 'usertype' not in request.session:
        return JsonResponse({
            'ret': 302,
            'msg': 'Not logged in',
            'redirect': '/mgr/sign.html'},
            status=302)

    if request.session['usertype'] != 'mgr':
        return JsonResponse({
            'ret': 302,
            'msg': 'User non mgr type',
            'redirect': '/mgr/sign.html'},
            status=302)


    # Put the request parameters into the params attribute of the request to facilitate subsequent processing

    # The GET request parameter is in the GET attribute of the request object
    if request.method == 'GET':
        request.params = request.GET

    # The POST/PUT/DELETE request parameters are obtained from the body attribute of the request object
    elif request.method in ['POST','PUT','DELETE']:
        # According to the interface, the message bodies of POST/PUT/DELETE requests are in json format
        request.params = json.loads(request.body)


    # Assign different functions for processing according to different action s
    action = request.params['action']
    if action == 'list_medicine':
        return listmedicine(request)
    elif action == 'add_medicine':
        return addmedicine(request)
    elif action == 'modify_medicine':
        return modifymedicine(request)
    elif action == 'del_medicine':
        return deletemedicine(request)

    else:
        return JsonResponse({'ret': 1, 'msg': 'The type is not supported http request'})



def listmedicine(request):
    # Returns a QuerySet object containing all table records
    qs = Medicine.objects.values()

    # Convert QuerySet object to list type
    # Otherwise, it cannot be converted to JSON string
    retlist = list(qs)

    return JsonResponse({'ret': 0, 'retlist': retlist})


def addmedicine(request):

    info    = request.params['data']

    # Get the information of the customer to be added from the request message
    # And insert it into the database
    medicine = Medicine.objects.create(name=info['name'] ,
                            sn=info['sn'] ,
                            desc=info['desc'])


    return JsonResponse({'ret': 0, 'id':medicine.id})


def modifymedicine(request):

    # Obtain the information of modifying the customer from the request message
    # Find the customer and modify it

    medicineid = request.params['id']
    newdata    = request.params['newdata']

    try:
        # Find the corresponding customer record from the database according to the id
        medicine = Medicine.objects.get(id=medicineid)
    except Medicine.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id by`{medicineid}`The drug does not exist'
        }


    if 'name' in  newdata:
        medicine.name = newdata['name']
    if 'sn' in  newdata:
        medicine.sn = newdata['sn']
    if 'desc' in  newdata:
        medicine.desc = newdata['desc']

    # Note that you must execute save to save the modification information to the database
    medicine.save()

    return JsonResponse({'ret': 0})


def deletemedicine(request):

    medicineid = request.params['id']

    try:
        # Find the corresponding drug record from the database according to the id
        medicine = Medicine.objects.get(id=medicineid)
    except Medicine.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id by`{medicineid}`Customer does not exist'
        }

    # The delete method deletes the record from the database
    medicine.delete()

    return JsonResponse({'ret': 0})

In Mgr \ URLs Py adds the request processing routing settings for medicine

from django.urls import path
from mgr import customer,sign_in_out,medicine

urlpatterns = [

    path('customers', customer.dispatcher),
    path('medicines', medicine.dispatcher), # Add this line

    path('signin', sign_in_out.signin),
    path('signout', sign_in_out.signout),

]

ORM operations on associated tables

In common / models Py

# Country table
class Country(models.Model):
    name = models.CharField(max_length=100)

# In the student table, the country field is the foreign key of the country table, forming a one to many relationship
class Student(models.Model):
    name    = models.CharField(max_length=100)
    grade   = models.PositiveSmallIntegerField()
    country = models.ForeignKey(Country,
                                on_delete=models.PROTECT)

Execute on console

python manage.py makemigrations common

python manage.py migrate

Generate table in database

Then execute Python manage.exe on the command line Py shell, directly start the Django command line and enter the code.

from common.models import *
c1 = Country.objects.create(name='China')
c2 = Country.objects.create(name='U.S.A')
c3 = Country.objects.create(name='France')
Student.objects.create(name='White moon', grade=1, country=c1)
Student.objects.create(name='Black feather', grade=2, country=c1)
Student.objects.create(name='Da Luo', grade=1, country=c1)
Student.objects.create(name='True Buddha', grade=2, country=c1)
Student.objects.create(name='Mike', grade=1, country=c2)
Student.objects.create(name='Gus',  grade=1, country=c2)
Student.objects.create(name='White', grade=2, country=c2)
Student.objects.create(name='Napolen', grade=2, country=c3)

Forward associative access

Foreign key table field access:

s1 = Student.objects.get(name='White moon')
s1.country.name

Foreign key table field filtering:

Student.objects.filter(grade=1).values()

Find all Chinese students in Grade 1 in the Student table, which cannot be written as Student objects. Filter (grade = 1, country = 'China')

It can be written as:

cn = Country.objects.get(name='China')
Student.objects.filter(grade=1,country_id=cn.id).values()

it's fine too:

cn = Country.objects.get(name='China')
Student.objects.filter(grade=1,country=cn).values()

Easier:

Student.objects.filter(grade=1,country__name='China').values()

If you only need two fields: student name and country name, you can specify values

Student.objects.filter(grade=1,country__name='China').values('name','country__name')

But the country name is "country"__ Name, the format is incorrect. If it must be , countryname, you can use the , annotate , method to rename the obtained field value

from django.db.models import F

# annotate can alias table fields
Student.objects.annotate(
    countryname=F('country__name'),
    studentname=F('name')
    ).filter(grade=1,countryname='China').values('studentname','countryname')

Reverse associative access

The reverse relationship is represented by converting the Model name of the  table to lowercase 

Get all the students who belong to this country:

cn = Country.objects.get(name='China')
cn.student_set.all()

The Model name is converted to lowercase through the} table, followed by a_ set to get all reverse foreign key Association objects

Reverse filtering:

Get the names of all countries with first graders:

# First get a list of all first grader IDs
country_ids = Student.objects.filter(grade=1).values_list('country', flat=True)

# Then use the id through the id list__ In filtering
Country.objects.filter(id__in=country_ids).values()

Related is not specified_ Name, the table name should be converted to lowercase using}

Country.objects.filter(student__grade=1).values()

However, this will produce duplicate records, which can be used distinct() de duplication

Country.objects.filter(student__grade=1).values().distinct()

Implementation project code

Create a new order under the mgr directory Py handles requests from clients to list and add orders

from django.http import JsonResponse
from django.db.models import F
from django.db import IntegrityError, transaction

# Import Order object definition
from  common.models import  Order,OrderMedicine

import json

def dispatcher(request):
    # Judge whether the user is the logged in administrator user according to the session
    if 'usertype' not in request.session:
        return JsonResponse({
            'ret': 302,
            'msg': 'Not logged in',
            'redirect': '/mgr/sign.html'},
            status=302)

    if request.session['usertype'] != 'mgr':
        return JsonResponse({
            'ret': 302,
            'msg': 'User non mgr type',
            'redirect': '/mgr/sign.html'},
            status=302)


    # Put the request parameters into the params attribute of the request to facilitate subsequent processing

    # The GET request parameter is in the GET attribute of the request object
    if request.method == 'GET':
        request.params = request.GET

    # The POST/PUT/DELETE request parameters are obtained from the body attribute of the request object
    elif request.method in ['POST','PUT','DELETE']:
        # According to the interface, the message bodies of POST/PUT/DELETE requests are in json format
        request.params = json.loads(request.body)

    # Assign different functions for processing according to different action s
    action = request.params['action']
    if action == 'list_order':
        return listorder(request)
    elif action == 'add_order':
        return addorder(request)

    # The order cannot be modified or deleted

    else:
        return JsonResponse({'ret': 1, 'msg': 'The type is not supported http request'})

In Mgr \ URLs Add the routing for orders request processing to py

from django.urls import path
from mgr import customer,sign_in_out,medicine,order

urlpatterns = [

    path('customers', customer.dispatcher),
    path('medicines', medicine.dispatcher),
    path('orders', order.dispatcher), # Add this line

    path('signin', sign_in_out.signin),
    path('signout', sign_in_out.signout),

]

Transaction, many to many record addition

Add the function addorder to process the {add order} request.

To add an Order record, you need to add records in two tables (Order and OrderMedicine).

The insertion of two tables means that we have to have two database operations.

If the first insertion succeeds and the second insertion fails, a part of the Order information is written in the Order table, but the Order information in the OrderMedicine table is not written successfully.

This is a big problem: it will cause the treatment to be half done.

Then there will be data inconsistency in the database. The term is dirty data

Use the transaction {mechanism of database to solve this problem

You can use "with transaction" in Django Atomic()

In order PY

def addorder(request):

    info  = request.params['data']

    # Get the information of the order to be added from the request message
    # And insert it into the database

    
    with transaction.atomic():
        new_order = Order.objects.create(name=info['name'] ,
                                         customer_id=info['customerid'])

        batch = [OrderMedicine(order_id=new_order.id,medicine_id=mid,amount=1)  
                    for mid in info['medicineids']]

        #  Multiple associated records have been added to the many to many relationship table
        OrderMedicine.objects.bulk_create(batch)


    return JsonResponse({'ret': 0,'id':new_order.id})

ORM foreign key Association

In order PY

def listorder(request):
    # Returns a QuerySet object containing all table records
    qs = Order.objects\
            .annotate(
                customer_name=F('customer__name'),
                medicines_name=F('medicines__name')
            )\
            .values(
                'id','name','create_date','customer_name','medicines_name'
            )

    # Convert QuerySet object to list type
    retlist = list(qs)

    # There may be order records with the same ID and different drugs, which need to be consolidated
    newlist = []
    id2order = {}
    for one in retlist:
        orderid = one['id']
        if orderid not in id2order:
            newlist.append(one)
            id2order[orderid] = one
        else:
            id2order[orderid]['medicines_name'] += ' | ' + one['medicines_name']

    return JsonResponse({'ret': 0, 'retlist': newlist})

Topics: Python Django Back-end