Python学习:Django开发_03
来源:白月黑羽教Python http://www.python3.vip/tut/webdev/django/01/
常用命令/配置
运行
python manage.py runserver 0.0.0.0:80
创建一个APP
进入项目根目录,执行下面的命令
python manage.py startapp sales
创建数据库脚本
python manage.py makemigrations common
执行数据库脚本
python manage.py migrate
数据库表的关联
后端系统开发中, 数据库设计是重中之重。
特别是前后端分离的系统, 后端的职责基本就是数据管理, 开发的代码几乎都是围绕数据操作的。
虽然,我们教程不是专门讲数据库的, 但也必须讲解常用的 数据库表 和 表之间的关系 的设计 。
目前 使用的数据库系统 主要还是 关系型数据库
。
什么是关系型数据库?就是建立在关系模型基础上的数据库。
大家耳熟能详的mysql、oracle、 sqlserver、SQLite 都是,而 mongodb、Cassandra不是
而关系型数据库,设计的一个难点就是 各种表之间的关联关系
。
常见的3种关联关系就是: 一对多
, 一对一
, 多对多
一对多
表之间 一对多
的关系,就是 外键
关联关系
比如,我们的 BYSMS 系统中, 已经定义了 客户(Customer)
这张表 。如下所示
class Customer(models.Model):
# 客户名称
name = models.CharField(max_length=200)
# 联系电话
phonenumber = models.CharField(max_length=200)
# 地址
address = models.CharField(max_length=200)
现在我们还需要定义 药品(Medicine)
这张表,包括药品名称、编号和描述 这些信息。
这个也很简单,添加如下的类定义
class Medicine(models.Model):
# 药品名
name = models.CharField(max_length=200)
# 药品编号
sn = models.CharField(max_length=200)
# 描述
desc = models.CharField(max_length=200)
接下来我们要定义 订单(Order)
这张表,这个Order表 包括 创建日期、客户、药品、数量。
其中:
客户字段对应的客户 只能是 Customer
中的某个客户记录
可以说:
Order表里面 一条订单记录的客户 对应 Customer表里面的一条客户记录
而 多条 Order记录里面的客户 是可以对应 Customer 表里面 同一个客户记录的,
反过来说,就是:一个客户记录可以对应多条订单记录
这就是一对多的关系,可以用如下图片表示
像这种一对多的关系,数据库中是用 外键 来表示的。
如果一个表中 的 某个字段是外键,那就意味着 这个外键字段的记录的取值,只能是它关联表的某个记录的主键的值。
我们定义表的 Model类的时候,如果没有指定主键字段,migrate 的时候 Django 会为该Model对应的数据库表自动生成一个id字段,作为主键。
比如,我们这里,Customer、Medicine表均没有主键,但是在migrate之后,查看数据库记录就可以发现有一个id字段,且该字段是 主键 (primary key)
现在我们要定义 订单 表 Order,
其中客户字段就应该是一个外键,对应Customer表的主键,也就是id字段
Django中定义外键 的方法就是 Model类的该属性字段 值为 ForeignKey
对象,如下所示
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)
大家可以发现, customer 字段 是外键, 指向 Customer 类。 意思就是告诉Django: Order表的 customer 字段 指向 Customer表的主键 的一个外键。
另外一个参数 on_delete 指定了 当我们想 删除
外键指向的主键 记录时, 系统的行为。
比如 我们要删除客户记录, 那么 Order表中 对应这个客户的订单记录 该如何处理呢?
on_delete 不同取值对应不同的做法,常见的做法如下
-
CASCADE
删除主键记录和 相应的外键表记录。
比如,我们要删除客户张三,在删除了客户表中张三记录同时,也删除Order表中所有这个张三的订单记录
-
PROTECT
禁止删除记录。
比如,我们要删除客户张三,如果Order表中有张三的订单记录,Django系统 就会抛出ProtectedError类型的异常,当然也就禁止删除 客户记录和相关的订单记录了。
除非我们将Order表中所有张三的订单记录都先删除掉,才能删除该客户表中的张三记录。
-
SET_NULL
删除主键记录,并且将外键记录中外键字段的值置为null。 当然前提是外键字段要设置为值允许是null。
比如,我们要删除客户张三时,在删除了客户张三记录同时,会将Order表里面所有的 张三记录里面的customer字段值置为 null。 但是上面我们并没有设置 customer 字段有
null=True
的参数设置,所以,是不能取值为 SET_NULL的。
一对一
外键是 一对多 的关系, 也可以说是 多对一 的关系。
有的时候,表之间是 一对一
的关系。
比如,某个学校的学生 表 和学生的地址表,就形成一对一的关系,即 一条主键所在表的记录 只能对应一条 外键所在表的记录。
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发现这样一对一定定义,它会在migrate的时候,在数据库中定义该字段为外键的同时, 加上 unique=True
约束,表示在此表中,所有记录的该字段 取值必须唯一,不能重复。
多对多
数据库表还有一种 多对多 的关系。
在我们的 BYSMS系统中, 一个订单可以采购多种药品,就对应 Medicine表里面的多种药品;而一种药品也可以被多个订单采购, 那么Order表 和 Medicine表 之间就形成了多对多的关系。
其对应关系可以用下图来表示
Django是通过 ManyToManyField
对象 表示 多对多的关系的。
如下所示:
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)
# 订单购买的药品,和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()
像这样
medicines = models.ManyToManyField(Medicine, through='OrderMedicine')
指定Order表和 Medicine 表 的多对多关系, 其实Order表中并不会产生一个 叫 medicines 的字段。
Order表和 Medicine 表 的多对多关系 是 通过另外一张表, 也就是 through 参数 指定的 OrderMedicine 表 来确定的。
migrate的时候,Django会自动产生一张新表 (这里就是 common_ordermedicine)来 实现 order 表 和 medicine 表之间的多对多的关系。
大家可以执行下面两行命令 migrate 试一下
python manage.py makemigrations common
python manage.py migrate
就会发现产生如下的一张新表 common_ordermedicine:
可以发现这张表中有 order_id 和 medicine_id 两个字段。
比如一个order表的订单id 为 1, 如果该订单中对应的药品有3种,它们的id分别 为 3,4,5。 那么就会有类似这样的这样3条记录在 common_order_medicine 表中。
order_id | medicine_id |
---|---|
1 | 3 |
1 | 4 |
1 | 5 |
实现代码:药品管理
现在我们要实现 药品管理 和 订单管理 的服务端代码了。
其中药品管理部分比较简单, 和前面的 customer.py 的代码 基本类似。
我们在 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,order
urlpatterns = [
path('customers', customer.dispatcher),
path('medicines', medicine.dispatcher), # 加上这行
path('signin', sign_in_out.signin),
path('signout', sign_in_out.signout),
]
我的前端代码已经开发好了对药品的 增删改查处理, 所以可以和我们上面的代码进行集成测试了。
大家可以运行服务,在界面上操作测试一下。
ORM 对关联表的操作
前面我们学过 一对多,一对一,多对多,都是通过外键来实现。
接下来,我们通过一个实例演示,Django ORM 如何 操作 外键关联关系
请大家在 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='White', grade=2, country=c2)
Student.objects.create(name='Napolen', grade=2, country=c3)
通过对象访问外键表
如果你已经获取了一个student对象,要得到他的国家名称只需这样
s1 = Student.objects.get(name='白月')
s1.country.name
根据外键表数据过滤
如果,我们要查找Student表中所有 一年级
学生,很简单
Student.objects.filter(grade=1).values()
如果现在,我们要查找Student表中所有 一年级中国
学生,该怎么写呢?
不能这么写:
Student.objects.filter(grade=1,country='中国')
因为,Student表中country字段并不是国家的名称,而是外键,其实是对应 Country记录的id。
可能有的朋友已经想,我们先获取中国的国家id,然后再通过id去找,像这样
cn = Country.objects.get(name='中国')
Student.objects.filter(grade=1,country_id=cn.id).values()
注意外键字段的id是通过后缀 _id
获取的。
或者这样,也是可以的
cn = Country.objects.get(name='中国')
Student.objects.filter(grade=1,country=cn).values()
上面的方法,写起来麻烦一些,有两步操作。而且需要发送两次数据请求,性能不高。
其实,Django ORM 中,对外键关联,有更方便的语法。
可以这样写
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')
反向访问
如果你已经获取了一个Country对象,如何访问到所有属于这个国家的学生呢?
cn = Country.objects.get(name='中国')
cn.student_set.all()
通过 表Model名转化为小写
,后面加上一个 _set
来获取所有的反向外键关联对象
Django还给出了一个方法,可以更直观的反映 关联关系。
在定义Model的时候,外键字段使用 related_name
参数,像这样
# 国家表
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')
就可以使用更直观的属性名,像这样
cn = Country.objects.get(name='中国')
cn.students.all()
反向过滤
如果我们要获取所有 具有一年级学生 的国家名,该怎么写?
当然可以这样
# 先获取所有的一年级学生id列表
country_ids = Student.objects.filter(grade=1).values_list('country', flat=True)
# 再通过id列表使用 id__in 过滤
Country.objects.filter(id__in=country_ids).values()
但是这样同样存在 麻烦 和性能的问题。
Django ORM 可以这样写
Country.objects.filter(students__grade=1).values()
注意, 因为,我们定义表的时候,用 related_name='students'
指定了反向关联名称 students
,所以这里是 students__grade
。 使用了反向关联名字。
如果没有指定方向关联名, 则应该使用 表名转化为小写
,就是这样
Country.objects.filter(student__grade=1).values()
但是,我们发现,这种方式,会有重复的记录产生,如下
<QuerySet [{'id': 1, 'name': '中国'}, {'id': 1, 'name': '中国'}, {'id': 2, 'name': '美国'}, {'id': 2, 'name': '美国'}]>
可以使用 .distinct()
去重
Country.objects.filter(students__grade=1).values().distinct()
注意:据说 .distinct()
对MySQL数据库无效,我没有来得及验证。实测 SQLite,Postgresql有效。
实现项目代码
url路由更新
现在,我们在 mgr 目录下面新建 order.py 处理 客户端发过来的 列出订单、添加订单 的请求。
同样,先写 dispatcher 函数,代码如下
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 怎么实现 事务操作呢?
这里我们可以使用 Django 的 with transaction.atomic()
代码如下
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})
with transaction.atomic()
下面 缩进部分的代码,对数据库的操作,就都是在 一个事务
中进行了。
如果其中有任何一步数据操作失败了, 前面的操作都会回滚。
这就可以防止出现 前面的 Order表记录插入成功, 而后面的 订单药品 记录插入失败而导致的数据不一致现象。
大家可以发现 插入 OrderMedicine 表中的数据 可能有很多条, 如果我们循环用 python OrderMedicine.objects.create(order_id=new_order.id,medicine_id=mid,amount=1)
插入的话, 循环几次, 就会执行 几次SQL语句 插入的 数据库操作 这样性能不高。
我们可以把多条数据的插入,放在一个SQL语句中完成, 这样会大大提高性能。
方法就是使用 bulk_create, 参数是一个包含所有 该表的 Model 对象的 列表
写好后, 大家可以运行服务 , 用我们做好的前端系统添加几条 订单记录, 然后再查看一下数据库里面的数据是否正确。
ORM外键关联
接下来,我们来编写listorder 函数用来处理 列出订单请求。
根据接口文档,我们应该返回 订单记录格式,如下:
[
{
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: "青霉素 | 红霉素 "
}
]
其中 ‘id’,‘name’,‘create_date’ 这些字段的内容获取很简单,order表中就有这些字段,
只需要这样写就可以了。
def listorder(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Order.objects.values('id','name','create_date')
return JsonResponse({'ret': 0, 'retlist': newlist})
问题是:‘customer_name’ 和 ‘medicines_name’ 这两个字段的值怎么获取呢? 因为 订单对应的客户名字 和 药品的名字 都不在 Order 表中啊。
Order 这个Model 中 有 ‘customer’ 字段 , 它外键关联了 Customer 表中的一个 记录,这个记录里面 的 name字段 就是我们要取的字段。
取 外键关联的表记录的字段值,在Django中很简单,可以直接通过 外键字段 后面加 两个下划线 加 关联字段名的方式 来获取。
比如 这里我们就可以用 下面的代码来实现
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})
我们可以 浏览器访问一下 订单管理界面, F12 查看 浏览器抓包。
同样的道理 , 订单对应 的药品 名字段,是 多对多 关联, 也同样可以用 两个下划线 获取 关联字段的值, 如下所示:
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})
我们可以 浏览器访问一下 订单管理界面, F12 查看 浏览器抓包。
首先,第一个问题, 接口文档需要的名字是 ‘customer_name’ 和 ‘medicines_name’。 里面只有一个下划线, 而我们这里却产生了 两个下划线。
怎么办?
可以使用 annotate 方法将获取的字段值进行重命名,像下面这样
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})
第二个问题,如果一个订单里面有多个药品,就会产生多条记录, 这不是我们要的。
根据接口,一个订单里面的多个药品, 用 竖线 隔开。
怎么办?
我们可以用python代码来处理,像下面这样
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})
如果前端开发工程师也完成了他们的前端开发,就可以进行集成测试了。