安装django:pip install django
创建项目:django-admin startproject bysms
启动项目:python manage.py runserver 0.0.0.0:80
HTTP请求的url路由
创建一个名为sales的app应用:python manage.py startapp sales
路由显示
bysms/urls.py
from django.contrib import admin
from django.urls import path,include
from sales.views import listordersurlpatterns = [path('admin/', admin.site.urls),path('sales/orders/',listorders),]
view.py
from django.http import HttpRequest, HttpResponse
from django.shortcuts import renderdef listorders(request):#返回的HTTP响应消息;消息体为...return HttpResponse('下面是系统中所有的订单信息...')
一级路由二级路由
一级路由bysms/urls.py
from django.contrib import admin
from django.urls import path,include
from sales.views import listordersurlpatterns = [path('admin/', admin.site.urls),# #主路由表path('sales/',include('sales.urls'))
]
二级路由sales/urls.py
from django.urls import path
from sales.views import listordersurlpatterns =[#二级路由表path('orders/',listorders)
]
创建数据库
这里使用的是数据库 sqlite
bysms/settings.py
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': BASE_DIR / 'db.sqlite3',}
}
创建数据库执行命令
E:\HYMS\py\django\bysms> python manage.py migrate
项目根目录下面就会生成一个配置文件中指定的数据库文件db.sqlite3 (字节大小就会由0KB变成128KB)
ORM
数据库
表定义和表记录之间的关系
就像类和实例
之间的关系
创建common应用:python manage.py startapp common
makemigrations修改数据库命令:python manage.py makemigrations common
看common应用下的models.py是否有更新
看目前settings里的所有app全部查看一遍有无表的变更:python manage.py migrate
定义数据库表
定义一张数据库表 就是定义一个继承自django.db.models.Model的类
定义表中的字段/列,就是定义该类里面的一些属性
类的方法就是对该表中数据的处理方法 ,包括数据的增删改查
common/models.py
from django.db import modelsclass Customer(models.Model):# 客户名称name = models.CharField(max_length=200)# 联系电话phonenumber = models.CharField(max_length=200)# 地址address = models.CharField(max_length=200)#qqqq = models.CharField(max_length=30,null=True,blank=True)
创建数据库表
settings.py
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',# 加入下面这行'common',
]
可以直接写app的包名
E:\HYMS\py\django\bysms> python manage.py makemigrations common
E:\HYMS\py\django\bysms> python manage.py migrate
Django Admin 管理数据
Django提供了一个管理员操作界面可以方便的 添加、修改、删除你定义的 model 表数据
创建 一个超级管理员账号:python manage.py createsuperuser
然后我们需要修改应用里面的 管理员 配置文件 common/admin.py,注册我们定义的model类;
这样Django才会知道
from django.contrib import adminfrom .models import Customeradmin.site.register(Customer)
python manage.py runserver 0.0.0.0:80 重启
http://127.0.0.1/admin
读取数据库中的数据
功能:127.0.0.1/sales/customers/ 服务端返回系统中所有的客户记录(customer表中所有记录) 给浏览器
sales/view.py
#导入Customer对象
from common.models import Customerdef 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} |'#<br>表换行retStr += '<br>'return HttpResponse(retStr)
二级路由表 sales/urls.py
path('customers/', listcustomers)
过滤条件
增加以下三行代码
#检查url中是否有参数phonenumberph = request.GET.get('phonenumber',None)#如果有,就添加过滤条件if ph:qs = qs.filter(phonenumber = ph)
相当于mysql的 select * from common_customer where phonenumber = 13204033566
qs:<QuerySet [{'id': 1, 'name': '哈哈哈哈', 'phonenumber': '13204033566', 'address': '海园一路1号', 'qq': '1122333'}]>
def listcustomers(request):#返回一个QuerySet对象,包含所有的表记录qs = Customer.objects.values()#检查url中是否有参数phonenumberph = 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} |'#<br>表换行retStr += '<br>'return HttpResponse(retStr)
127.0.0.1/sales/customers/?phonenumber=13204033566
前后端分离架构
格式化HTML存放数据
views.py
from django.http import HttpRequest, HttpResponse
from django.shortcuts import renderfrom common.models import Customerdef listorders(request):#返回的HTTP响应消息;消息体为...return HttpResponse('下面是系统中所有的订单信息...')html_template="""
<!DOCTYPE html>
<html lang="en">
<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表头单元格;td表格单元格<th>id</th><th>姓名</th><th>电话号码</th><th>地址</th></tr>%s</table></body>
</html>
"""def listcustomers(request):#返回一个QuerySet对象,包含所有的表记录qs = Customer.objects.values()#检查url中是否有参数phonenumberph = request.GET.get('phonenumber',None)#如果有,就添加过滤条件if ph:qs = qs.filter(phonenumber = ph)#用于生成html模板中要插入的html片段内容tableContent=''for customer in qs:#每条记录一个trtableContent += '<tr>'#name是表头,在th那里for name , value in customer.items():tableContent += f'<td>{value}</td>'tableContent += '</tr>'#% tableContent:html_template模板中的%s用% tableContent替换return HttpResponse(html_template % tableContent)
border-collapse:collapse;折叠边框和单元格
数据的增删改查
首先,创建一个应用:python manage.py startapp mgr
这是为 管理员用户 专门创建的一个应用 mgr 用于处理相关请求
mgr/customer.py
from django.http import JsonResponse import json# 导入 Customer from common.models import Customerdef 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格式# json.loads(request.body) json格式字符串变py类型对象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请求'})def listcustomers(request):# 返回一个 QuerySet 对象 ,包含所有的表记录qs = Customer.objects.values()# 将 QuerySet 对象 转化为 list 类型# 否则不能 被 转化为 JSON 字符串retlist = list(qs)return JsonResponse({'ret': 0, 'retlist': retlist})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})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})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})
mgr/urls.py
from django.urls import pathfrom mgr import customerurlpatterns =[path('customers',customer.dispatcher), ]
bysms/urls.py一级
from django.contrib import admin from django.urls import path,include from django.conf.urls.static import staticurlpatterns = [path('admin/', admin.site.urls),# #主路由表path('sales/',include('sales.urls')),path('api/mgr/', include('mgr.urls'))] + static("/",document_root="./z_dist")#到z_dist文件下找;看是否有mgr
还要注释掉settings.py取消csrf校验
# 'django.middleware.csrf.CsrfViewMiddleware',z_dist建在根目录下
对资源的增查改删处理 - 白月黑羽
列出客户信息(就是查看)
接口文档,后端需要返回的数据格式如下:
{
"ret": 0,
"retlist": [
{
"address": "江苏省常州武进市白云街44号",
"id": 1,
"name": "武进市 袁腾飞",
"phonenumber": "13886666666"
},{
"address": "北京海淀区",
"id": 4,
"name": "北京海淀区代理 蔡国庆",
"phonenumber": "13990123456"
}
]
}
# 导入 Customer 根目录是bysms
from common.models import Customerdef listcustomers(request):# 返回一个 QuerySet 对象 ,包含所有的表记录qs = Customer.objects.values()# 返回的是一个QuerySet对象,每条记录都是一个dict对象;# 将 QuerySet 对象 转化为 list 类型# 否则不能 被 转化为 JSON 字符串retlist = list(qs)#JsonResponse是HTTPResponse的子类,专门用于生成JSON格式的响应;#也就是可以自动将()内的东西自动转换成JSON格式return JsonResponse({'ret': 0, 'retlist': retlist})
添加客户信息
接口文档,前端提供的数据格式:
{
"action":"add_customer",
"data":{
"name":"武汉市桥西医院",
"phonenumber":"13345679934",
"address":"武汉市桥西医院北路"
}
}
响应内容:
{
"ret": 0,
"id" : 677
}
def addcustomer(request):#得到FormsDict对象,转化为字典,其内容包含url后的参数和值,同时也包含了body中的值,#要注意的是,它把body中所以的参数作为一个key存入了。info = request.params['data']# 从请求消息中 获取要添加客户的信息# 并且插入到数据库中# 返回值 就是对应插入记录的对象 record = Customer.objects.create(name=info['name'] ,phonenumber=info['phonenumber'] ,address=info['address'])return JsonResponse({'ret': 0, 'id':record.id})
1.Customer.objects.create
方法,添加一条Customer表里面的记录2.info['name']:
{
"name":"武汉市桥西医院",
"phonenumber":"13345679934",
"address":"武汉市桥西医院北路"
}又一个字典
3.临时取消csrf校验
新创建的项目, Django 缺省会启用一个 CSRF (跨站请求伪造) 安全防护机制。
在这种情况下, 所有的Post、PUT 类型的 请求都必须在HTTP请求头中携带用于校验的数据。
为了简单起见,我们先临时取消掉CSRF的 校验机制,等以后有需要再打开
修改客户信息
接口文档,前端提供的数据格式如下:
{
"action":"modify_customer",
"id": 6,
"newdata":{
"name":"武汉市桥北医院",
"phonenumber":"13345678888",
"address":"武汉市桥北医院北路"
}
}
响应内容:
{
"ret": 0
}
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})
删除客户信息
接口文档,前端只需要提供要删除的客户的ID
{
"action":"del_customer",
"id": 6
}
响应内容:
{
"ret": 0
}
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})
和前端集成
z_dist文件放到bysms下根目录;在bysms/urls.py文件末尾加:
+ static("/", document_root="./z_dist") #静态文件路由设置
静态文件服务声明:
from django.conf.urls.static import static
如果 http请求的url 不是以 admin/、 sales/ 、api/mgr/ 开头, 比如:http://localhost/mgr/index.html,Django 就会认为是要访问 z_dist目录下面的静态文件;
到z_dist文件下找;看是否有mgr
重启:python manage.py runserver 80
浏览器输入:http://localhost/mgr/index.html
登录
在mgr应用下新建一个sign_in_out.py文件用来处理用户登录、登出请求
sign_in_out.py
from django.http import JsonResponsefrom django.contrib.auth import authenticate, login, logout# 登录处理
def signin( request):# 从 HTTP POST 请求中获取用户名、密码参数userName = request.POST.get('username')passWord = request.POST.get('password')# 使用 Django auth 库里面的authenticate方法校验用户名、密码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})
mgr/urls.py
from django.urls import pathfrom mgr import customer,sign_in_outurlpatterns =[path('customers',customer.dispatcher),path('signin',sign_in_out.signin),path('signout',sign_in_out.signout),
]
localhost/api/mgr/signin 浏览器访问
响应内容
登录成功:
{
"ret": 0
}
登录失败,返回失败原因:
{
"ret": 1,
"msg": "用户名或者密码错误"
}
与前端集成
http://localhost/mgr/sign.html
zhao ; 12345678
前端人员还没开发好时,如何测试我们的后端系统
使用python构建http请求,使用Request库,自己看Requests库-CSDN博客这篇
建立一个tests文件,再在其下建一个tc0001.py
列出客户
请求消息
GET /api/mgr/customers?action=list_customer HTTP/1.1
请求参数
http 请求消息 url 中 需要携带如下参数,
action
填写值为 list_customer
登录系统
请求参数
http 请求消息 body 中 参数以 格式 x-www-form-urlencoded 存储
需要携带如下参数,
username
用户名
password
密码
import requests,pprint# payload = {
# 'username': 'byhy',
# 'password': '88888888'
# }# payload = {
# 'username': 'zhao',
# 'password': '12345678'
# }#看接口文档,请求消息: GET /api/mgr/customers?action=list_customer HTTP/1.1
payload = {'action':'list_customer'
}# response = requests.post('http://localhost/api/mgr/signin',
# data=payload)response = requests.get('http://localhost/api/mgr/customers',params=payload)pprint.pprint(response.json())
单独 Run 'tc0001'
pprint.pprint()用来美观地输出字典。如果字典本身包含嵌套的列表或字典,那么pprint.pprint()函数特别有用。
参考:字典中:print()函数、pprint.pprint()函数、pprint.pformat()函数的区别-CSDN博客
Session和token
校验用户是否为合法的管理员用户;对于请求消息的合法性验证,通常有两种方案:session和token
session方案是如何校验用户登录的合法性的
session表主要记录一次用户登录的相关信息(session_data);用户每登录成功一次,就会多一条session记录;一般存的是该用户的ID、姓名、登录名
session key就相当于sessionid
用户登录成功后,服务端就会自动在数据库session表里创建一条记录,记录这次会话
login(request, user)# login会在session表里产生一条数据# 往session data里写入用户类型数据 usertype=mgrrequest.session['usertype'] = 'mgr'
token方案是如何校验用户登录的合法性的
校验用户合法性
mgr/customer.py的dispatcher函数最上方
用户登录,先判断是否有session记录;通过看session data是否存在usertype判断是否有记录
如果有记录,在判断是否为管理员;
# 根据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)
怎么验证:
记得先退出登录,然后在登录页面直接访问http://localhost/mgr/index.html;
因为不携带cookie,没有session记录,预览显示302未登录
数据库表的关联
对于关系型数据库,各表间的关联关系无非就3种:一对多、一对一、多对多
PS E:\HYMS\py\django\bysms> python manage.py makemigrations common
PS E:\HYMS\py\django\bysms> python manage.py migrate
一对多
一个客户可以下多个订单
common/models.py公共数据存放;客户表删qq,加药品表、订单表
Django中用ForeignKey对象来实现一对多的关系
from django.db import models
import datetime#客户表
class Customer(models.Model):# 客户名称name = models.CharField(max_length=200)# 联系电话phonenumber = models.CharField(max_length=200)# 地址address = models.CharField(max_length=200)#药品表
class Medicine(models.Model):# 药品名name = models.CharField(max_length=200)# 药品编号sn = models.CharField(max_length=200)# 描述desc = models.CharField(max_length=200)#订单表
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 = models.ForeignKey(Customer,on_delete=models.PROTECT)
#参1:关联Customer这张表
#参2:on_delete参数:指定了当删除外键指向的主键记录时,系统的行为
#CASCADE: 删除主键记录和相应的外键表记录(一个客户有多条订单;删一个客户,对应的那几条订单记录也被删除)
#PROTECT: 禁止删除记录(这里就是禁止删除客户记录和相关的订单记录)
#SET_NULL:删除主键记录;并且将外键记录中外键字段的值置为null;前提是外键字段要设置为值允许是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中用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')# 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()
药品管理
#处理客户端发来的 列出药品、添加药品、修改药品、删除药品的请求
from django.http import JsonResponse# 导入 Medicine 对象定义
from common.models import Medicineimport jsondef 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})
path('medicines',medicine.dispatcher),
ORM是怎样对关联表进行操作的
common/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 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)
删除多条数据记录
students = Student.objects.all()
students.delete()countrys = Country.objects.all()
countrys.delete()
删除单条数据记录
>>> students=Student.object.get(id=1)
>>> students.delete()
通过对象访问它所关联的外键表中的数据
>>> s1 = Student.objects.get(name='白月')
>>> s1.country.name
外键关联的访问用.(s1.country也是个对象)
根据外键表数据过滤
首先,查找Student表中所有一年级学生
Student.objects.filter(grade=1).values()
然后,查找Student表中所有一年级的中国学生
思路:先找到国家表中国对应的id是多少,再在学生表找id对应
>>> cn = Country.objects.get(name='中国')
>>> Student.objects.filter(grade=1,country_id=cn.id).values()
法二
>>> Student.objects.filter(grade=1,country__name='中国').values()
__表示外键字段;找外键字段country表里name = '中国'
如果返回结果只需要两个字段 “学生姓名” 、“国家名”,可以指定values内容
Student.objects.filter(grade=1,country__name='中国').values('name','country__name')
给表字段起别名
from django.db.models import F
# annotate 可以将表字段进行别名处理
Student.objects.annotate(
countryname=F('country__name'),
studentname=F('name')
)\
.filter(grade=1,countryname='中国').values('studentname','countryname')
反向访问
访问所有属于中国的学生
>>> cn = Country.objects.get(name='中国')
>>> cn.student_set.all()
通过表Model名转化为小写,后面加_set来获取所有的反向外键关联对象
<QuerySet [<Student: Student object (1)>, <Student: Student object (2)>, <Student: Student object (3)>, <Student: Student object (4)>]>
>>> cn.student_set.all()[0].name #.对象操作
'白月'
法二: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找出来;再去国家表根据国家id过滤
# 先获取所有的一年级学生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(student__grade=1).values().distinct()
反向关联;表名转化为小写,反向关联student表的grade;
法二: Country.objects.filter(students__grade=1).values().distinct()
定义表时,用related_name='students'指定反向关联名称students;(没指明关联名,就使用表名小写)
ORM处理关联表
添加一个订单
{
"action":"add_order",
"data":{
"name":"华山医院订单002",
"customerid":3,
"medicineids":[1,2] #订单中药品的id 列表
}
}
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,OrderMedicineimport jsondef 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)if action == 'add_order':return addorder(request)# 订单 暂 不支持修改 和删除else:return JsonResponse({'ret': 1, 'msg': '不支持该类型http请求'})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})
path('orders',order.dispatcher),