首页 > 编程语言 >Python 框架学习 Django篇 (六) 数据表关联、ORM关联

Python 框架学习 Django篇 (六) 数据表关联、ORM关联

时间:2023-10-28 10:06:08浏览次数:39  
标签:name Python request 药品 关联 数据表 models medicine id


在后端服务器开发中,特别是前后端分离的架构中数据库是非常重要的,后端主要就是负责管理数据,而我们经常使用的mysql、oracle 都是关系型数据库,什么是关系型数据库?就是建立在关系模型基础上的数据库,而最难处理的就是各个表之间的关联关系,一般这种关系分为三种: 一对一 、一对多、多对多

 一、数据表关联

1、一对多

表之间以对多的关系就是数据库中的 "外键"  ,下面我们举个例子,比如一个医药系统中肯定会有客户的信息吧,我们先定义一个客户的基本信息(客户名称、联系电话、居住地址)

  vi Django_demo/paas/models.py

class Customer(models.Model):
    # 客户名称
    name = models.CharField(max_length=200)

    # 联系电话
    phonenumber = models.CharField(max_length=200)

    # 地址
    address = models.CharField(max_length=200)

我们是一个医药系统,肯定存在很多不同的药品类型,同样也需要定义一个药品类型的表

Medicine药品表 ,包含一些(药品名称、编号、描述信息)

  vi Django_demo/paas/models.py

class Medicine(models.Model):
    # 药品名
    name = models.CharField(max_length=200)
    # 药品编号
    sn = models.CharField(max_length=200)
    # 描述
    desc = models.CharField(max_length=200)

有了药品信息、客户信息,那么只要存在销售的话就一定会有订单信息


想一想,我们订单的信息是不是和上面的两张表多少有一些关联,比如订单中需要用到客户信息和药品信息


在实际观察中,我们发现订单表里面会同时需要拿到上面两张表中的数据,在下图中我们可以看到一个客户同时可能会有多个订单,这种情况就是一对多,或者说多对一

 

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_字段

像是这种一对多的关系,在数据库中是以外键形式表示的,如果说一个表中的字段是外键,那么他的值一定来源与其他表的主键


另外,我们定义表的 Model类的时候,如果没有指定主键字段,migrate 的时候 Django 会为该Model对应的数据库表自动生成一个id字段,作为主键

#导入数据库
python manage.py makemigrations
python manage.py migrate 

#查看
desc paas_customer;

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_ci_02

现在我们要生成订单表,按照实际情况我们订单表的字段里面也会有客户的信息表示谁下的订单,而用户的信息需要使用外键去关联客户的主键,而客户表也就是customer表的主键就是id字段,Django中定义外键 的方法就是 Model类的该属性字段 值为(ForeignKey)

 vi Django_demo/paas/models.py

import datetime
class Order(models.Model):
    # 订单名
    name = models.CharField(max_length=200,null=True,blank=True)

    # 创建日期
    create_date = models.DateTimeField(default=datetime.datetime.now)

    # 客户
    customer = models.ForeignKey(Customer,on_delete=models.PROTECT)

上面定义的customer是外键,让他去找Customer表的主键获取数据,而这里设置了一个on_delete的参数,这个意思是当主键被删除了那么外键这个数据还要不要了

1、CASCADE: 跟随主机一起把外键数据删除

2、PROTECT   禁止删除,如果非要删除就先清除外键数据后,才能删除对应主键

3、SET_NULL   删除后外键数据修改为null

注意

      外键字段,实际在数据库表中的字段名是DjangoForeignKey定义字段名加上后缀"_id"

比如上面,在执行了 migrate 命令更新数据库后,customer 这个外键字段实际上在 数据库表中的字段名 是 customer_id

python manage.py makemigrations
python manage.py migrate 

#查看
desc paas_info;

返回

mysql> desc paas_order;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | bigint       | NO   | PRI | NULL    | auto_increment |
| name        | varchar(200) | YES  |     | NULL    |                |
| create_date | datetime(6)  | NO   |     | NULL    |                |
| customer_id | bigint       | NO   | MUL | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_ci_03

2、一对一

上面的外键案例,可以说是一对多或者多对一,而有时候是一对一的情况

