天天看点

Django ORM查询总结

employee models

import os
import django

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False)


from employee.models import Employee, Salary, Department, Dept_emp
from students.models import Student, Score
from django.db.models import Q, Avg, Sum, Max, Min, Count

emps = Employee.objects.all()
smps = Salary.objects
dmps = Department.objects
demps = Dept_emp.objects

# --- 多对多查询

# 查询10010员工的所在的部门编号及员工信息
# es = emps.get(pk=10010)
# ed = es.dept_emp_set.all() # 记得加all(),不然会返回None
# print(es)
# print(ed)


# for i in ed:
    # print(type(i), i)
    # e = i.emp_no
    # print(type(e), e)
    # d = i.dept_no
    # print(type(d), d, d.dept_no, d.dept_name)

# --- 一对多查询

# print(smps.all())
# print(smps.filter(pk__gt=30)) # 直接用Salary.objects即可管理
#
# print(*Employee.__dict__.items(), sep='\n')
# print('-'*30)
# print(*Salary.__dict__.items(), sep='\n')

# 查询1004号员工的所有工资(建议从"一"端查,只查询一次)
# print(emps.get(pk=10004).salary_set.all()) # 记得加all()

# 工资大于55000的所有员工的姓名
# print(smps.filter(salary__gt=55000).values('emp_no').distinct())

# 查询1004号员工的所有工资及姓名(建议从"一"端查,只查询一次)
# print(emps.get(pk=10004).salary_set.all()) # 记得加all()
# print(emps.get(pk=10004).name)

# 查询工资大于55000的所有员工姓名(emp_no仅表示关系,salary_set,emp_no才是2个表真正用的属性)
# nos = smps.filter(salary__gt=55000)
# names = set()
# for i in nos:
#     names.add(i.emp_no.name)
# print(names)
# 查询10004员工所有工资及姓名
# slist = list(smps.filter(emp_no=10004).filter(salary__gt=55000))
# for s in slist:
#     print(s.emp_no.name, s.emp_no_id, s.salary) # s.emp_no 这里的emp_no表示【关系】

# 员工大于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
# """
# # print(emps.raw(sql)) #惰性的set
# print(list(emps.raw(sql)))


# --- 缓存验证

# print(emps)
# print(*emps, sep='\n')
# print(emps[0].gender, emps[0].get_gender_display())

# print(type(emps))
# print(1, emps)
# print(2, emps)
# print(3, emps[0])
# print(4, emps[0])
# print(emps._result_cache)
# # 上面共查询了4次数据库,emps._result_cache为None,说明emps是惰性的

# print(type(emps)) # QuerySet查询集
# print(list(emps)) # print(*emps) 先遍历一遍,缓存住
# print(1, emps)
# print(2, emps)
# print(3, emps[0])
# print(4, emps[:])
# print(emps._result_cache) # 结果集列表
# # 上面list(emps)进行了缓存,所以下面4个就不进行查询了,直接利用了缓存,综合查询了1次

# # --- 切片和步长
# print(emps[10:15])
# print(emps[20:30])
# print(emps[0:20:5])
# print(emps[::5])

# # --- 结果集查询
# print(emps.values())
# print(emps.filter(pk=10010).values())
# print(emps.exclude(emp_no=10001))
# print(emps.exclude(emp_no=10002).order_by('emp_no'))
# print(emps.exclude(emp_no=10002).order_by('-pk'))
# print(emps.exclude(emp_no=10002).order_by('-pk').values())
# # values返回的集合里的元素是字典

# # --- 单值查询
# print(emps.filter(pk=10010).get())
# print(emps.get(pk=10001))
# #print(emps.exclude(pk=10010).get()) # get严格一个
# print(emps.first()) # limit 1
# print(emps.exclude(pk=10010).last()) # desc, limit 1
# print(emps.filter(pk=10010, gender=1).first()) # AND,找不到返回None
# print(emps.count())
# print(emps.exclude(pk=10010).count())

