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),
列出所有订单
相关推荐
云和数据.ChenGuang1 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
yaosheng_VALVE13 小时前
探究全金属硬密封蝶阀的奥秘-耀圣控制
运维·eclipse·自动化·pyqt·1024程序员节
dami_king13 小时前
SSH特性|组成|SSH是什么?
运维·ssh·1024程序员节
LuiChun18 小时前
Django 模板分割及多语言支持案例【需求文档】-->【实现方案】
数据库·django·sqlite
凡人的AI工具箱18 小时前
每天40分玩转Django:Django管理界面
开发语言·数据库·后端·python·django
中科院提名者18 小时前
Django连接mysql数据库报错ModuleNotFoundError: No module named ‘MySQLdb‘
数据库·mysql·django
碧水澜庭18 小时前
django中cookie与session的使用
python·django
鬼义II虎神18 小时前
将Minio设置为Django的默认Storage(django-storages)
python·django·minio·django-storages
大霸王龙19 小时前
在 Django 中使用 SMTP 发送邮件是一个常见的需求
数据库·django·sqlite
凡人的AI工具箱1 天前
每天40分玩转Django:Django测试
数据库·人工智能·后端·python·django·sqlite