安装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
python
from django.contrib import admin
from django.urls import path,include
from sales.views import listorders
urlpatterns = [
path('admin/', admin.site.urls),
path('sales/orders/',listorders),
]
python
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
def listorders(request):
#返回的HTTP响应消息;消息体为...
return HttpResponse('下面是系统中所有的订单信息...')
一级路由二级路由
一级路由bysms/urls.py
python
from django.contrib import admin
from django.urls import path,include
from sales.views import listorders
urlpatterns = [
path('admin/', admin.site.urls),
# #主路由表
path('sales/',include('sales.urls'))
]
二级路由sales/urls.py
python
from django.urls import path
from sales.views import listorders
urlpatterns =[
#二级路由表
path('orders/',listorders)
]
创建数据库
这里使用的是数据库sqlite
bysms/settings.py
python
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
python
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)
#qq
qq = models.CharField(max_length=30,null=True,blank=True)
创建数据库表
python
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才会知道
python
from django.contrib import admin
from .models import Customer
admin.site.register(Customer)
python manage.py runserver 0.0.0.0:80 重启
读取数据库中的数据
功能:127.0.0.1/sales/customers/ 服务端返回系统中所有的客户记录(customer表中所有记录) 给浏览器
sales/view.py
python
#导入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} |'
#<br>表换行
retStr += '<br>'
return HttpResponse(retStr)
二级路由表 sales/urls.py
python
path('customers/', listcustomers)
过滤条件
增加以下三行代码
python
#检查url中是否有参数phonenumber
ph = 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'}]>
python
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} |'
#<br>表换行
retStr += '<br>'
return HttpResponse(retStr)
127.0.0.1/sales/customers/?phonenumber=13204033566
前后端分离架构
格式化HTML存放数据
python
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
from common.models import Customer
def 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中是否有参数phonenumber
ph = request.GET.get('phonenumber',None)
#如果有,就添加过滤条件
if ph:
qs = qs.filter(phonenumber = ph)
#用于生成html模板中要插入的html片段内容
tableContent=''
for customer in qs:
#每条记录一个tr
tableContent += '<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
pythonfrom django.http import JsonResponse import json # 导入 Customer from common.models import Customer 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格式 # 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
pythonfrom django.urls import path from mgr import customer urlpatterns =[ path('customers',customer.dispatcher), ]
bysms/urls.py一级
pythonfrom django.contrib import admin from django.urls import path,include from django.conf.urls.static import static urlpatterns = [ 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"
}
]
}
python
# 导入 Customer 根目录是bysms
from common.models import Customer
def 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
}
python
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
}
python
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
}
python
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
python
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 库里面的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
python
from django.urls import path
from mgr import customer,sign_in_out
urlpatterns =[
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
密码
python
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表里创建一条记录,记录这次会话
python
login(request, user)
# login会在session表里产生一条数据
# 往session data里写入用户类型数据 usertype=mgr
request.session['usertype'] = 'mgr'
token方案是如何校验用户登录的合法性的
校验用户合法性
mgr/customer.py的dispatcher函数最上方
用户登录,先判断是否有session记录;通过看session data是否存在usertype判断是否有记录
如果有记录,在判断是否为管理员;
python
# 根据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对象来实现一对多的关系
python
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对象来实现一对一的关系
python
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对象来实现多对多的关系
python
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()
药品管理
python
#处理客户端发来的 列出药品、添加药品、修改药品、删除药品的请求
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})
python
path('medicines',medicine.dispatcher),
ORM是怎样对关联表进行操作的
common/models.py
一对多
python
# 国家表
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的运行环境
命令行输入代码:
python
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参数指定反向访问的名字
python
# 国家表
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
cn = Country.objects.get(name='中国')
cn.students.all()
反向过滤
获取所有一年级学生的国家名
思路:先去学生表,把所有一年级学生对应的国家的id找出来;再去国家表根据国家id过滤
python
# 先获取所有的一年级学生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
python
#处理客户端发来的 列出订单、添加订单的请求
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)
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})
python
path('orders',order.dispatcher),