数据库开发-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 '' COMMENT 'M=1, F=2',
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`),
CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees`
(`emp_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. 重建原来的外键约束即可

二.构建模型

 from django.db import models

 # Create your models here.
from django.db import models class Employee(models.Model):
class Meta:
db_table = 'employees' emp_no = models.IntegerField(primary_key=True)
birth_date = models.DateField(null=False)
first_name = models.CharField(null=False, max_length=14)
last_name = models.CharField(null=False, max_length=16)
gender = models.SmallIntegerField(null=False)
hire_date = models.DateField(null=False) def __repr__(self):
return "<Employee: {} {} {}>".format(
self.emp_no,
self.first_name,
self.last_name
) __str__ = __repr__ class Salary(models.Model):
class Meta:
db_table = 'salaries' id = models.AutoField(primary_key=True) # 额外增加的,Django不支持联合主键
# 候选键(emp_no, from_date)
emp_no = models.ForeignKey('Employee', on_delete=models.CASCADE, null=False, db_column='emp_no') #Django习惯给外键默认起名为xxx_id(例如:emp_no_id),推荐显式增加db_column来指定字段名称。
from_date = models.DateField(null=False)
salary = models.IntegerField(null=False)
to_date = models.DateField(null=False) def __repr__(self):
return "<Salary: {} {} {}>".format(
self.emp_no,
self.from_date,
self.salary
) __str__ = __repr__

三.特殊属性

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import os
import django
from django.db.models import Avg,Sum,Max,Min,Count
#参考salary/wsgi.py文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) #导入employee应用的models模块中定义的Employee类
from employee.models import Employee,Salary """
如果增加类外键后,Django会对一端和多端增加一些新的类属性。
从一端往多端查 <Employee_instance>.salary_set
从多端往一端查 <Salary_instance>.emp_no
"""
emps = Employee.objects """
一端,Employee类中多了一个类属性,即"('salary_set', <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x1045ae550>)"
"""
print(*Employee.__dict__.items(),sep="\n") print("{0} 我是分隔符 {0}".format("*" * 15)) """
多端,Salary类中也多了一个类属性,即"('emp_no_id', <django.db.models.query_utils.DeferredAttribute object at 0x1045ae240>)"和"('emp_no', <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x1045ae278>)"
"""
print(*Salary.__dict__.items(),sep="\n")
('__module__', 'employee.models')
('__repr__', <function Employee.__repr__ at 0x1045c7b70>)
('__str__', <function Employee.__repr__ at 0x1045c7b70>)
('__doc__', 'Employee(emp_no, birth_date, first_name, last_name, gender, hire_date)')
('_meta', <Options for Employee>)
('DoesNotExist', <class 'employee.models.Employee.DoesNotExist'>)
('MultipleObjectsReturned', <class 'employee.models.Employee.MultipleObjectsReturned'>)
('emp_no', <django.db.models.query_utils.DeferredAttribute object at 0x1045cbc88>)
('birth_date', <django.db.models.query_utils.DeferredAttribute object at 0x1045cbcc0>)
('get_next_by_birth_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: birth_date>, is_next=True))
('get_previous_by_birth_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: birth_date>, is_next=False))
('first_name', <django.db.models.query_utils.DeferredAttribute object at 0x1045b1d30>)
('last_name', <django.db.models.query_utils.DeferredAttribute object at 0x1045cbd30>)
('gender', <django.db.models.query_utils.DeferredAttribute object at 0x1045cbd68>)
('hire_date', <django.db.models.query_utils.DeferredAttribute object at 0x1045cbda0>)
('get_next_by_hire_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: hire_date>, is_next=True))
('get_previous_by_hire_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: hire_date>, is_next=False))
('objects', <django.db.models.manager.ManagerDescriptor object at 0x1045cbeb8>)
('salary_set', <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x1045d44a8>)
*************** 我是分隔符 ***************
('__module__', 'employee.models')
('__repr__', <function Salary.__repr__ at 0x1045c2158>)
('__str__', <function Salary.__repr__ at 0x1045c2158>)
('__doc__', 'Salary(id, emp_no, from_date, salary, to_date)')
('_meta', <Options for Salary>)
('DoesNotExist', <class 'employee.models.Salary.DoesNotExist'>)
('MultipleObjectsReturned', <class 'employee.models.Salary.MultipleObjectsReturned'>)
('id', <django.db.models.query_utils.DeferredAttribute object at 0x1045d40f0>)
('emp_no_id', <django.db.models.query_utils.DeferredAttribute object at 0x1045d4198>)
('emp_no', <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x1045d41d0>)
('from_date', <django.db.models.query_utils.DeferredAttribute object at 0x1045d4208>)
('get_next_by_from_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: from_date>, is_next=True))
('get_previous_by_from_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: from_date>, is_next=False))
('salary', <django.db.models.query_utils.DeferredAttribute object at 0x1045d42b0>)
('to_date', <django.db.models.query_utils.DeferredAttribute object at 0x1045d4320>)
('get_next_by_to_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: to_date>, is_next=True))
('get_previous_by_to_date', functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x10379d620>, , field=<django.db.models.fields.DateField: to_date>, is_next=False))
('objects', <django.db.models.manager.ManagerDescriptor object at 0x1045d4438>)

以上代码执行结果戳这里

四.查询

1>.使用salary_set查询

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import os
import django #参考salary/wsgi.py文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) #导入employee应用的models模块中定义的Employee类
from employee.models import Employee,Salary emps = Employee.objects #查询10004员工所有工资
print(emps.get(pk=10004).salary_set.all())
(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` = 10004; args=(10004,)
<QuerySet [<Salary: <Employee: 10004 Chirstian Koblick> 1986-12-01 40054>, <Salary: <Employee: 10004 Chirstian Koblick> 1987-12-01 42283>, <Salary: <Employee: 10004 Chirstian Koblick> 1988-11-30 42542>, <Salary: <Employee: 10004 Chirstian Koblick> 1989-11-30 46065>, <Salary: <Employee: 10004 Chirstian Koblick> 1990-11-30 48271>, <Salary: <Employee: 10004 Chirstian Koblick> 1991-11-30 50594>, <Salary: <Employee: 10004 Chirstian Koblick> 1992-11-29 52119>, <Salary: <Employee: 10004 Chirstian Koblick> 1993-11-29 54693>, <Salary: <Employee: 10004 Chirstian Koblick> 1994-11-29 58326>, <Salary: <Employee: 10004 Chirstian Koblick> 1995-11-29 60770>]>
(0.001) SELECT `salaries`.`id`, `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary`, `salaries`.`to_date` FROM `salaries` WHERE `salaries`.`emp_no` = 10004 LIMIT 21; args=(10004,)

以上代码执行结果戳这里

2>.如果觉得salary_set不好用,可以使用related_name 

from django.db import models

# Create your models here.
from django.db import models class Employee(models.Model):
class Meta:
db_table = 'employees' emp_no = models.IntegerField(primary_key=True)
birth_date = models.DateField(null=False)
first_name = models.CharField(null=False, max_length=14)
last_name = models.CharField(null=False, max_length=16)
gender = models.SmallIntegerField(null=False)
hire_date = models.DateField(null=False) def __repr__(self):
return "<Employee: {} {} {}>".format(
self.emp_no,
self.first_name,
self.last_name
) __str__ = __repr__ class Salary(models.Model):
class Meta:
db_table = 'salaries' id = models.AutoField(primary_key=True) # 额外增加的,Django不支持联合主键
# 候选键(emp_no, from_date)
#emp_no = models.ForeignKey('Employee', on_delete=models.CASCADE, null=False, db_column='emp_no') #Django习惯给外键默认起名为xxx_id(例如:emp_no_id),推荐显式增加db_column来指定字段名称。
emp_no = models.ForeignKey('Employee', on_delete=models.CASCADE, null=False,db_column='emp_no', related_name='salaries')
from_date = models.DateField(null=False)
salary = models.IntegerField(null=False)
to_date = models.DateField(null=False) def __repr__(self):
return "<Salary: {} {} {}>".format(
self.emp_no,
self.from_date,
self.salary
) __str__ = __repr__

需要修改models.py的文件内容

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import os
import django #参考salary/wsgi.py文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) #导入employee应用的models模块中定义的Employee类
from employee.models import Employee,Salary emps = Employee.objects #查询10004员工所有工资
#print(emps.get(pk=10004).salary_set.all())
print(emps.get(pk=10004).salaries.all())
(0.001) 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` = 10004; args=(10004,)
(0.001) SELECT `salaries`.`id`, `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary`, `salaries`.`to_date` FROM `salaries` WHERE `salaries`.`emp_no` = 10004 LIMIT 21; args=(10004,)
<QuerySet [<Salary: <Employee: 10004 Chirstian Koblick> 1986-12-01 40054>, <Salary: <Employee: 10004 Chirstian Koblick> 1987-12-01 42283>, <Salary: <Employee: 10004 Chirstian Koblick> 1988-11-30 42542>, <Salary: <Employee: 10004 Chirstian Koblick> 1989-11-30 46065>, <Salary: <Employee: 10004 Chirstian Koblick> 1990-11-30 48271>, <Salary: <Employee: 10004 Chirstian Koblick> 1991-11-30 50594>, <Salary: <Employee: 10004 Chirstian Koblick> 1992-11-29 52119>, <Salary: <Employee: 10004 Chirstian Koblick> 1993-11-29 54693>, <Salary: <Employee: 10004 Chirstian Koblick> 1994-11-29 58326>, <Salary: <Employee: 10004 Chirstian Koblick> 1995-11-29 60770>]>

以上代码执行结果戳这里

3>.完整代码

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import os
import django #参考salary/wsgi.py文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) #导入employee应用的models模块中定义的Employee类
from employee.models import Employee,Salary emps = Employee.objects
sals = Salary.objects # 查询10004员工所有工资
# 方案一、从员工往工资查
print(emps.get(pk=10004).salaries.all()) print("{0} 1 我是分割线 {0}".format("*" * 15)) # 查询10004员工所有工资
emp = emps.get(pk=10004) # 单一员工对象
print(emp.salaries.all())
print(emp.salaries.values('emp_no', 'from_date', 'salary')) # 投影 # 工资大于55000
print(emp.salaries.filter(salary__gt=55000).all()) print("{0} 2 我是分割线 {0}".format("*" * 15)) # 查询10004员工所有工资及姓名
# 方案二、从工资往员工查
slist = list(sals.filter(emp_no=10004)) for s in slist:
print(s.emp_no.first_name, s.emp_no_id, s.salary) # s.emp_no会引发填充对象 print("{0} 3 我是分割线 {0}".format("*" * 15)) # ############## 特别注意 #####################
# 这种查询会导致列表中的n个Salary实例填充其中emp_no属性,会查n此数据库
# 方案二改进(方案二的改进,虽然别扭,但也完成了,查询了较少的次数。)
slist = list(sals.filter(emp_no=10004))
if slist:
first = slist[0]
emp = first.emp_no
for s in slist:
print(emp.pk, emp.first_name, s.emp_no_id, s.salary)
(0.001) 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` = 10004; args=(10004,)
(0.001) SELECT `salaries`.`id`, `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary`, `salaries`.`to_date` FROM `salaries` WHERE `salaries`.`emp_no` = 10004 LIMIT 21; args=(10004,)
<QuerySet [<Salary: <Employee: 10004 Chirstian Koblick> 1986-12-01 40054>, <Salary: <Employee: 10004 Chirstian Koblick> 1987-12-01 42283>, <Salary: <Employee: 10004 Chirstian Koblick> 1988-11-30 42542>, <Salary: <Employee: 10004 Chirstian Koblick> 1989-11-30 46065>, <Salary: <Employee: 10004 Chirstian Koblick> 1990-11-30 48271>, <Salary: <Employee: 10004 Chirstian Koblick> 1991-11-30 50594>, <Salary: <Employee: 10004 Chirstian Koblick> 1992-11-29 52119>, <Salary: <Employee: 10004 Chirstian Koblick> 1993-11-29 54693>, <Salary: <Employee: 10004 Chirstian Koblick> 1994-11-29 58326>, <Salary: <Employee: 10004 Chirstian Koblick> 1995-11-29 60770>]>
*************** 1 我是分割线 ***************
<QuerySet [<Salary: <Employee: 10004 Chirstian Koblick> 1986-12-01 40054>, <Salary: <Employee: 10004 Chirstian Koblick> 1987-12-01 42283>, <Salary: <Employee: 10004 Chirstian Koblick> 1988-11-30 42542>, <Salary: <Employee: 10004 Chirstian Koblick> 1989-11-30 46065>, <Salary: <Employee: 10004 Chirstian Koblick> 1990-11-30 48271>, <Salary: <Employee: 10004 Chirstian Koblick> 1991-11-30 50594>, <Salary: <Employee: 10004 Chirstian Koblick> 1992-11-29 52119>, <Salary: <Employee: 10004 Chirstian Koblick> 1993-11-29 54693>, <Salary: <Employee: 10004 Chirstian Koblick> 1994-11-29 58326>, <Salary: <Employee: 10004 Chirstian Koblick> 1995-11-29 60770>]>
(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` = 10004; args=(10004,)
(0.001) SELECT `salaries`.`id`, `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary`, `salaries`.`to_date` FROM `salaries` WHERE `salaries`.`emp_no` = 10004 LIMIT 21; args=(10004,)
(0.001) SELECT `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary` FROM `salaries` WHERE `salaries`.`emp_no` = 10004 LIMIT 21; args=(10004,)
<QuerySet [{'emp_no': 10004, 'from_date': datetime.date(1986, 12, 1), 'salary': 40054}, {'emp_no': 10004, 'from_date': datetime.date(1987, 12, 1), 'salary': 42283}, {'emp_no': 10004, 'from_date': datetime.date(1988, 11, 30), 'salary': 42542}, {'emp_no': 10004, 'from_date': datetime.date(1989, 11, 30), 'salary': 46065}, {'emp_no': 10004, 'from_date': datetime.date(1990, 11, 30), 'salary': 48271}, {'emp_no': 10004, 'from_date': datetime.date(1991, 11, 30), 'salary': 50594}, {'emp_no': 10004, 'from_date': datetime.date(1992, 11, 29), 'salary': 52119}, {'emp_no': 10004, 'from_date': datetime.date(1993, 11, 29), 'salary': 54693}, {'emp_no': 10004, 'from_date': datetime.date(1994, 11, 29), 'salary': 58326}, {'emp_no': 10004, 'from_date': datetime.date(1995, 11, 29), 'salary': 60770}]>
<QuerySet [<Salary: <Employee: 10004 Chirstian Koblick> 1994-11-29 58326>, <Salary: <Employee: 10004 Chirstian Koblick> 1995-11-29 60770>]>
*************** 2 我是分割线 ***************
Chirstian 10004 40054
(0.001) SELECT `salaries`.`id`, `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary`, `salaries`.`to_date` FROM `salaries` WHERE (`salaries`.`emp_no` = 10004 AND `salaries`.`salary` > 55000) LIMIT 21; args=(10004, 55000)
(0.001) SELECT `salaries`.`id`, `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary`, `salaries`.`to_date` FROM `salaries` WHERE `salaries`.`emp_no` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
Chirstian 10004 42283
Chirstian 10004 42542
Chirstian 10004 46065
Chirstian 10004 48271
Chirstian 10004 50594
(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` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
Chirstian 10004 52119
Chirstian 10004 54693
Chirstian 10004 58326
Chirstian 10004 60770
*************** 3 我是分割线 ***************
(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` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
(0.001) SELECT `salaries`.`id`, `salaries`.`emp_no`, `salaries`.`from_date`, `salaries`.`salary`, `salaries`.`to_date` FROM `salaries` WHERE `salaries`.`emp_no` = 10004; args=(10004,)
(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` = 10004; args=(10004,)
10004 Chirstian 10004 40054
10004 Chirstian 10004 42283
10004 Chirstian 10004 42542
10004 Chirstian 10004 46065
10004 Chirstian 10004 48271
10004 Chirstian 10004 50594
10004 Chirstian 10004 52119
10004 Chirstian 10004 54693
10004 Chirstian 10004 58326
10004 Chirstian 10004 60770

以上代码执行结果戳这里

五.distinct

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import os
import django #参考salary/wsgi.py文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) #导入employee应用的models模块中定义的Employee类
from employee.models import Employee,Salary emps = Employee.objects
sals = Salary.objects # 所有发了工资的员工 print(salarymgr.values('emp_no').distinct())
# 工资大于55000的所有员工的姓名
emps = sals.filter(salary__gt=55000).values('emp_no').distinct()
print(type(emps)) print(emps)
print(emps.filter(emp_no__in=[d.get('emp_no') for d in emps])) print("{0} 我是分隔符 {0}".format("*" * 15)) #不使用上面的distinct(),观察输出的结果。 emps = sals.filter(salary__gt=55000).values('emp_no')
print(type(emps)) print(emps)
print(emps.filter(emp_no__in=[d.get('emp_no') for d in emps]))
<class 'django.db.models.query.QuerySet'>
(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
<QuerySet [{'emp_no': 10001}, {'emp_no': 10002}, {'emp_no': 10004}]>
(0.001) SELECT DISTINCT `salaries`.`emp_no` FROM `salaries` WHERE `salaries`.`salary` > 55000 LIMIT 21; args=(55000,)
(0.001) SELECT DISTINCT `salaries`.`emp_no` FROM `salaries` WHERE `salaries`.`salary` > 55000; args=(55000,)
<QuerySet [{'emp_no': 10001}, {'emp_no': 10002}, {'emp_no': 10004}]>
*************** 我是分隔符 ***************
<class 'django.db.models.query.QuerySet'>
<QuerySet [{'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10002}, {'emp_no': 10002}, {'emp_no': 10002}, '...(remaining elements truncated)...']>
(0.001) SELECT DISTINCT `salaries`.`emp_no` FROM `salaries` WHERE (`salaries`.`salary` > 55000 AND `salaries`.`emp_no` IN (10001, 10002, 10004)) LIMIT 21; args=(55000, 10001, 10002, 10004)
(0.001) SELECT `salaries`.`emp_no` FROM `salaries` WHERE `salaries`.`salary` > 55000 LIMIT 21; args=(55000,)
(0.001) SELECT `salaries`.`emp_no` FROM `salaries` WHERE `salaries`.`salary` > 55000; args=(55000,)
<QuerySet [{'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10001}, {'emp_no': 10002}, {'emp_no': 10002}, {'emp_no': 10002}, '...(remaining elements truncated)...']>
(0.001) SELECT `salaries`.`emp_no` FROM `salaries` WHERE (`salaries`.`salary` > 55000 AND `salaries`.`emp_no` IN (10001, 10002, 10004)) LIMIT 21; args=(55000, 10001, 10002, 10004)

以上代码执行结果戳这里

六.raw的使用(如果查询非常复杂,使用Django不方便,可以直接使用SQL语句 )

 #!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import os
import django #参考salary/wsgi.py文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False) #导入employee应用的models模块中定义的Employee类
from employee.models import Employee empmgr = Employee.objects # 工资大于55000的所有员工的姓名
sql = """\
SELECT
DISTINCT e.emp_no, e.first_name, e.last_name
FROM
employees e
JOIN
salaries s
ON
e.emp_no=s.emp_no
WHERE
s.salary > 55000
""" # DISTINCT 需要,结果会去重
emps = empmgr.raw(sql)
print(type(emps)) # RawQuerySet
print(list(emps)) # 员工工资记录里超过70000的人的工资和姓名
sql = """\
SELECT
e.emp_no, e.first_name, e.last_name, s.salary
FROM
employees e
JOIN
salaries s
ON
e.emp_no = s.emp_no
where
s.salary > 70000
""" #如果查询非常复杂,使用Django不方便,可以直接使用SQL语句
for x in empmgr.raw(sql):
print(x.__dict__) # 将salary属性注入到当前Employee实例中
print(x.first_name, x.salary)
<class 'django.db.models.query.RawQuerySet'>
(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT
DISTINCT e.emp_no, e.first_name, e.last_name
FROM
employees e
JOIN
salaries s
ON
e.emp_no=s.emp_no
WHERE
s.salary > 55000
; args=()
(0.001) SELECT
e.emp_no, e.first_name, e.last_name, s.salary
FROM
employees e
JOIN
salaries s
ON
e.emp_no = s.emp_no
where
s.salary > 70000
; args=()
[<Employee: 10001 Georgi Facello>, <Employee: 10002 Bezalel Simmel>, <Employee: 10004 Chirstian Koblick>]
{'_state': <django.db.models.base.ModelState object at 0x104751160>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 71046}
Georgi 71046
{'_state': <django.db.models.base.ModelState object at 0x1047511d0>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 74333}
Georgi 74333
{'_state': <django.db.models.base.ModelState object at 0x104751240>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 75286}
Georgi 75286
{'_state': <django.db.models.base.ModelState object at 0x1047512b0>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 75994}
Georgi 75994
{'_state': <django.db.models.base.ModelState object at 0x104751320>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 76884}
Georgi 76884
{'_state': <django.db.models.base.ModelState object at 0x104751390>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 80013}
Georgi 80013
{'_state': <django.db.models.base.ModelState object at 0x104751400>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 81025}
Georgi 81025
{'_state': <django.db.models.base.ModelState object at 0x104751470>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 81097}
Georgi 81097
{'_state': <django.db.models.base.ModelState object at 0x1047514e0>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 84917}
Georgi 84917
{'_state': <django.db.models.base.ModelState object at 0x104751550>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 85112}
Georgi 85112
{'_state': <django.db.models.base.ModelState object at 0x1047515c0>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 85097}
Georgi 85097
{'_state': <django.db.models.base.ModelState object at 0x104751630>, 'emp_no': 10001, 'first_name': 'Georgi', 'last_name': 'Facello', 'salary': 88958}
Georgi 88958
{'_state': <django.db.models.base.ModelState object at 0x1047516a0>, 'emp_no': 10002, 'first_name': 'Bezalel', 'last_name': 'Simmel', 'salary': 71963}
Bezalel 71963
{'_state': <django.db.models.base.ModelState object at 0x104751710>, 'emp_no': 10002, 'first_name': 'Bezalel', 'last_name': 'Simmel', 'salary': 72527}
Bezalel 72527

以上代码执行结果戳这里

数据库开发-Django ORM的一对多查询的更多相关文章

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

    数据库开发-Django ORM的多对多查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.联合主键问题 CREATE TABLE `employees` ( `emp_no` ...

  2. 数据库开发-Django ORM的单表查询

    数据库开发-Django ORM的单表查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查询集 1>.查询集相关概述 查询会返回结果的集,它是django.db.mod ...

  3. 数据库开发-Django ORM的数据库迁移

    数据库开发-Django ORM的数据库迁移 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. Django 项目准备 1>.安装django包 pip install d ...

  4. Django ORM 一对一,一对多,多对多, 添加,批量插入和查询

    模型类 class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_ ...

  5. Django ORM --- 建表、查询、删除基础

    1.什么是ORM ORM的全称是Object Relational Mapping,即对象关系映射.它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的 ...

  6. Django学习——静态文件配置、request对象方法、pycharm如何链接数据库、Django如何指定数据库、Django orm操作

    静态文件配置 # 1.静态文件 网站所使用的已经提前写好的文件 css文件 js文件 img文件 第三方文件 我们在存储静态文件资源的时候一般默认都是放在static文件夹下 # 2.Django静态 ...

  7. 数据库:django ORM如何处理N+1查询

    数据库N+1查询是个常见的问题,简单描述场景如下 基本场景 class Category(models.Model): name = models.CharField(max_length=30) c ...

  8. Django ORM中的模糊查询

    ORM映射 什么是ORM映射?在笔者认为就是对SQL语句的封装,所写语句与SQL对应语句含义相同,使开发更加简单方便,不过也是存在弊端的,使程序运行效率下降.例如: UserInfo.objects. ...

  9. django ORM多对多正向查询时查询返回结果为None

    表 class Books(models.Model): '''书籍''' id = models.AutoField(primary_key=True) name = models.CharFiel ...

随机推荐

  1. Hive、Inceptor数据倾斜详解及解决

    一.倾斜造成的原因 正常的数据分布理论上都是倾斜的,就是我们所说的20-80原理:80%的财富集中在20%的人手中, 80%的用户只使用20%的功能 , 20%的用户贡献了80%的访问量. 俗话是,一 ...

  2. FFmpeg 的bug

    发现一个ffmpeg 的bug, 我用老版本的ffmpeg解码播视频,对同样的视频,音频部分得到的是6通道,一直有杂音 周末呢换了新版本的ffmpeg4.2的库,得到是4,6,8三个通道在切换,我修改 ...

  3. 最常见的Java面试题及答案汇总(六)

    异常 74. throw 和 throws 的区别? throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是 ...

  4. 容器服务如何在企业客户落地?Rancher 解决之道分享

    Docker 的优势和趋势我想不必再赘述,那么对于非互联网公司的传统企业客户,以及我们大量的围绕企业客户做集成.交付解决方案的服务提供商,需要考虑的一个问题就是怎么样把容器技术以高质量.低成本.易维护 ...

  5. Linux内核参数详解

    所谓Linux服务器内核参数优化(适合Apache.Nginx.Squid等多种web应用,特殊的业务有可能需要做略微调整),主要是指在Linux系统中针对业务服务应用而进行的系统内核参数调整,优化并 ...

  6. python 异常处理(25)

    在python开发中,代码书写时难免有疏忽或者意向不到的bug,导致程序run的过程中有可能会直接崩溃:然后对于程序猿而言,程序因bug崩溃是家常便饭,为了增加程序的健壮性,防止程序崩溃,我们可以对程 ...

  7. Spring Initializr生成的demo测试404错误

    体验Spring Initializr生成的spring boot工程,启动成功, 目录结构如下: 添加了一个简单的controller后,启动成功但访问报404错误: 原因: springboot默 ...

  8. mybatis-3.5.2增删查改

    这玩意没啥技术含量,只不过长时间不用,就显得生疏了.正好今天想读取一个文件写入数据库,平时都是集成环境,都碰不到这些基础东西,看来还是需要时常给自己找活干. 首先建立一个maven工程. next n ...

  9. 长乐国庆集训Day5-2

    T1 彩虹 题目 [题目描述] Mr.Raju和他的一个大家庭外出度假,他们想要乘着彩虹欣赏周围的景色,但是这样最会有一些问题. 在他们家族中,如果一个人想要骑上彩虹,那么他喜欢的所有人和喜欢他的所有 ...

  10. Service must be explitict android 5.0问题

    如果target到API 21,有一些注意的事项,以下是目前我发现的两个问题1. Service must be explitict,从Lollipop开始,service必须显性声明,解决方案:ht ...