Django

安装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),
   
]

view.py

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)
创建数据库表

settings.py

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 重启

http://127.0.0.1/admin

读取数据库中的数据

功能: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存放数据

views.py

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

python 复制代码
from 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

python 复制代码
from django.urls import path

from mgr import customer

urlpatterns =[
    path('customers',customer.dispatcher),
]

bysms/urls.py一级

python 复制代码
from 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),
列出所有订单
相关推荐
blues_C2 天前
十三、【核心功能篇】测试计划管理:组织和编排测试用例
vue.js·django·测试用例·drf·测试平台
恸流失2 天前
DJango项目
后端·python·django
编程大全3 天前
41道Django高频题整理(附答案背诵版)
数据库·django·sqlite
网安小张3 天前
解锁FastAPI与MongoDB聚合管道的性能奥秘
数据库·python·django
KENYCHEN奉孝3 天前
Pandas和Django的示例Demo
python·django·pandas
老胖闲聊3 天前
Python Django完整教程与代码示例
数据库·python·django
noravinsc3 天前
django paramiko 跳转登录
后端·python·django
践行见远3 天前
django之请求处理过程分析
数据库·django·sqlite
声声codeGrandMaster3 天前
Django之表格上传
后端·python·django
菌菌的快乐生活3 天前
网站静态文件加速-Django项目静态文件存储到腾讯云COS存储提升网络请求速度
django·cos存储