# # --- LOOKUP表达式
# print(emps.filter(emp_no__exact=10010)) # 就是等于,所以很少用exact
# print(emps.filter(pk__in=[10010, 10009]))
# print(emps.filter(last_name__startswith='P'))
# print(emps.exclude(pk__gt=10003))

# # --- Q对象
# print(emps.filter(Q(pk__lt=10006))) # 不如直接写filter(pk__lt=10006)
# # 下面几句一样
# print(emps.filter(pk__gt=10003).filter(pk__lt=10006)) # 与
# print(emps.filter(pk__gt=10003, pk__lt=10006)) # 与
# print(emps.filter(Q(pk__gt=10003), Q(pk__lt=10006)))
# print(emps.filter(Q(pk__gt=10003) & Q(pk__lt=10006))) # 与
# print(emps.filter(pk__gt=10003) & emps.filter(pk__lt=10006))
# # 下面几句等价
# print(emps.filter(pk__in=[10003, 10006])) # in
# print(emps.filter(Q(pk=10003) | Q(pk=10006))) # 或
# print(emps.filter(pk=10003) | emps.filter(pk=10006))
#
# print(emps.filter(~Q(pk__gt=10003))) # 非
# # 可使用&|和Q对象来构造复杂的逻辑表达式,可以使用一个或多个Q对象。
# # 如果混用关键字参数和Q对象,那么Q对象必须位于关键字参数的前面。

# --- 聚合分组

# # aggregate() 返回字典,方便使用
# print(emps.filter(pk__gt=10010).count()) # 单值
# print(emps.filter(pk__gt=10010).aggregate(Count('pk'), Max('pk'))) # 字典
# print(emps.filter(pk__lte=10010).aggregate(Avg('pk')))
# print(emps.aggregate(Max('pk'), min=Min('pk'))) # 别名

# # annotate()方法用来分组聚合,返回查询集。
# print(emps.filter(pk__gt=10010).aggregate(Count('pk'))) # 字典
# s = emps.filter(pk__gt=10010).annotate(Count('pk')) # 返回查询集,没指定分组字段,
# # print(s)
# # 使用主键分组
# for x in s:
#     print(x)
#     print(x.__dict__) # 里面多了一个属性pk__count

# # values()方法,放在annotate前就是指定分组字段,之后就是取结果中的字段。
# s = emps.filter(pk__gt=10010).values('gender').annotate(Count('pk')) # 查询集
# print(s)
# for x in s:
#     print(x) # 字典

# s = emps.filter(pk__gt=10010).values('gender').annotate(c=Count('pk')).order_by('-c') # 查询集
# print(s)
# for x in s:
#     print(x) # 字典

# s = emps.filter(pk__gt=10010).values('gender').annotate(Avg('pk'), c=Count('pk')).order_by('-c').values('pk__avg', 'c') # 查询集,但后面的values过滤了每个对象字典的key
# print(s)
# for x in s:
#     print(x) # 字典



# --- 练习题(记得用test2数据库)

