• 数据库开发-Django ORM的多对多查询


                  数据库开发-Django ORM的多对多查询

                                          作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

    一.联合主键问题 

    CREATE TABLE `employees` (
      `emp_no` int(11) NOT NULL,
      `birth_date` date NOT NULL,
      `first_name` varchar(14) NOT NULL,
      `last_name` varchar(16) NOT NULL,
      `gender` smallint(6) NOT NULL DEFAULT '1' COMMENT 'M=1, F=2',
      `hire_date` date NOT NULL,
      PRIMARY KEY (`emp_no`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    CREATE TABLE `departments` (
      `dept_no` char(4) NOT NULL,
      `dept_name` varchar(40) NOT NULL,
      PRIMARY KEY (`dept_no`),
      UNIQUE KEY `dept_name` (`dept_name`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    CREATE TABLE `dept_emp` (
      `emp_no` int(11) NOT NULL,
      `dept_no` char(4) NOT NULL,
      `from_date` date NOT NULL,
      `to_date` date NOT NULL,
      PRIMARY KEY (`emp_no`,`dept_no`),
      KEY `dept_no` (`dept_no`),
      CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees`
    (`emp_no`) ON DELETE CASCADE,
      CONSTRAINT `dept_emp_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `departments`
    (`dept_no`) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    多对多建表语句
    SQLAlchemy提供了联合主键支持,但是Django至今都没有支持。 
    
    Django只支持单一主键,这也是我提倡的。但对于本次基于Django测试的表就只能增加一个单一主键了。具体原因,请参看 https://code.djangoproject.com/wiki/MultipleColumnPrimaryKeys 。
    
    Django 到目前为止也没有提供这种Composite primary key Django不能直接添加自己的2个字段的联合主键,我们手动为表创建一个自增id主键。操作顺序如下:
      1. 取消表所有联合主键,并删除所有外键约束后保存,成功再继续
      2. 为表增加一个id字段,自增、主键。保存,如果成功,它会自动填充数据 
      3. 重建原来的外键约束即可

    二.构建模型

     1 from django.db import models
     2 
     3 # Create your models here.
     4 from django.db import models
     5 
     6 class Employee(models.Model):
     7    class Meta:
     8        db_table = 'employees'
     9 
    10    emp_no = models.IntegerField(primary_key=True)
    11    birth_date = models.DateField(null=False)
    12    first_name = models.CharField(null=False, max_length=14)
    13    last_name = models.CharField(null=False, max_length=16)
    14    gender = models.SmallIntegerField(null=False)
    15    hire_date = models.DateField(null=False)
    16 
    17    def __repr__(self):
    18        return "<Employee: {} {} {}>".format(
    19            self.emp_no,
    20            self.first_name,
    21            self.last_name
    22        )
    23 
    24    __str__ = __repr__
    25  
    26 
    27 class Department(models.Model):
    28     class Meta:
    29         db_table = 'departments'
    30 
    31     dept_no = models.CharField(primary_key=True, max_length=4)
    32     dept_name = models.CharField(max_length=40, null=False, unique=True)
    33 
    34     def __repr__(self):
    35         return "<Department: {} {}>".format(
    36             self.dept_no,
    37             self.dept_name
    38         )
    39 
    40     __str__ = __repr__
    41 
    42 class Dept_emp(models.Model):
    43     class Meta:
    44         db_table = 'dept_emp'
    45 
    46     id = models.AutoField(primary_key=True) # 新增自增主键,解决不支持联合主键问题
    47     emp_no = models.ForeignKey(to='Employee', on_delete=models.CASCADE,db_column='emp_no')                      #写模块.类名,当前模块写类名
    48     dept_no = models.ForeignKey(to='Department', on_delete=models.CASCADE,max_length=4,db_column='dept_no')     # django会给外键字段自动加后缀_id,如果不需要加这个后缀,用db_column指定
    49     from_date = models.DateField(null=False)
    50     to_date = models.DateField(null=False)
    51 
    52     def __repr__(self):
    53         return "<DeptEmp: {} {}>".format(
    54             self.emp_no, 
    55             self.dept_no
    56         )
    57 
    58     __str__ = __repr__

    三.多对多查询案例

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import os
     7 import django
     8 
     9 #参考salary/wsgi.py文件
    10 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
    11 django.setup(set_prefix=False)
    12 
    13 #导入employee应用的models模块中定义的Employee类
    14 from employee.models import Employee,Department
    15 
    16 empmgr = Employee.objects
    17 deptmgr = Department.objects
    18 # 查询10010员工的所在的部门编号及员工信息
    19 emp = empmgr.filter(pk=10010).get() # 只查employees
    20 print('-' * 30)
    21 depts = emp.dept_emp_set.all() # 懒查
    22 for x in depts: # 查dept_emp中的2个部门,然后再查departments 2次
    23     print(type(x), x) #
    24     e = x.emp_no #
    25     print(type(e), e)
    26     d = x.dept_no #
    27     print(type(d), d)
    28     print()
    29     print(e.emp_no, e.first_name, e.last_name, d.dept_no, d.dept_name)
    ------------------------------
    (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
    (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
    (0.001) SELECT `employees`.`emp_no`, `employees`.`birth_date`, `employees`.`first_name`, `employees`.`last_name`, `employees`.`gender`, `employees`.`hire_date` FROM `employees` WHERE `employees`.`emp_no` = 10010; args=(10010,)
    <class 'employee.models.Dept_emp'> <DeptEmp: <Employee: 10010 Duangkaew Piveteau> <Department: d004 Production>>
    (0.001) SELECT `dept_emp`.`id`, `dept_emp`.`emp_no`, `dept_emp`.`dept_no`, `dept_emp`.`from_date`, `dept_emp`.`to_date` FROM `dept_emp` WHERE `dept_emp`.`emp_no` = 10010; args=(10010,)
    <class 'employee.models.Employee'> <Employee: 10010 Duangkaew Piveteau>
    (0.001) SELECT `departments`.`dept_no`, `departments`.`dept_name` FROM `departments` WHERE `departments`.`dept_no` = 'd004'; args=('d004',)
    <class 'employee.models.Department'> <Department: d004 Production>
    
    (0.001) SELECT `departments`.`dept_no`, `departments`.`dept_name` FROM `departments` WHERE `departments`.`dept_no` = 'd006'; args=('d006',)
    10010 Duangkaew Piveteau d004 Production
    <class 'employee.models.Dept_emp'> <DeptEmp: <Employee: 10010 Duangkaew Piveteau> <Department: d006 Quality Management>>
    <class 'employee.models.Employee'> <Employee: 10010 Duangkaew Piveteau>
    <class 'employee.models.Department'> <Department: d006 Quality Management>
    
    10010 Duangkaew Piveteau d006 Quality Management
    以上代码执行结果戳这里

    五.总结

    在开发中,一般都会采用ORM框架,这样就可以使用对象操作表了。 

    Django中,定义表映射的类,继承自Model类。Model类使用了元编程,改变了元类。

    使用Field实例作为类属性来描述字段。
    使用ForeignKey来定义外键约束。
    是否使用外键约束?
      力挺派
        能使数据保证完整性一致性,Django属于力挺派系列的软件。
      弃用派
        开发难度增加,大量数据的时候影响插入、修改、删除的效率。 在业务层保证数据的一致性。
  • 相关阅读:
    使用 supervisor 管理进程
    用gunicorn+gevent启动Flask项目
    pip与apt-get
    Python计算地图上两点经纬度间的距离
    java基础学习总结——数组
    java基础学习总结——异常处理
    java基础学习总结——面向对象1
    java基础学习总结——基础语法2
    java基础学习总结——基础语法1
    java基础学习总结——java环境变量配置
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/11954411.html
Copyright © 2020-2023  润新知