比如,某个学校的学生表 和学生的地址表,就形成一对一的关系,即 一条主键所在表的记录 只能对应一条 外键所在表的记录,而Django 中 用 OneToOneField 对象 实现 一对一 的关系

 vi Django_demo/paas/models.py

class Student(models.Model):
    # 姓名
    name = models.CharField(max_length=200)
    # 班级
    classname = models.CharField(max_length=200)
    # 描述
    desc = models.CharField(max_length=200)


class ContactAddress(models.Model):
    # 一对一 对应学生 
    student = models.OneToOneField(Student, on_delete=models.PROTECT)
    # 家庭
    homeaddress = models.CharField(max_length=200)
    # 电话号码
    phone = models.CharField(max_length=200)

 Django发现这样一对一定定义,它会在migrate的时候,在数据库中定义该字段为外键的同时, 加上 unique=True 约束,表示在此表中,所有记录的该字段 取值必须唯一,不能重复

 3、多对多

数据库中还存在一种多对多的关系,在order订单表中


一个订单可以采购多种药品,就对应 Medicine表里面的多种药品;


而一种药品也可以被多个订单采购, 那么Order表 和 Medicine表 之间就形成了多对多的关系

 

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_外键_04

 Django是通过 ManyToManyField 对象 表示 多对多的关系的

 vi Django_demo/paas/models.py

import datetime
class Order(models.Model):
    # 订单名
    name = models.CharField(max_length=200,null=True,blank=True)

    # 创建日期
    create_date = models.DateTimeField(default=datetime.datetime.now)

    # 客户
    customer = models.ForeignKey(Customer,on_delete=models.PROTECT)

    # 订单购买的药品,和Medicine表是多对多 的关系
    medicines = models.ManyToManyField(Medicine, through='OrderMedicine')

class OrderMedicine(models.Model):
    #添加外键
    order = models.ForeignKey(Order, on_delete=models.PROTECT)
    medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT)

    # 订单中药品的数量  一种特殊的类型,表示非负整数
    amount = models.PositiveIntegerField()

我们上面通过medicines = models.ManyToManyField(Medicine, through='OrderMedicine')


去指定Order表和Medicine表的对应关系,其实不会在Order表上面创建medicines的字段

python manage.py makemigrations
python manage.py migrate 

#查看
desc paas_OrderMedicine;

 

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_学习_05

4、管理药品实现

我们在 mgr 目录下面新建 medicine.py,处理 客户端发过来的 列出药品、添加药品、修改药品、删除药品 的请求,需要运用前面的数据库增删改查的方法

vi Django_demo/mgr/medicine.py

from django.http import JsonResponse

# 导入 Medicine 对象定义(这块可能显示模块导入不正常,忽略)
from  paas.models import  Medicine

import json

def Orderdispatcher(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})

添加路由

vi Django_demo/mgr/urls.py

from django.urls import path

from .k8s import dispatcher
from .sign_in_out import signin,signout

from .medicine import orderdispatcher  #添加
urlpatterns = [
    path('customers/', dispatcher),
    path('medicines/', orderdispatcher),  #添加 必须带斜杠

    path('signin', signin),
    path('signout', signout),


]

5、添加药品

vi main.py

import  requests,pprint

#添加认证
payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')




# 构建添加 客户信息的 消息体,是json格式
payload = {
    "action":"add_medicine",
    "data":{
        "name":"板蓝根",
        "sn":"133",
        "desc":"感冒药"
    }
}
url='http://127.0.0.1:8000/api/mgr/medicines/'
if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送请求给web服务
    response = requests.post(url,json=payload,headers=headers)
    pprint.pprint(response.json())

json类型说明

刚才上面我们使用了查询和添加数据,但是发现一个问题,两个请求传参的时候稍有不同

#data=payload  表示这个请求携带的参数是以表单的形式也就是字符串形式传输给后端的
requests.post(url,data=payload)


#json=payload   表示参数是以json的形式传输给后端的
requests.post(url,json=payload)

在使用时要特别注意,我卡了半天才看到。。

6、查询药品

vi main.py

import  requests,pprint

payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')
if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送带有Cookie的新请求 修改url到新的路由
    response = requests.get('http://127.0.0.1:8000/api/mgr/medicines/?action=list_medicine',headers=headers)
    pprint.pprint(response.json())

返回