# # # 导入数据
#
# stu_list = [('王一涵',10),('张青阳',12),('韩名博',12),('王梓',13),('骆铭峰',11),('赢乘风',11),('林烽',10),('吴博文',12),('马小文',12)]
# sco_list = [(1,'语文',90,'王一涵'),(2,'数学',80,'王一涵'),(3,'英语',75,'王一涵'),(4,'语文',95,'张青阳'),(5,'数学',90,'张青阳'),(6,'英语',98,'张青阳'),(7,'语文',80,'韩名博'),(8,'数学',89,'韩名博'),(9,'英语',70,'韩名博'),(10,'语文',60,'王梓'),(11,'数学',75,'王梓'),(12,'英语',65,'王梓'),(13,'语文',81,'骆铭峰'),(14,'数学',82,'骆铭峰'),(15,'英语',55,'骆铭峰'),(16,'语文',78,'赢乘风'),(17,'数学',89,'赢乘风'),(18,'英语',65,'赢乘风'),(19,'语文',89,'林烽'),(20,'数学',60,'林烽'),(21,'英语',49,'林烽'),(22,'语文',89,'吴博文'),(23,'数学',92,'吴博文'),(24,'英语',79,'吴博文'),(25,'语文',50,'马小文'),(26,'数学',60,'马小文'),(27,'英语',62,'马小文')]
#
# for k,v in stu_list:
#     Student(k,v).save()
#
# for s1,s2,s3,s4 in sco_list:
#     Score(s1,s2,s3,s4).save()
#
#
# # 查询
#
# stu = Student.objects.all()
# sco = Score.objects.all()
#
# # 总成绩大于250分的学生信息
# print(sco.values('name').annotate(Sum('score')).filter(score__sum__gt=250))
# # 语文成绩在80-90分之间的学生信息
# print(sco.filter(exam_subjects='语文').filter(score__gt=80,score__lt=90))
# # 有一门科目低于60分的学生信息
# print(sco.filter(score__lt=60).values('name').annotate())
# # 平均分70以上的学生信息
# print(sco.values('name').annotate(Avg('score')).filter(score__avg__gt=70))
# # 三门成绩都大于90分的学生姓名
# print(sco.filter(score__gte=90).values('name').annotate(Count('score')).filter(score__count=3))      

students models

from django.db import models

# Create your models here.

class Student(models.Model):
    class Mate:
        db_table = 'students'

    # id = models.AutoField(primary_key=True)
    name = models.CharField(primary_key=True, max_length=30, verbose_name='姓名')
    age = models.PositiveSmallIntegerField(verbose_name='年龄')

    def __repr__(self):
        return '{} {}'.format(self.name, self.age)

    __str__ = __repr__

class Score(models.Model):
    class Mate:
        db_table = 'scroes'

    id = models.AutoField(primary_key=True)
    exam_subjects = models.CharField(max_length=40, verbose_name='科目')
    score = models.PositiveSmallIntegerField(verbose_name='分数')
    name = models.ForeignKey(Student, db_column='name', on_delete=models.CASCADE)
    # to_field = name (默认用的Studentde主键)
    # name表示关系,db_column='name'的name表示数据库显示的名称(数据库用的名称),ORM真正与数据的name对应的却是name_id

    def __repr__(self):
        return '{} {} {}'.format(self.exam_subjects, self.score, self.name_id)

    __str__ = __repr__      

test.py

import os
import django

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False)


from employee.models import Employee, Salary, Department, Dept_emp
from students.models import Student, Score
from django.db.models import Q, Avg, Sum, Max, Min, Count

emps = Employee.objects.all()
smps = Salary.objects
dmps = Department.objects
demps = Dept_emp.objects

# --- 多对多查询

# 查询10010员工的所在的部门编号及员工信息
# es = emps.get(pk=10010)
# ed = es.dept_emp_set.all() # 记得加all(),不然会返回None
# print(es)
# print(ed)


# for i in ed:
    # print(type(i), i)
    # e = i.emp_no
    # print(type(e), e)
    # d = i.dept_no
    # print(type(d), d, d.dept_no, d.dept_name)

# --- 一对多查询

# print(smps.all())
# print(smps.filter(pk__gt=30)) # 直接用Salary.objects即可管理
#
# print(*Employee.__dict__.items(), sep='\n')
# print('-'*30)
# print(*Salary.__dict__.items(), sep='\n')

# 查询1004号员工的所有工资(建议从"一"端查,只查询一次)
# print(emps.get(pk=10004).salary_set.all()) # 记得加all()

# 工资大于55000的所有员工的姓名
# print(smps.filter(salary__gt=55000).values('emp_no').distinct())

# 查询1004号员工的所有工资及姓名(建议从"一"端查,只查询一次)
# print(emps.get(pk=10004).salary_set.all()) # 记得加all()
# print(emps.get(pk=10004).name)

