pip install django
创建项目
进入d:\projects 目录,执行 django-admin startproject bysms
创建 如下的目录结构:
bysms/ 项目根目录
manage.py 一个工具脚本,用作项目管理的
bysms/ 目录是python包。 里面包含项目的重要配置文件。
init.py
settings.py Django 项目的配置文件. 包含了非常重要的配置项
urls.py 里面存放了 一张表, 声明了前端发过来的各种http请求
wsgi.py
wsgi规范的 web后端系统
运行django web服务
在d:\projects\bysms\执行命令 python manage.py runserver 0.0.0.0:80
在浏览器中输入环回地址127.0.0.1
添加其他域名地址:
创建项目app
进入d:\projects根目录,执行python manage.py startapp sales 命令
就会创建一个目录名为sales的app
返回页面内容给浏览器
在views.py中写入
from django.http import HttpResponse
def listorders(request):
return HttpResponse("下面是系统中所有的订单信息。。。")
添加url路由记录
from django.contrib import admin
from django.urls import path
别忘了导入 listorders 函数
from sales.views import listorders
urlpatterns = [
path('admin/', admin.site.urls),
# 添加如下的路由记录
path('sales/orders/', listorders),
]
登录查看
登录浏览器输入
网址http://127.0.0.1/sales/orders/
简化路由表,路由表拆分
所以在sales目录下面建立一个新的文件sales\urls.py
然后在sales\urls.py 文件中输入:
from django.urls import path
from sales.views import listorders
urlpatterns = [
path('orders/', listorders),
]
在总的urls的文件中就需要修改路由路径
数据库和表
sqlite 没有 独立的数据库服务进程。Django中可以直接使用,无须先搭建数据服务。
项目中数据库的配置在bysms/settings.py 中,这里
根目录下一般有一个db.sqlite3 文件,但是是0KB,
然后创建数据库执行python manage.py migrate命令,里面就有东西了
然后下载数据库工具sqlitestudio,地址:
SQLiteStudio https://sqlitestudio.pl/;
进去打开即可
ORM
定义一张数据库的表 就是定义一个继承自 django.db.models.Model 的类
定义该表中的字段(列), 就是定义该类里面的一些属性
类的方法就是对该表中数据的处理方法,包括 数据的增删改查
定义数据库
先创建一个名为common的应用目录,进入根目录执行python manage.py startapp common 命令
在common/models.py中,定义我们的业务所需要的表。
max_length 指明了该 varchar字段的 最大长度。
from django.db import models
class Customer(models.Model):
# 客户名称
name = models.CharField(max_length=200)
# 联系电话
phonenumber = models.CharField(max_length=200)
# 地址
address = models.CharField(max_length=200)
创建数据库表
在项目的配置文件 settings.py 中, INSTALLED_APPS 配置项 加入如下内容
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 加入下面这行
'common.apps.CommonConfig',
]
在项目根目录下执行d:\projects\bysms>python manage.py makemigrations common命令
然后在common\migrations 目录下面自动出现了0001_initial.py,就是相应要进行的数据库操作代码。
再在项目根目录下执行 d:\projects\bysms>python manage.py migrate命令
如果后面需要更新一个数据,
比如加一个QQ上去,需要在后面加上两个参数null = True , blank = True
然后执行python manage.py makemigrations common命令和python manage.py migrate命令
创建管理员Admin
项目的根目录,执行d:\projects\bysms>python manage.py createsuperuser命令
然后在黑窗口上自己输入登录名、email、密码(密码至少8个字符)
需要修改应用里面的 管理员 配置文件 common/admin.py,注册我们定义的model类
from django.contrib import admin
from .models import Customer
admin.site.register(Customer)
然后再运行一下python manage.py runserver 0.0.0.0:80
进入到浏览器,访问 http://127.0.0.1/admin/
这里可以直接添加信息。去数据库查看就可以删除、增加、修改用户信息
如果要改网站语言,在配置文件 settings.py 中 MIDDLEWARE 最后加入如下配置
# admin界面语言本地化
'django.middleware.locale.LocaleMiddleware',
读取数据库数据
实现浏览器访问 sales/customers/,服务端就返回系统中所有的客户记录给浏览器。
在文件sales/views.py 中,定义一个listcustomers 函数,(别写错了views的上级目录)
导入 Customer 对象定义
from common.models import Customer
def listcustomers(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
# 每条表记录都是是一个dict对象,
# key 是字段名,value 是 字段值
qs = Customer.objects.values()
# 定义返回字符串
retStr = ''
for customer in qs:
for name,value in customer.items():
retStr += f'{name} : {value} | '
# 表示换行
retStr += ''
return HttpResponse(retStr)
要注意加上路由请求,修改 sales/urls.py就行了,已经拆分过路由了。
加上 path(‘customers/’, listcustomers),别忘了导入
然后在浏览器输入如下 网址:http://127.0.0.1/sales/customers/
如果编辑过customer
就会得到
过滤数据库信息
当用户在浏览器输入/sales/customers/?phonenumber=13000000001 ,要求返回电话号码为 13000000001 客户记录。
修改sales/views.py的代码
def listcustomers(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Customer.objects.values()
# 检查url中是否有参数phonenumber
ph = request.GET.get('phonenumber',None)
# 如果有,添加过滤条件
if ph:
qs = qs.filter(phonenumber=ph)
# 定义返回字符串
retStr = ''
for customer in qs:
for name,value in customer.items():
retStr += f'{name} : {value} | '
# 表示换行
retStr += ''
return HttpResponse(retStr)
request.GET就是获取到了一个字典,request.GET.get就是找到键为第一个参数的值,如果没有就返回None
qs = qs.filter(phonenumber=ph),这个类似于Django去执行查询的SQL的语句 加上where从句,进行过滤查询
现在在浏览器输入如下 url:http://127.0.0.1/sales/customers/?phonenumber=1354784574
就会得到
前后端分离架构
代码直接生成HTML
方案一:用字符串拼接形式
修改sales/views.py的代码
先定义好HTML模板
html_template ='''
table {
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}
id
姓名
电话号码
地址
%s
'''
def listcustomers(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Customer.objects.values()
# 检查url中是否有参数phonenumber
ph = request.GET.get('phonenumber',None)
# 如果有,添加过滤条件
if ph:
qs = qs.filter(phonenumber=ph)
# 生成html模板中要插入的html片段内容
tableContent = ''
for customer in qs:
tableContent += ''
for name,value in customer.items():
tableContent += f'{value}'
tableContent += ''
return HttpResponse(html_template%tableContent)
替换好了之后,再次访问 http://127.0.0.1/sales/customers/
就会出现表格类型的页面
方案二:使用模板
修改sales/views.py的代码
先定义好HTML模板
html_template ='''
table {
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}
id
姓名
电话号码
地址
{% for customer in customers %}
{% for name, value in customer.items %}
{{ value }}
{% endfor %}
{% endfor %}
'''
from django.template import engines
django_engine = engines['django']
template = django_engine.from_string(html_template)
def listcustomers(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Customer.objects.values()
# 检查url中是否有参数phonenumber
ph = request.GET.get('phonenumber',None)
# 如果有,添加过滤条件
if ph:
qs = qs.filter(phonenumber=ph)
# 传入渲染模板需要的参数
rendered = template.render({'customers':qs})
return HttpResponse(rendered)
然后,访问浏览器,可以得到一样的结果。
后端不涉及HTML,
如果采用前后端分离的架构开发, 后端几乎不负责任何展现界面的工作,只负责对数据进行管理 。
创建mgr应用目录
针对管理员用户的请求,
前面为 销售员用户专门创建了一个应用 sales 来处理相关的请求。
再为 管理员用户 专门创建一个应用 mgr 来处理相关的 请求。
执行python manage.py startapp mgr命令
添加处理请求模块和url路由
在bysms/mgr应用里,添加一个新的文件customer.py文件
在这个文件中定义一个函数,用来分发路径
在 customer.py 中定义如下 dispatcher 函数
from django.http import JsonResponse
import json
def dispatcher(request):
# 将请求参数统一放入request 的 params 属性中,方便后续处理
# GET请求 参数在url中,同过request 对象的 GET属性获取
if request.method == 'GET':
request.params = request.GET
# POST/PUT/DELETE 请求 参数 从 request 对象的 body 属性中获取
elif request.method in ['POST','PUT','DELETE']:
# 根据接口,POST/PUT/DELETE 请求的消息体都是 json格式
request.params = json.loads(request.body)
# 根据不同的action分派给不同的函数进行处理
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': '不支持该类型http请求'})
修改路由表
在bysms/urls.py中,修改api/mgr/的路由
凡是 url 以 api/mgr 开头的,
都根据 mgr.urls 里面的 子路由表进行路由
path('api/mgr/', include('mgr.urls')),
然后再去mgr 目录下面添加 urls.py 路由文件
from django.urls import path
from mgr import customer
urlpatterns = [
path('customers', customer.dispatcher),
]
凡是 API 请求url为 /api/mgr/customers 的,都交由 我们上面定义的dispatch函数进行分派处理
在mgr/customers.py中写入函数
def listcustomers(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Customer.objects.values()
# 将 QuerySet 对象 转化为 list 类型
# 否则不能 被 转化为 JSON 字符串
retlist = list(qs)
return JsonResponse({'ret': 0, 'retlist': retlist})
开头需要导入
导入 Customer
from common.models import Customer
最后返回的数据就是这样的格式。
添加客户
在mgr/customers.py中写入函数
def addcustomer(request):
info = request.params['data']
# 从请求消息中 获取要添加客户的信息
# 并且插入到数据库中
# 返回值 就是对应插入记录的对象
record = Customer.objects.create(name=info['name'] ,
phonenumber=info['phonenumber'] ,
address=info['address'])
return JsonResponse({'ret': 0, 'id':record.id})
Customer.objects.create方法就可以添加一条Customer表里面的记录。
临时取消CSRF校验
为了简单起见,我们先临时取消掉CSRF的 校验机制,等以后有需要再打开。
在 项目的配置文件bysms/settings.py 中 MIDDLEWARE配置项 里 注释掉 ‘django.middleware.csrf.CsrfViewMiddleware’
修改客户
在mgr/customers.py中写入函数
def modifycustomer(request):
# 从请求消息中 获取修改客户的信息
# 找到该客户,并且进行修改操作
customerid = request.params['id']
newdata = request.params['newdata']
try:
# 根据 id 从数据库中找到相应的客户记录
customer = Customer.objects.get(id=customerid)
except Customer.DoesNotExist:
return {
'ret': 1,
'msg': f'id 为{customerid}
的客户不存在'
}
if 'name' in newdata:
customer.name = newdata['name']
if 'phonenumber' in newdata:
customer.phonenumber = newdata['phonenumber']
if 'address' in newdata:
customer.address = newdata['address']
# 注意,一定要执行save才能将修改信息保存到数据库
customer.save()
return JsonResponse({'ret': 0})
删除客户
在mgr/customers.py中写入函数
def deletecustomer(request):
customerid = request.params['id']
try:
# 根据 id 从数据库中找到相应的客户记录
customer = Customer.objects.get(id=customerid)
except Customer.DoesNotExist:
return {
'ret': 1,
'msg': f'id 为{customerid}
的客户不存在'
}
# delete 方法就将该记录从数据库中删除了
customer.delete()
return JsonResponse({'ret': 0})
和前端集成
前端系统:点击这里下载http://cdn1.python3.vip/files/django/z_dist.zip ;,解压到文件根目录
在 bysms/urls.py 文件中,在末尾 添加一个
+ static("/", document_root="./z_dist")
并添加声明
静态文件服务
from django.conf.urls.static import static
重新启动一下,输入python manage.py runserver 80
然后再打开浏览器,输入如下网址:http://localhost/mgr/index.html
实现登录
在mgr目录里面创建一个代码文件sign_in_out.py
from django.http import JsonResponse
from django.contrib.auth import authenticate, login, logout
登录处理
def signin( request):
# 从 HTTP POST 请求中获取用户名、密码参数
userName = request.POST.get('username')
passWord = request.POST.get('password')
# 使用 Django auth 库里面的 方法校验用户名、密码
user = authenticate(username=userName, password=passWord)
# 如果能找到用户,并且密码正确
if user is not None:
if user.is_active:
if user.is_superuser:
login(request, user)
# 在session中存入用户类型
request.session['usertype'] = 'mgr'
return JsonResponse({'ret': 0})
else:
return JsonResponse({'ret': 1, 'msg': '请使用管理员账户登录'})
else:
return JsonResponse({'ret': 0, 'msg': '用户已经被禁用'})
# 否则就是用户名、密码有误
else:
return JsonResponse({'ret': 1, 'msg': '用户名或者密码错误'})
登出处理
def signout( request):
# 使用登出方法
logout(request)
return JsonResponse({'ret': 0})
创建url路由
因为在总路由文件bysms/urls.py 中 添加了路由记录
所以只需要在mgr 目录下面 的子路由文件urls.py 里添加内容
path('signin', sign_in_out.signin),
path('signout', sign_in_out.signout),
以及导入
from mgr import sign_in_out
然后浏览器登录 http://127.0.0.1/mgr/sign.html
测试
测试登录登出接口
在根目录创建一个新的目录test,在此目录下创建一个新的py文件,tc001.py
import requests,pprint
payload = {
'username': 'jiang',
'password': '123qwe456'
}
response = requests.post('http://localhost/api/mgr/signin',
data=payload)
pprint.pprint(response.json())
测试列出客户的接口
在test目录下创建一个新的py文件,ts001.py
import requests,pprint
response = requests.get('http://localhost/api/mgr/customers?action=list_customer')
pprint.pprint(response.json())
测试添加客户的接口
在test目录下创建一个新的py文件,ts002.py
import requests,pprint
构建添加 客户信息的 消息体,是json格式
payload = {
"action":"add_customer",
"data":{
"name":"武汉市桥西医院",
"phonenumber":"13345679934",
"address":"武汉市桥西医院北路"
}
}
发送请求给web服务
response = requests.post('http://localhost/api/mgr/customers',
json=payload)
pprint.pprint(response.json())
构建查看 客户信息的消息体
response = requests.get('http://localhost/api/mgr/customers?action=list_customer')
发送请求给web服务
pprint.pprint(response.json())
session方案
解决用户可能会跳过登录,直接访问后续地址能直接访问的问题
修改 mgr/customer.py 的dispatcher 函数,在前面加上
# 根据session判断用户是否是登录的管理员用户
if 'usertype' not in request.session:
return JsonResponse({
'ret': 302,
'msg': '未登录',
'redirect': '/mgr/sign.html'},
status=302)
if request.session['usertype'] != 'mgr' :
return JsonResponse({
'ret': 302,
'msg': '用户非mgr类型',
'redirect': '/mgr/sign.html'} ,
status=302)
关闭黑窗口再重新打开,并输入python manage.py runserver 80
然后再打开浏览器,输入如下网址:http://localhost/mgr/index.html
按下F12会发现,显示未登录
数据库的关联
在common/models.py删除之前创建的QQ
在控制台输入python manage.py makemigrations common
以及python manage.py migrate
一对多
表之间 一对多 的关系,就是 外键 关联关系 ForeignKey
在common/models.py新增药品类
class Medicine(models.Model):
# 药品名
name = models.CharField(max_length=200)
# 药品编号
sn = models.CharField(max_length=200)
# 描述
desc = models.CharField(max_length=200)
在common/models.py定义 订单 表 Order
import datetime
class Order(models.Model):
# 订单名
name = models.CharField(max_length=200,null=True,blank=True)
# 创建日期
create_date = models.DateTimeField(default=datetime.datetime.now)
# 客户
customer = models.ForeignKey(Customer,on_delete=models.PROTECT)
- CASCADE
删除主键记录和 相应的外键表记录。
比如,我们要删除客户张三,在删除了客户表中张三记录同时,也删除Order表中所有这个张三的订单记录,瀑布式删除
- PROTECT
禁止删除记录。
比如,我们要删除客户张三,如果Order表中有张三的订单记录,Django系统 就会抛出ProtectedError类型的异常,当然也就禁止删除 客户记录和相关的订单记录了。
除非我们将Order表中所有张三的订单记录都先删除掉,才能删除该客户表中的张三记录。
- SET_NULL
删除主键记录,并且将外键记录中外键字段的值置为null。 当然前提是外键字段要设置为值允许是null。
比如,我们要删除客户张三时,在删除了客户张三记录同时,会将Order表里面所有的 张三记录里面的customer字段值置为 null。 但是上面我们并没有设置 customer 字段有 null=True 的参数设置,所以,是不能取值为 SET_NULL的。
在控制台输入python manage.py makemigrations common
以及python manage.py migrate
一对一
Django 中 用OneToOneField对象 实现 一对一 的关系
class Student(models.Model):
# 姓名
name = models.CharField(max_length=200)
# 班级
classname = models.CharField(max_length=200)
# 描述
desc = models.CharField(max_length=200)
class ContactAddress(models.Model):
# 一对一 对应学生
student = models.OneToOneField(Student, on_delete=models.PROTECT)
# 家庭
homeaddress = models.CharField(max_length=200)
# 电话号码
phone = models.CharField(max_length=200)
多对多
Django是通过 ManyToManyField 对象 表示 多对多的关系的
会新建立一个表common_ordermedicine
用两个表的键来建立关系的一个新表
在common/models.py新增
# 订单购买的药品,和Medicine表是多对多 的关系
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)
# 订单中药品的数量
amount = models.PositiveIntegerField()
在控制台输入python manage.py makemigrations common
以及python manage.py migrate
药品管理
在 mgr 目录下面新建 medicine.py
from django.http import JsonResponse
导入 Medicine 对象定义
from common.models import Medicine
import json
def dispatcher(request):
# 根据session判断用户是否是登录的管理员用户
if 'usertype' not in request.session:
return JsonResponse({
'ret': 302,
'msg': '未登录',
'redirect': '/mgr/sign.html'},
status=302)
if request.session['usertype'] != 'mgr':
return JsonResponse({
'ret': 302,
'msg': '用户非mgr类型',
'redirect': '/mgr/sign.html'},
status=302)
# 将请求参数统一放入request 的 params 属性中,方便后续处理
# GET请求 参数 在 request 对象的 GET属性中
if request.method == 'GET':
request.params = request.GET
# POST/PUT/DELETE 请求 参数 从 request 对象的 body 属性中获取
elif request.method in ['POST','PUT','DELETE']:
# 根据接口,POST/PUT/DELETE 请求的消息体都是 json格式
request.params = json.loads(request.body)
# 根据不同的action分派给不同的函数进行处理
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': '不支持该类型http请求'})
def listmedicine(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Medicine.objects.values()
# 将 QuerySet 对象 转化为 list 类型
# 否则不能 被 转化为 JSON 字符串
retlist = list(qs)
return JsonResponse({'ret': 0, 'retlist': retlist})
def addmedicine(request):
info = request.params['data']
# 从请求消息中 获取要添加客户的信息
# 并且插入到数据库中
medicine = Medicine.objects.create(name=info['name'] ,
sn=info['sn'] ,
desc=info['desc'])
return JsonResponse({'ret': 0, 'id':medicine.id})
def modifymedicine(request):
# 从请求消息中 获取修改客户的信息
# 找到该客户,并且进行修改操作
medicineid = request.params['id']
newdata = request.params['newdata']
try:
# 根据 id 从数据库中找到相应的客户记录
medicine = Medicine.objects.get(id=medicineid)
except Medicine.DoesNotExist:
return {
'ret': 1,
'msg': f'id 为{medicineid}
的药品不存在'
}
if 'name' in newdata:
medicine.name = newdata['name']
if 'sn' in newdata:
medicine.sn = newdata['sn']
if 'desc' in newdata:
medicine.desc = newdata['desc']
# 注意,一定要执行save才能将修改信息保存到数据库
medicine.save()
return JsonResponse({'ret': 0})
def deletemedicine(request):
medicineid = request.params['id']
try:
# 根据 id 从数据库中找到相应的药品记录
medicine = Medicine.objects.get(id=medicineid)
except Medicine.DoesNotExist:
return {
'ret': 1,
'msg': f'id 为{medicineid}
的客户不存在'
}
# delete 方法就将该记录从数据库中删除了
medicine.delete()
return JsonResponse({'ret': 0})
在 mgr\urls.py里面加上 对 medicine 的 请求处理 路由设置
from django.urls import path
from mgr import customer,sign_in_out,medicine
urlpatterns = [
path('customers', customer.dispatcher),
path('medicines', medicine.dispatcher), # 加上这行
path('signin', sign_in_out.signin),
path('signout', sign_in_out.signout),
]
ORM 对关联表的操作
在common/models.py中定义这样的两个Model
国家表
class Country(models.Model):
name = models.CharField(max_length=100)
学生表, country 字段是国家表的外键,形成一对多的关系
class Student(models.Model):
name = models.CharField(max_length=100)
grade = models.PositiveSmallIntegerField()
country = models.ForeignKey(Country,
on_delete=models.PROTECT)
在控制台执行
python manage.py makemigrations common
python manage.py migrate
在数据库中生成表
然后在命令行中执行 python manage.py shell,直接启动Django命令行,输入代码。
from common.models import *
c1 = Country.objects.create(name='中国')
c2 = Country.objects.create(name='美国')
c3 = Country.objects.create(name='法国')
Student.objects.create(name='白月', grade=1, country=c1)
Student.objects.create(name='黑羽', grade=2, country=c1)
Student.objects.create(name='大罗', grade=1, country=c1)
Student.objects.create(name='真佛', 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)
正向关联访问
外键表字段访问:
s1 = Student.objects.get(name='白月')
s1.country.name
外键表字段过滤:
Student.objects.filter(grade=1).values()
查找Student表中所有 一年级中国 学生,不能写成 Student.objects.filter(grade=1,country=’中国’)
可以写成:
cn = Country.objects.get(name='中国')
Student.objects.filter(grade=1,country_id=cn.id).values()
也可以:
cn = Country.objects.get(name='中国')
Student.objects.filter(grade=1,country=cn).values()
更简便:
Student.objects.filter(grade=1,country__name='中国').values()
返回结果如果只需要 学生姓名 和 国家名两个字段,可以指定values内容
Student.objects.filter(grade=1,country__name='中国').values('name','country__name')
但是国家名是 country__name,格式不对,如果要求一定是countryname可以使用annotate 方法将获取的字段值进行重命名
from django.db.models import F
annotate 可以将表字段进行别名处理
Student.objects.annotate(
countryname=F('country__name'),
studentname=F('name')
).filter(grade=1,countryname='中国').values('studentname','countryname')
反向关联访问
反向关系,是通过 表Model名转化为小写 表示的
获取到所有属于这个国家的学生:
cn = Country.objects.get(name='中国')
cn.student_set.all()
通过 表Model名转化为小写 ,后面加上一个 _set 来获取所有的反向外键关联对象
反向过滤:
获取所有 具有一年级学生 的国家名:
先获取所有的一年级学生id列表
country_ids = Student.objects.filter(grade=1).values_list('country', flat=True)
再通过id列表使用 id__in 过滤
Country.objects.filter(id__in=country_ids).values()
没有指定related_name, 则应该使用 表名转化为小写
Country.objects.filter(student__grade=1).values()
但是这样会产生重复记录,可以使用 .distinct() 去重
Country.objects.filter(student__grade=1).values().distinct()
实现项目代码
在 mgr 目录下面新建order.py处理 客户端发过来的 列出订单、添加订单 的请求
from django.http import JsonResponse
from django.db.models import F
from django.db import IntegrityError, transaction
导入 Order 对象定义
from common.models import Order,OrderMedicine
import json
def dispatcher(request):
# 根据session判断用户是否是登录的管理员用户
if 'usertype' not in request.session:
return JsonResponse({
'ret': 302,
'msg': '未登录',
'redirect': '/mgr/sign.html'},
status=302)
if request.session['usertype'] != 'mgr':
return JsonResponse({
'ret': 302,
'msg': '用户非mgr类型',
'redirect': '/mgr/sign.html'},
status=302)
# 将请求参数统一放入request 的 params 属性中,方便后续处理
# GET请求 参数 在 request 对象的 GET属性中
if request.method == 'GET':
request.params = request.GET
# POST/PUT/DELETE 请求 参数 从 request 对象的 body 属性中获取
elif request.method in ['POST','PUT','DELETE']:
# 根据接口,POST/PUT/DELETE 请求的消息体都是 json格式
request.params = json.loads(request.body)
# 根据不同的action分派给不同的函数进行处理
action = request.params['action']
if action == 'list_order':
return listorder(request)
elif action == 'add_order':
return addorder(request)
# 订单 暂 不支持修改 和删除
else:
return JsonResponse({'ret': 1, 'msg': '不支持该类型http请求'})
在mgr\urls.py里面加上 对 orders 请求处理的路由
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), # 加上这行
path('signin', sign_in_out.signin),
path('signout', sign_in_out.signout),
]
事务、多对多记录添加
添加函数 addorder,来处理 添加订单 请求。
添加一条订单记录,需要在2张表(Order 和 OrderMedicine )中添加记录。
两张表的插入,意味着我们要有两次数据库操作。
如果第一次插入成功, 而第二次插入失败, 就会出现 Order表中 把订单信息写了一部分,而OrderMedicine表中 该订单的信息 却没有写成功。
这是个大问题: 就会造成 这个处理 做了一半。
那么数据库中就会出现数据的不一致。术语叫 脏数据
用 数据库 的 事务 机制来解决这个问题
Django 中可以使用with transaction.atomic()来解决
在order.py中添加
def addorder(request):
info = request.params['data']
# 从请求消息中 获取要添加订单的信息
# 并且插入到数据库中
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']]
# 在多对多关系表中 添加了 多条关联记录
OrderMedicine.objects.bulk_create(batch)
return JsonResponse({'ret': 0,'id':new_order.id})
ORM外键关联
在order.py中添加
def listorder(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Order.objects\
.annotate(
customer_name=F('customer__name'),
medicines_name=F('medicines__name')
)\
.values(
'id','name','create_date','customer_name','medicines_name'
)
# 将 QuerySet 对象 转化为 list 类型
retlist = list(qs)
# 可能有 ID相同,药品不同的订单记录, 需要合并
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})
Original: https://blog.csdn.net/jc2935030145/article/details/122267557
Author: 小筱超
Title: Django学习笔记以及项目制作过程
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/735593/
转载文章受原作者版权保护。转载请注明原作者出处!