创建mode模型表
Django_demo/mgr/models.py
# 国家表
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
python manage.py migrate
添加测试数据
python manage.py shell
#注意应用名称
from paas.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)
一、外键表使用
1、字段访问
#获取student表中 name='白月' 的数据
s1 = Student.objects.get(name='白月')
#将拿到的数据通过外键直接获取到对应外键表的name字段数据并输出
s1.country.name
案例
>>> s1 = Student.objects.get(name='白月')
>>> s1.country.name
'中国'
2、单个字段过滤
Student.objects.filter(grade=1).values()
返回
<QuerySet [{'id': 1, 'name': '白月', 'grade': 1, 'country_id': 1}, {'id': 3, 'name': '大罗', 'grade': 1, 'country_id': 1}, {'id': 5, 'name': 'Mike', 'grade': 1, 'country_id': 2}, {
'id': 6, 'name': 'Gus', 'grade': 1, 'country_id': 2}]>
3、多字段过滤
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()
返回
>>> cn = Country.objects.get(name='中国')
>>> Student.objects.filter(grade=1,country_id=cn.id).values()
<QuerySet [{'id': 1, 'name': '白月', 'grade': 1, 'country_id': 1}, {'id': 3, 'name': '大罗', 'grade': 1, 'country_id': 1}]>
>>> cn = Country.objects.get(name='中国')
>>> Student.objects.filter(grade=1,country=cn).values()
<QuerySet [{'id': 1, 'name': '白月', 'grade': 1, 'country_id': 1}, {'id': 3, 'name': '大罗', 'grade': 1, 'country_id': 1}]>
4、多字段过滤优化
Student.objects.filter(grade=1,country__name='中国').values()
返回
<QuerySet [{'id': 1, 'name': '白月', 'grade': 1, 'country_id': 1}, {'id': 3, 'name': '大罗', 'grade': 1, 'country_id': 1}]>
5、过滤优化--指定显示字段
Student.objects.filter(grade=1,country__name='中国').values('name','country__name')
返回
<QuerySet [{'name': '白月', 'country__name': '中国'}, {'name': '大罗', 'country__name': '中国'}]>
6、字段显示重命名
from django.db.models import F
# annotate 可以将表字段进行别名处理
Student.objects.annotate(
countryname=F('country__name'),
studentname=F('name')
)\
.filter(grade=1,countryname='中国').values('studentname','countryname')
7、反向访问
案例
#声明获取国家表中name字段为中国的数据
cn = Country.objects.get(name='中国')
#先将要查看的表改为全小写,并且声明_set来获取所有的反向外键关联对象
cn.student_set.all()
返回
>>> cn = Country.objects.get(name='中国')
>>> cn.student_set.all()
<QuerySet [<Student: Student object (1)>, <Student: Student object (2)>, <Student: Student object (3)>, <Student: Student object (4)>]>
>>>
小知识
#国家表
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,
# 指定反向访问的名字
related_name='students')
python manage.py makemigrations
python manage.py migrate
查询
cn = Country.objects.get(name='中国')
students = cn.students.all()
#拿到的值循环存储并且输出
student_names = [student.name for student in students]
print(student_names)
返回
>>> print(student_names)
['白月', '黑羽', '大罗', '真佛']
8、反向过滤
# 先获取所有的一年级学生id列表
country_ids = Student.objects.filter(grade=1).values_list('country', flat=True)
# 再通过id列表使用 id__in 过滤
Country.objects.filter(id__in=country_ids).values()
Country.objects.filter(students__grade=1).values()
返回
>>> Country.objects.filter(students__grade=1).values()
<QuerySet [{'id': 7, 'name': '中国'}, {'id': 7, 'name': '中国'}, {'id': 8, 'name': '美国'}, {'id': 8, 'name': '美国'}]>
>>> Country.objects.filter(students__grade=1).values().distinct()
<QuerySet [{'id': 7, 'name': '中国'}, {'id': 8, 'name': '美国'}]>
注意
Country.objects.filter(student__grade=1).values()
二、实现项目代码
1、添加增删改查主体程序
vi Django_demo/mgr/order.py
from django.http import JsonResponse
from django.db.models import F
from django.db import IntegrityError, transaction
# 导入 Order 对象定义
from paas.models import Order,OrderMedicine
import json
def dispatcherorder(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请求'})
2、添加路由
vi Django_demo/mgr/urls.py
urlpatterns = [
...
path('orders', dispatcherorder), # 加上这行
...
]
3、定义添加订单函数
什么是事务
在django中使用事务机制
Django_demo/mgr/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})
代码说明
batch = [OrderMedicine(order_id=new_order.id,medicine_id=mid,amount=1)
for mid in info['medicineids']]
# 在多对多关系表中 添加了 多条关联记录
OrderMedicine.objects.bulk_create(batch)
OrderMedicine.objects.create(order_id=new_order.id,medicine_id=mid,amount=1)
batch = [OrderMedicine(order_id=new_order.id,medicine_id=mid,amount=1)
for mid in info['medicineids']]
# 在多对多关系表中 添加了 多条关联记录
OrderMedicine.objects.bulk_create(batch)
三、ORM 外键关联
[
{
id: 1,
name: "华山医院订单001",
create_date: "2018-12-26T14:10:15.419Z",
customer_name: "华山医院",
medicines_name: "青霉素"
},
{
id: 2,
name: "华山医院订单002",
create_date: "2018-12-27T14:10:37.208Z",
customer_name: "华山医院",
medicines_name: "青霉素 | 红霉素 "
}
]
1、基于接口案例返回值
def listorder(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Order.objects.values('id','name','create_date')
return JsonResponse({'ret': 0, 'retlist': newlist})
def listorder(request):
qs = Order.objects\
.values(
'id','name','create_date',
# 两个下划线,表示取customer外键关联的表中的name字段的值
'customer__name'
)
# 将 QuerySet 对象 转化为 list 类型
retlist = list(qs)
return JsonResponse({'ret': 0, 'retlist': retlist})
Django_demo/mgr/order.py
def listorder(request):
qs = Order.objects\
.values(
'id','name','create_date',
'customer__name',
# 两个下划线,表示取medicines 关联的表中的name字段的值
# 如果有多个,就会产生多条记录
'medicines__name'
)
# 将 QuerySet 对象 转化为 list 类型
retlist = list(qs)
return JsonResponse({'ret': 0, 'retlist': retlist})
2、重命名返回字段
from django.db.models import F
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)
return JsonResponse({'ret': 0, 'retlist': retlist})
3、去除订单内多个不同药品
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})
4、测试--获取订单信息
import requests,pprint
#添加认证
payload = {
'username': 'root',
'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')
# 构建添加 客户信息的 消息体,是json格式
payload = {
"action":"list_order",
}
url='http://127.0.0.1:8000/api/mgr/orders/'
if set_cookie:
# 将Set-Cookie字段的值添加到请求头中
headers = {'Cookie': set_cookie}
# 发送请求给web服务
response = requests.post(url,json=payload,headers=headers)
pprint.pprint(response.json())
返回
{'ret': 0,
'retlist': [{'create_date': '2023-10-25T03:08:00Z',
'customer_name': 'zhangsan',
'id': 5,
'medicines_name': 'gmkl',
'name': 'test'}]}
5、测试--添加订单信息
import requests,pprint
#添加认证
payload = {
'username': 'root',
'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')
# 构建添加 客户信息的 消息体,是json格式
payload = {
"action":"add_order", #模式改为添加
"data": {
"name": "天山订单", #订单名称自定义
"customerid": 1, #客户表中的id值
"medicineids": ["6"] #这个是药品表中的id值
}
}
url='http://127.0.0.1:8000/api/mgr/orders/'
if set_cookie:
# 将Set-Cookie字段的值添加到请求头中
headers = {'Cookie': set_cookie}
# 发送请求给web服务
response = requests.post(url,json=payload,headers=headers)
pprint.pprint(response.json())