10 数据库表的关联

  • 常见的三种关联关系:一对多一对一多对多
  • 一对多
    • 一对多的关系,就是外键关联关系
    • 定义药品(Medicine)表,包括药品名称、编号和描述
    • 定义订单表(Order),包括创建日期、客户、药品、数量,客户字段对应的客户只能是Customer中的某个客户记录
    • Order表里面的一条订单记录的客户,对应Customer表里面的一条客户记录一个客户记录可以对应多条订单记录,这就是一对多的关系
    • 像这种一对多的关系,数据库中是用外键来表示的
    • 如果一个表中的某个字段是外键,那就意味着这个外键字段的记录的取值,只能是它关联表某个记录的主键的值
    • 定义表的Model类的时候,如果没有指定主键字段migrate的时候django会为该Model对应的数据库表自动生成一个id字段,作为主键,比如Customer和Medicine
    • 定义订单表Order客户字段就应该是一个外键,对应Customer表的主键,也就是id字段
    • django中定义外键的方法就是Model类该属性字段值ForenignKey对象
    •  customer = models.ForeignKey(Customer,on_delete=models.PROTECT) :customer字段是外键,指向Customer类,也就是Order表的customer字段指向Customer表的主键的一个外键,
    • on_delete指定了当我们想删除外键指向的主键记录时,系统的行为
    • CASCADE:删除主键记录和相应的外键表记录
    • PROTECT:禁止删除记录(除非是删除了Order表中所有跟当前要删除的Customer记录的数据
    • SET_NULL:删除主键记录,并且将外键记录中的外键字段的值置为null(前提是外键字段要设置为值允许为null)
    • 外键字段实际在数据库表中的字段名:django ForeignKey定义的字段名 + 后缀_id(customer_id
    •  1 # common.models
       2 from django.db import models
       3 import datetime
       4 
       5 
       6 class Customer(models.Model):
       7     # 客户名称
       8     name = models.CharField(max_length=200)
       9 
      10     # 联系电话
      11     phonenumber = models.CharField(max_length=200)
      12 
      13     # 地址
      14     address = models.CharField(max_length=200)
      15 
      16 
      17 class Medicine(models.Model):
      18     # 药品名
      19     name = models.CharField(max_length=200)
      20     # 药品编号
      21     sn = models.CharField(max_length=200)
      22     # 描述
      23     desc = models.CharField(max_length=200)
      24 
      25 
      26 class Order(models.Model):
      27     # 订单名
      28     name = models.CharField(max_length=200, null=True, blank=True)
      29 
      30     # 创建日期
      31     create_date = models.DateTimeField(default=datetime.datetime.now)
      32 
      33     # 客户
      34     customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
    • 执行python manage.py makemigrations commonpython manage.py migrate common
  • 一对一
    • django通过OneToOneField实现一对一的关系
    • django发现OneToOneField后,它会在migrate的时候,在数据库中定义该字段为外键的同时,加上unique=True约束,表示在外键的表中,该字段取值必须唯一,不能重复。
  • 多对多
    • BYSMS系统中,一个订单可以采购多种药品,就对应Medicine表里面的多种药品;一种药品也可以被多个订单采购。Order表和Medicine表之间就形成了多对多的关系
    •  medicines = models.ManyToManyField(Medicine, through='OrderMedicine') :指定Order表和Medicine表多对多的关系,其实Order表中并不会产生一个叫medicines的字段
    • Order表和Medicine表多对多的关系是通过另外一张表,也就是through参数指定的OrderMedicine表来确定的
    • migrate的时候,django会自动产生一张新表(common_ordermedicine)来实现Order表和Medicine表多对多的关系
    •  python manage.py makemigrations common python manage.py migrate common #执行这两行命令 
    •  1 # common.models.py
       2 from django.db import models
       3 import datetime
       4 
       5 
       6 class Customer(models.Model):
       7     # 客户名称
       8     name = models.CharField(max_length=200)
       9 
      10     # 联系电话
      11     phonenumber = models.CharField(max_length=200)
      12 
      13     # 地址
      14     address = models.CharField(max_length=200)
      15 
      16 
      17 class Medicine(models.Model):
      18     # 药品名
      19     name = models.CharField(max_length=200)
      20     # 药品编号
      21     sn = models.CharField(max_length=200)
      22     # 描述
      23     desc = models.CharField(max_length=200)
      24 
      25 
      26 class Order(models.Model):
      27     # 订单名
      28     name = models.CharField(max_length=200, null=True, blank=True)
      29 
      30     # 创建日期
      31     create_date = models.DateTimeField(default=datetime.datetime.now)
      32 
      33     # 客户
      34     customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
      35 
      36     # 订单购买的药品,如果没有额外的字段amount的话througn='OrderMedicine'是不需要指定的,django会为我们自动生成
        
      37 medicines = models.ManyToManyField(Medicine, through='OrderMedicine') 38 39 40 class OrderMedicine(models.Model): 41 order = models.ForeignKey(Order, on_delete=models.PROTECT) 42 medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT) 43 44 # 订单中药品的数量 45 amount = models.PositiveIntegerField()
  • 实现代码
    • mgr目录下创建medicine.py
    •  1 # bysms.urls.py
       2 from django.contrib import admin
       3 from django.urls import path, include
       4 # 静态文件服务声明
       5 from django.conf.urls.static import static
       6 
       7 urlpatterns = [
       8                   path('admin/', admin.site.urls),
       9                   # 全路由
      10                   # path('sales/orders/', list_orders),
      11                   # 路由子表
      12                   path('sales/', include('sales.urls')),
      13                   path('api/mgr/', include('mgr.urls'))
      14               ] + static('/', document_root='./z_dist')
    •  1 #mgr.urls.py
       2 from django.urls import path
       3 from mgr import customer, sign_in_out,medicine
       4 
       5 urlpatterns = [
       6     path('customers', customer.dispatcher),
       7     path('medicines', medicine.dispatcher),
       8     path('signin', sign_in_out.signin),
       9     path('signout', sign_in_out.signout),
      10 ]
    •   1 # mgr.medicine.py
        2 import json
        3 
        4 from django.http import JsonResponse
        5 
        6 from common.models import Medicine
        7 
        8 
        9 def mgr_login_required(view_func):
       10     def wrapper(request, *args, **kwargs):
       11         if 'usertype' not in request.session:
       12             return JsonResponse({
       13                 'ret': 302,
       14                 'msg': '未登录',
       15                 'redirect': '/mgr/sign.html'
       16             }, status=302)
       17 
       18         if request.session['usertype'] != 'mgr':
       19             return JsonResponse({
       20                 'ret': 302,
       21                 'msg': '用户非mgr类型',
       22                 'redirect': '/mgr/sign.html'
       23             }, status=302)
       24 
       25         return view_func(request, *args, **kwargs)
       26 
       27     return wrapper
       28 
       29 
       30 @mgr_login_required
       31 def dispatcher(request):
       32     if request.method == 'GET':
       33         request.params = request.GET
       34 
       35     elif request.method in ['POST', 'PUT', 'DELETE']:
       36         request.params = json.loads(request.body)
       37 
       38     action = request.params['action']
       39     if action == 'list_medicine':
       40         return listmedicines(request)
       41     elif action == 'add_medicine':
       42         return addmedicine(request)
       43     elif action == 'modify_medicine':
       44         return modifymedicine(request)
       45     elif action == 'del_medicine':
       46         return deletemedicine(request)
       47 
       48     else:
       49         return JsonResponse({'ret': 1, 'msg': '不支持该类型http请求'})
       50 
       51 
       52 def listmedicines(request):
       53     qs = Medicine.objects.values()
       54 
       55     retlist = list(qs)
       56 
       57     return JsonResponse({'ret': 0, 'retlist': retlist})
       58 
       59 
       60 def addmedicine(request):
       61     info = request.params['data']
       62     record = Medicine.objects.create(desc=info['desc'], name=info['name'], sn=info['sn'])
       63 
       64     return JsonResponse({
       65         "ret": 0,
       66         "id": record.id
       67     })
       68 
       69 
       70 def modifymedicine(request):
       71     medicineid = request.params['id']
       72     newdata = request.params['newdata']
       73 
       74     try:
       75         # 根据id 从数据库中找到相应的客户记录
       76         medicine = Medicine.objects.get(id=medicineid)
       77     except Medicine.DoesNotExist:
       78         return {
       79             'ret': 1,
       80             'msg': f'id为`{medicineid}`的客户不存在'
       81         }
       82 
       83     if 'name' in newdata:
       84         medicine.name = newdata['name']
       85 
       86     if 'desc' in newdata:
       87         medicine.desc = newdata['desc']
       88 
       89     if 'sn' in newdata:
       90         medicine.address = newdata['sn']
       91 
       92     # 注意,一定要执行save才能将修改的信息保存到数据库中
       93     medicine.save()
       94 
       95     return JsonResponse({'ret': 0})
       96 
       97 
       98 def deletemedicine(request):
       99     medicineid = request.params['id']
      100 
      101     try:
      102         medicine = Medicine.objects.get(id=medicineid)
      103     except Medicine.DoesNotExist:
      104         return {
      105             'ret': 1,
      106             'msg': f'id 为`{medicineid}` 的客户不存在'
      107         }
      108 
      109     # delete 方法就将该记录从数据库中删除了
      110     medicine.delete()
      111     return JsonResponse({'ret': 0})
posted @ 2025-12-07 15:06  理想赵雷  阅读(8)  评论(0)    收藏  举报