{'ret': 0,
 'retlist': [{'desc': '192.168.1.2', 'id': 1, 'name': 'abc', 'sn': '133'},
             {'desc': '感冒药', 'id': 2, 'name': '板蓝根', 'sn': '133'}]}

第一行是我写错了添加上的,一会当作删除的案例

遇到的问题

在访问url的时候,要确定url访问时是否需要带上/  如果定义的urls上有/,那边必须要带上斜杠不然会报错

7、修改药品

vi main.py

import  requests,pprint

#添加认证
payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')




# 构建添加 客户信息的 消息体,是json格式
payload = {
    "action":"modify_medicine",
    "id": "1",
    "newdata":{
        "name":"诺氟沙星",
        "sn":"141",
        "desc":"无"
    }
}
url='http://127.0.0.1:8000/api/mgr/medicines/'

if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送请求给web服务
    response = requests.post(url,json=payload,headers=headers)
    pprint.pprint(response.json())

再次查询

{'ret': 0,
 'retlist': [{'desc': '无', 'id': 1, 'name': '诺氟沙星', 'sn': '141'},
             {'desc': '感冒药', 'id': 2, 'name': '板蓝根', 'sn': '133'}]}

8、删除药品

import  requests,pprint

#添加认证
payload = {
    'username': 'root',
    'password': '12345678'
}
#发送登录请求
response = requests.post('http://127.0.0.1:8000/api/mgr/signin',data=payload)
#拿到请求中的认证信息进行访问
set_cookie = response.headers.get('Set-Cookie')




# 构建添加 客户信息的 消息体,是json格式
payload = {
    "action":"del_medicine",
    "id":"1",
}
url='http://127.0.0.1:8000/api/mgr/medicines/'

if set_cookie:
    # 将Set-Cookie字段的值添加到请求头中
    headers = {'Cookie': set_cookie}

    # 发送请求给web服务
    response = requests.post(url,json=payload,headers=headers)
    pprint.pprint(response.json())

 返回

{'ret': 0, 'retlist': [{'desc': '感冒药', 'id': 2, 'name': '板蓝根', 'sn': '133'}]}

可以看到除了查询以外,增加、修改、删除的操作基本是一致的,只需要修改携带参数中的动作以及传入的参数值即可

二、数据库关联操作(sql)

1、一对多

#先查询用户的id,然后基于id查询外键对应的订单
select * from paas_order where customer_id = (select id from paas_customer where name = "zhangsan");

一对多,我们查询指定的一个客户id,然后基于id去订单表中获取所以用户相关的订单

2、多对多

我们上面使用的时候添加过这么一个表  OrderMedicine 

class OrderMedicine(models.Model):
    #添加外键
    order = models.ForeignKey(Order, on_delete=models.PROTECT)
    medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT)

    # 订单中药品的数量  一种特殊的类型,表示非负整数
    amount = models.PositiveIntegerField()

多对多,表示什么意思呢,我们建立的上面的表是将order订单表 和Medicine药品表进行关联的一个中间表,我们在给前面两张表添加数据的时候,还需要单独去给中间表添加一次数据,用来声明订单和药品的关系,通过这张中间表,我们就能查询药品是那些客户进行购买,也可以查询那些客户购买了那些药品,我们做一个案例

 Django_demo/mgr/admin.py

from  paas.models import Customer,Medicine,Order,OrderMedicine
admin.site.register([Customer,Medicine,Order,OrderMedicine])

 访问admin页面,前面我们添加了很多的数据除了客户表信息以外都先删除一下

 

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_学习_06

我们先给Medicines药品表  和orders 订单表 添加一条信息

 

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_ci_07

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_学习_08

上面给药品添加了感冒颗粒,订单表中给张三用户添加了一个test的订单 ,现在是没有任何关联机制的,这两张表也没有交互,我们在order medicines表中添加下两个订单的关联

Python 框架学习 Django篇 (六) 数据表关联、ORM关联_学习_09

 我们关联了第一条数据,将刚才的订单信息和药品信息以及数量一并放入到了中间表中

mysql> select * from paas_ordermedicine;
+----+--------+-------------+----------+
| id | amount | medicine_id | order_id |
+----+--------+-------------+----------+
|  1 |     10 |           6 |        5 |
+----+--------+-------------+----------+
1 row in set (0.00 sec)

 这里因为存放了药品的id和订单的id,我们就可以根据这个表来查询关联的数据信息,比如我想要看看订单表里面test订单对应下单了什么药品,买了多少