# 查询工资大于55000的所有员工姓名(emp_no仅表示关系,salary_set,emp_no才是2个表真正用的属性)
# nos = smps.filter(salary__gt=55000)
# names = set()
# for i in nos:
#     names.add(i.emp_no.name)
# print(names)
# 查询10004员工所有工资及姓名
# slist = list(smps.filter(emp_no=10004).filter(salary__gt=55000))
# for s in slist:
#     print(s.emp_no.name, s.emp_no_id, s.salary) # s.emp_no 这里的emp_no表示【关系】

# 员工大于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
# """
# # print(emps.raw(sql)) #惰性的set
# print(list(emps.raw(sql)))


# --- 缓存验证

# print(emps)
# print(*emps, sep='\n')
# print(emps[0].gender, emps[0].get_gender_display())

# print(type(emps))
# print(1, emps)
# print(2, emps)
# print(3, emps[0])
# print(4, emps[0])
# print(emps._result_cache)
# # 上面共查询了4次数据库,emps._result_cache为None,说明emps是惰性的

# print(type(emps)) # QuerySet查询集
# print(list(emps)) # print(*emps) 先遍历一遍,缓存住
# print(1, emps)
# print(2, emps)
# print(3, emps[0])
# print(4, emps[:])
# print(emps._result_cache) # 结果集列表
# # 上面list(emps)进行了缓存,所以下面4个就不进行查询了,直接利用了缓存,综合查询了1次

# # --- 切片和步长
# print(emps[10:15])
# print(emps[20:30])
# print(emps[0:20:5])
# print(emps[::5])

# # --- 结果集查询
# print(emps.values())
# print(emps.filter(pk=10010).values())
# print(emps.exclude(emp_no=10001))
# print(emps.exclude(emp_no=10002).order_by('emp_no'))
# print(emps.exclude(emp_no=10002).order_by('-pk'))
# print(emps.exclude(emp_no=10002).order_by('-pk').values())
# # values返回的集合里的元素是字典

# # --- 单值查询
# print(emps.filter(pk=10010).get())
# print(emps.get(pk=10001))
# #print(emps.exclude(pk=10010).get()) # get严格一个
# print(emps.first()) # limit 1
# print(emps.exclude(pk=10010).last()) # desc, limit 1
# print(emps.filter(pk=10010, gender=1).first()) # AND,找不到返回None
# print(emps.count())
# print(emps.exclude(pk=10010).count())

# # --- LOOKUP表达式
# print(emps.filter(emp_no__exact=10010)) # 就是等于,所以很少用exact
# print(emps.filter(pk__in=[10010, 10009]))
# print(emps.filter(last_name__startswith='P'))
# print(emps.exclude(pk__gt=10003))

# # --- Q对象
# print(emps.filter(Q(pk__lt=10006))) # 不如直接写filter(pk__lt=10006)
# # 下面几句一样
# print(emps.filter(pk__gt=10003).filter(pk__lt=10006)) # 与
# print(emps.filter(pk__gt=10003, pk__lt=10006)) # 与
# print(emps.filter(Q(pk__gt=10003), Q(pk__lt=10006)))
# print(emps.filter(Q(pk__gt=10003) & Q(pk__lt=10006))) # 与
# print(emps.filter(pk__gt=10003) & emps.filter(pk__lt=10006))
# # 下面几句等价
# print(emps.filter(pk__in=[10003, 10006])) # in
# print(emps.filter(Q(pk=10003) | Q(pk=10006))) # 或
# print(emps.filter(pk=10003) | emps.filter(pk=10006))
#
# print(emps.filter(~Q(pk__gt=10003))) # 非
# # 可使用&|和Q对象来构造复杂的逻辑表达式,可以使用一个或多个Q对象。
# # 如果混用关键字参数和Q对象,那么Q对象必须位于关键字参数的前面。

# --- 聚合分组

# # aggregate() 返回字典,方便使用
# print(emps.filter(pk__gt=10010).count()) # 单值
# print(emps.filter(pk__gt=10010).aggregate(Count('pk'), Max('pk'))) # 字典
# print(emps.filter(pk__lte=10010).aggregate(Avg('pk')))
# print(emps.aggregate(Max('pk'), min=Min('pk'))) # 别名