#找到订单中的id
select id from paas_order where name = "test";


#基于id查询关系表中药品
select medicine_id,amount  from paas_ordermedicine where order_id = 5;


#命令组合
mysql> select medicine_id,amount  from paas_ordermedicine where order_id = (select id from paas_order where name = "test");
+-------------+--------+
| medicine_id | amount |
+-------------+--------+
|           6 |     10 |
+-------------+--------+
1 row in set (0.00 sec)

标签:name,Python,request,药品,关联,数据表,models,medicine,id
From: https://blog.51cto.com/u_14205795/8065007

相关文章

  • Python 框架学习 Django篇 (六) ORM关联
    像是上一章我们很少会通过页面点击去添加和绑定关系表,更多的时候都是通过django的语法实现,接下来我们做一个案例djangorom是怎么操作外键关系的创建mode模型表Django_demo/mgr/models.py#国家表classCountry(models.Model):name=models.CharField(max_length=100)#......
  • python题目:使用lambda来创建匿名函数
    实例#!/usr/bin/python#-*-coding:UTF-8-*-MAXIMUM=lambdax,y:(x>y)*x+(x<y)*yMINIMUM=lambdax,y:(x>y)*y+(x<y)*xif__name__=='__main__':a=10b=20print('Thelargaroneis%d'%MA......
  • python 题目:数字比较。
    实例#!/usr/bin/python#-*-coding:UTF-8-*- if __name__ == '__main__':  i = 10  j = 20   if i > j:     print ('%d大于%d' % (i,j))   elif i == j:     print ('%d等于%d' % (i,j))   elif i < j:  ......
  • Python 函数
    函数当编写的代码出现有规律的重复时,这个时候就要考虑定义函数,将这些代码提取定义成一个函数,方便调用。Python提供许多内置函数,可以根据需要调用相应的函数实现想要的功能。同样Python也能够灵活地自定义函数。调用函数介绍如何定义函数前,先讲下如何调用函数。Python提供许多内......
  • Python时间序列分析库介绍:statsmodels、tslearn、tssearch、tsfresh
    时间序列分析在金融和医疗保健等领域至关重要,在这些领域,理解随时间变化的数据模式至关重要。在本文中,我们将介绍四个主要的Python库——statmodels、tslearn、tssearch和tsfresh——每个库都针对时间序列分析的不同方面进行了定制。这些库为从预测到模式识别的任务提供了强大的工......
  • python123 第二章:我的读书笔记
    print("后四位学号:3114")print("\n03")#03运行超市抹零结账行为‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪......
  • [Python急救站]草莓熊的绘制
    草莓熊也是一个热门的图案,今天就用Pythonimportturtleast#设置背景颜色,窗口位置以及大小t.colormode(255)#颜色模式t.speed(0)t.screensize(850,760)t.setup(width=850,height=760,startx=None,starty=None)#绘图窗口的大小和起始坐标t.resizemode('nores......
  • Python 利用pandas和mysql-connector获取Excel数据写入到MySQL数据库
    如何将Excel数据插入到MySQL数据库中在实际应用中,我们可能需要将Excel表格中的数据导入到MySQL数据库中,以便于进行进一步的数据分析和处理。本文将介绍如何使用Python将Excel表格中的数据插入到MySQL数据库中。导入必要的库首先,我们需要导入pandas库和MySQLConnector/Python库......
  • Python 中多态性的示例和类的继承多态性
    单词"多态"意味着"多种形式",在编程中,它指的是具有相同名称的方法/函数/操作符,可以在许多不同的对象或类上执行。函数多态性一个示例是Python中的len()函数,它可以用于不同的对象。字符串对于字符串,len()返回字符的数量:示例x="HelloWorld!"print(len(x))元组......
  • Python根据列表在指定目录寻找对应前缀的文件
    现在有一个txt列表,里面包含的是一些文件名,如a,b等等,现在需求是在一个多级文件夹下,需要寻找以a为名字的任何格式文件,如a.001,a.002等等,寻找这个txt列表里包含的文件名的对应文件,复制到指定文件夹下importosimportshutil#读取文件名列表withopen('msg.txt','r')asfile:......