# # annotate()方法用来分组聚合,返回查询集。
# print(emps.filter(pk__gt=10010).aggregate(Count('pk'))) # 字典
# s = emps.filter(pk__gt=10010).annotate(Count('pk')) # 返回查询集,没指定分组字段,
# # print(s)
# # 使用主键分组
# for x in s:
#     print(x)
#     print(x.__dict__) # 里面多了一个属性pk__count

# # values()方法,放在annotate前就是指定分组字段,之后就是取结果中的字段。
# s = emps.filter(pk__gt=10010).values('gender').annotate(Count('pk')) # 查询集
# print(s)
# for x in s:
#     print(x) # 字典

# s = emps.filter(pk__gt=10010).values('gender').annotate(c=Count('pk')).order_by('-c') # 查询集
# print(s)
# for x in s:
#     print(x) # 字典

# s = emps.filter(pk__gt=10010).values('gender').annotate(Avg('pk'), c=Count('pk')).order_by('-c').values('pk__avg', 'c') # 查询集,但后面的values过滤了每个对象字典的key
# print(s)
# for x in s:
#     print(x) # 字典



# --- 练习题(记得用test2数据库)

# # # 导入数据
#
# stu_list = [('王一涵',10),('张青阳',12),('韩名博',12),('王梓',13),('骆铭峰',11),('赢乘风',11),('林烽',10),('吴博文',12),('马小文',12)]
# sco_list = [(1,'语文',90,'王一涵'),(2,'数学',80,'王一涵'),(3,'英语',75,'王一涵'),(4,'语文',95,'张青阳'),(5,'数学',90,'张青阳'),(6,'英语',98,'张青阳'),(7,'语文',80,'韩名博'),(8,'数学',89,'韩名博'),(9,'英语',70,'韩名博'),(10,'语文',60,'王梓'),(11,'数学',75,'王梓'),(12,'英语',65,'王梓'),(13,'语文',81,'骆铭峰'),(14,'数学',82,'骆铭峰'),(15,'英语',55,'骆铭峰'),(16,'语文',78,'赢乘风'),(17,'数学',89,'赢乘风'),(18,'英语',65,'赢乘风'),(19,'语文',89,'林烽'),(20,'数学',60,'林烽'),(21,'英语',49,'林烽'),(22,'语文',89,'吴博文'),(23,'数学',92,'吴博文'),(24,'英语',79,'吴博文'),(25,'语文',50,'马小文'),(26,'数学',60,'马小文'),(27,'英语',62,'马小文')]
#
# for k,v in stu_list:
#     Student(k,v).save()
#
# for s1,s2,s3,s4 in sco_list:
#     Score(s1,s2,s3,s4).save()
#
#
# # 查询
#
# stu = Student.objects.all()
# sco = Score.objects.all()
#
# # 总成绩大于250分的学生信息
# print(sco.values('name').annotate(Sum('score')).filter(score__sum__gt=250))
# # 语文成绩在80-90分之间的学生信息
# print(sco.filter(exam_subjects='语文').filter(score__gt=80,score__lt=90))
# # 有一门科目低于60分的学生信息
# print(sco.filter(score__lt=60).values('name').annotate())
# # 平均分70以上的学生信息
# print(sco.values('name').annotate(Avg('score')).filter(score__avg__gt=70))
# # 三门成绩都大于90分的学生姓名
# print(sco.filter(score__gte=90).values('name').annotate(Count('score')).filter(score__count=3))      

settings.py

"""
Django settings for salary project.

Generated by 'django-admin startproject' using Django 3.2.6.

For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-(uouz1h2%5ey)2+n6o8efxd+p+h!@m&we+1%6erp6ng79j9p#2'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'employee',
    'students',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'salary.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'salary.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {'charset': 'utf8'},
        'NAME': 'test',
        'USER': 'soymilk',
        'PASSWORD': '123456',
        'HOST': '172.16.241.2',
        'PORT': '3306',
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'zh-Hans' # 'en-us'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },

    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    },
}