博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django之ORM
阅读量:6648 次
发布时间:2019-06-25

本文共 30365 字,大约阅读时间需要 101 分钟。

 

 

阅读目录

 

 

 

对应关系

 

映射关系:       python的类名对应的SQL语句的表名       python的类属性对应的SQL语句的表名下的字段       python的类属性的约束对应的SQL语句的表名下的字段类型                                            类的实例对象---------------表中的一条记录对象

 

 

创建表

 

class Student(models.Model):                nid=models.AutoField(primary_key=True)         #  主键约束                name=models.CharField(max_length=32)           #  字符串字段                birth=models.DateField()                       #  日期类型                class_id=models.IntegerField(default=0)      #  整数类型

 

外键创建

#多对一,放在多的一边publish=models.ForeignKey(to="Publish",to_field="nid")#多对多,自动生成第三张表,放在任意一边authors=models.ManyToManyField(to='Author') #一对一,放在常用的一边authorDetail=models.OneToOneField(to="AuthorDetail")

 

 

 

字段类型详细

使用时需要引入django.db.models包,字段类型如下:AutoField:自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性。BooleanField:布尔字段,值为True或False。NullBooleanField:支持Null、True、False三种值。CharField(max_length=字符长度):字符串。TextField:大文本字段,一般超过4000个字符时使用。参数max_length表示最大字符个数。IntegerField:整数。DecimalField(max_digits=None, decimal_places=None):十进制浮点数。FloatField:浮点数。参数max_digits表示总位数。参数decimal_places表示小数位数。DateField[auto_now=False, auto_now_add=False]):日期。TimeField:时间,参数同DateField。参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。参数auto_now_add和auto_now是相互排斥的,组合将会发生错误。DateTimeField:日期时间,参数同DateField。FileField:上传文件字段。ImageField:继承于FileField,对上传的内容进行校验,确保是有效的图片。
View Code

 

 

字段选项

 

每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR数据库字段的大小。还有一些适用于所有字段的通用参数。 

这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:

(1)null如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.(1)blank如果为True,该字段允许不填。默认为False。要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。(2)default字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。(3)primary_key如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,否则没必要设置任何一个字段的primary_key=True。(4)unique如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的(5)choices由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。这是一个关于 choices 列表的例子:YEAR_IN_SCHOOL_CHOICES = (    ('FR', 'Freshman'),    ('SO', 'Sophomore'),    ('JR', 'Junior'),    ('SR', 'Senior'),    ('GR', 'Graduate'),)每个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或 ModelChoiceField 中用作显示的内容。 在一个给定的 model 类的实例中,想得到某个 choices 字段的显示值,就调用 get_FOO_display 方法(这里的 FOO 就是 choices 字段的名称 )。例如:from django.db import modelsclass Person(models.Model):    SHIRT_SIZES = (        ('S', 'Small'),        ('M', 'Medium'),        ('L', 'Large'),    )    name = models.CharField(max_length=60)    shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)>>> p = Person(name="Fred Flintstone", shirt_size="L")>>> p.save()>>> p.shirt_size'L'>>> p.get_shirt_size_display()'Large'
View Code

字段补充

AutoField(Field)        - int自增列,必须填入参数 primary_key=True    BigAutoField(AutoField)        - bigint自增列,必须填入参数 primary_key=True        注:当model中如果没有自增列,则自动会创建一个列名为id的列        from django.db import models        class UserInfo(models.Model):            # 自动创建一个列名为id的且为自增的整数列            username = models.CharField(max_length=32)        class Group(models.Model):            # 自定义自增列            nid = models.AutoField(primary_key=True)            name = models.CharField(max_length=32)    SmallIntegerField(IntegerField):        - 小整数 -32768 ~ 32767    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)        - 正小整数 0 ~ 32767    IntegerField(Field)        - 整数列(有符号的) -2147483648 ~ 2147483647    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)        - 正整数 0 ~ 2147483647    BigIntegerField(IntegerField):        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807    自定义无符号整数字段        class UnsignedIntegerField(models.IntegerField):            def db_type(self, connection):                return 'integer UNSIGNED'        PS: 返回值为字段在数据库中的属性,Django字段默认的值为:            'AutoField': 'integer AUTO_INCREMENT',            'BigAutoField': 'bigint AUTO_INCREMENT',            'BinaryField': 'longblob',            'BooleanField': 'bool',            'CharField': 'varchar(%(max_length)s)',            'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',            'DateField': 'date',            'DateTimeField': 'datetime',            'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',            'DurationField': 'bigint',            'FileField': 'varchar(%(max_length)s)',            'FilePathField': 'varchar(%(max_length)s)',            'FloatField': 'double precision',            'IntegerField': 'integer',            'BigIntegerField': 'bigint',            'IPAddressField': 'char(15)',            'GenericIPAddressField': 'char(39)',            'NullBooleanField': 'bool',            'OneToOneField': 'integer',            'PositiveIntegerField': 'integer UNSIGNED',            'PositiveSmallIntegerField': 'smallint UNSIGNED',            'SlugField': 'varchar(%(max_length)s)',            'SmallIntegerField': 'smallint',            'TextField': 'longtext',            'TimeField': 'time',            'UUIDField': 'char(32)',    BooleanField(Field)        - 布尔值类型    NullBooleanField(Field):        - 可以为空的布尔值    CharField(Field)        - 字符类型        - 必须提供max_length参数, max_length表示字符长度    TextField(Field)        - 文本类型    EmailField(CharField):        - 字符串类型,Django Admin以及ModelForm中提供验证机制    IPAddressField(Field)        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制    GenericIPAddressField(Field)        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6        - 参数:            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"    URLField(CharField)        - 字符串类型,Django Admin以及ModelForm中提供验证 URL    SlugField(CharField)        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)    CommaSeparatedIntegerField(CharField)        - 字符串类型,格式必须为逗号分割的数字    UUIDField(Field)        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证    FilePathField(Field)        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能        - 参数:                path,                      文件夹路径                match=None,                正则匹配                recursive=False,           递归下面的文件夹                allow_files=True,          允许文件                allow_folders=False,       允许文件夹    FileField(Field)        - 字符串,路径保存在数据库,文件上传到指定目录        - 参数:            upload_to = ""      上传文件的保存路径            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage    ImageField(FileField)        - 字符串,路径保存在数据库,文件上传到指定目录        - 参数:            upload_to = ""      上传文件的保存路径            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage            width_field=None,   上传图片的高度保存的数据库字段名(字符串)            height_field=None   上传图片的宽度保存的数据库字段名(字符串)    DateTimeField(DateField)        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]    DateField(DateTimeCheckMixin, Field)        - 日期格式      YYYY-MM-DD    TimeField(DateTimeCheckMixin, Field)        - 时间格式      HH:MM[:ss[.uuuuuu]]    DurationField(Field)        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型    FloatField(Field)        - 浮点型    DecimalField(Field)        - 10进制小数        - 参数:            max_digits,小数总长度            decimal_places,小数位长度    BinaryField(Field)        - 二进制类型
字段

 

 

补充:

ForeignKey.on_delete

 

ForeignKey.on_delete¶当一个ForeignKey 引用的对象被删除时,Django 默认模拟SQL 的ON DELETE CASCADE 的约束行为,并且删除包含该ForeignKey的对象。这种行为可以通过设置on_delete 参数来改变。例如,如果你有一个可以为空的ForeignKey,在其引用的对象被删除的时你想把这个ForeignKey 设置为空:user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)on_delete 在django.db.models中可以找到的值有:CASCADE¶级联删除;默认值。PROTECT¶抛出ProtectedError 以阻止被引用对象的删除,它是django.db.IntegrityError 的一个子类。SET_NULL¶把ForeignKey 设置为null; null 参数为True 时才可以这样做。SET_DEFAULT¶ForeignKey 值设置成它的默认值;此时必须设置ForeignKey 的default 参数。SET()¶设置ForeignKey 为传递给SET() 的值,如果传递的是一个可调用对象,则为调用后的结果。在大部分情形下,传递一个可调用对象用于避免models.py 在导入时执行查询:from django.conf import settingsfrom django.contrib.auth import get_user_modelfrom django.db import modelsdef get_sentinel_user():    return get_user_model().objects.get_or_create(username='deleted')[0]class MyModel(models.Model):    user = models.ForeignKey(settings.AUTH_USER_MODEL,                             on_delete=models.SET(get_sentinel_user))DO_NOTHING¶Take no action. 如果你的数据库后端强制引用完整性,它将引发一个IntegrityError ,除非你手动添加一个ON DELETE 约束给数据库自动(可能要用到初始化的SQL)。
related_name   #反向查询的别名,就可以代替 表名_set

 

limit_choices_to={}  #用于选择时option只显示按条件过滤后的选项#示例limit_choices_to={'depart_id__in':[1008,1009]}limit_choices_to={'depart_id':1001,}

 

auto_now 与 auto_now_add

DateTimeField.auto_now这个参数的默认值为false,设置为true时,能够在保存该字段时,将其值设置为当前时间,并且每次修改model,都会自动更新。因此这个参数在需要存储“最后修改时间”的场景下,十分方便。需要注意的是,设置该参数为true时,并不简单地意味着字段的默认值为当前时间,而是指字段会被“强制”更新到当前时间,你无法程序中手动为字段赋值;如果使用django再带的admin管理器,那么该字段在admin中是只读的。DateTimeField.auto_now_add这个参数的默认值也为False,设置为True时,会在model对象第一次被创建时,将字段的值设置为创建时的时间,以后修改对象时,字段的值不会再更新。该属性通常被用在存储“创建时间”的场景下。与auto_now类似,auto_now_add也具有强制性,一旦被设置为True,就无法在程序中手动为字段赋值,在admin中字段也会成为只读的。auto_now_add = True用于创建时间auto_now = True用于更新时间

 

db_index = True 表示设置索引unique(唯一的意思) = True 设置唯一索引联合唯一class Meta:unique_together = ( ('email','ctime'),)联合索引(不做限制)index_together = (('email','ctime'),)
class Meta:        verbose_name = "课程大类"  #人类可读对象名        verbose_name_plural = "课程大类" #人类可读对象名复数

 

多级表关系以及参数

ForeignKey(ForeignObject) # ForeignObject(RelatedField)        to,                         # 要进行关联的表名        to_field=None,              # 要关联的表中的字段名称        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为                                        - models.CASCADE,删除关联数据,与之关联也删除                                        - models.DO_NOTHING,删除关联数据,引发错误IntegrityError                                        - models.PROTECT,删除关联数据,引发错误ProtectedError                                        - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)                                        - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)                                        - models.SET,删除关联数据,                                                      a. 与之关联的值设置为指定值,设置:models.SET(值)                                                      b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)                                                        def func():                                                            return 10                                                        class MyModel(models.Model):                                                            user = models.ForeignKey(                                                                to="User",                                                                to_field="id"                                                                on_delete=models.SET(func),)        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:                                    # 如:                                            - limit_choices_to={'nid__gt': 5}                                            - limit_choices_to=lambda : {'nid__gt': 5}                                            from django.db.models import Q                                            - limit_choices_to=Q(nid__gt=10)                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')        db_constraint=True          # 是否在数据库中创建外键约束        parent_link=False           # 在Admin中是否显示关联数据    OneToOneField(ForeignKey)        to,                         # 要进行关联的表名        to_field=None               # 要关联的表中的字段名称        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为                                    ###### 对于一对一 ######                                    # 1. 一对一其实就是 一对多 + 唯一索引                                    # 2.当两个类之间有继承关系时,默认会创建一个一对一字段                                    # 如下会在A表中额外增加一个c_ptr_id列且唯一:                                            class C(models.Model):                                                nid = models.AutoField(primary_key=True)                                                part = models.CharField(max_length=12)                                            class A(C):                                                id = models.AutoField(primary_key=True)                                                code = models.CharField(max_length=1)    ManyToManyField(RelatedField)        to,                         # 要进行关联的表名        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:                                    # 如:                                            - limit_choices_to={'nid__gt': 5}                                            - limit_choices_to=lambda : {'nid__gt': 5}                                            from django.db.models import Q                                            - limit_choices_to=Q(nid__gt=10)                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')        symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段                                    # 做如下操作时,不同的symmetrical会有不同的可选字段                                        models.BB.objects.filter(...)                                        # 可选字段有:code, id, m1                                            class BB(models.Model):                                            code = models.CharField(max_length=12)                                            m1 = models.ManyToManyField('self',symmetrical=True)                                        # 可选字段有: bb, code, id, m1                                            class BB(models.Model):                                            code = models.CharField(max_length=12)                                            m1 = models.ManyToManyField('self',symmetrical=False)        through=None,               # 自定义第三张表时,使用字段用于指定关系表        through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表                                        from django.db import models                                        class Person(models.Model):                                            name = models.CharField(max_length=50)                                        class Group(models.Model):                                            name = models.CharField(max_length=128)                                            members = models.ManyToManyField(                                                Person,                                                through='Membership',                                                through_fields=('group', 'person'),                                            )                                        class Membership(models.Model):                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)                                            inviter = models.ForeignKey(                                                Person,                                                on_delete=models.CASCADE,                                                related_name="membership_invites",                                            )                                            invite_reason = models.CharField(max_length=64)        db_constraint=True,         # 是否在数据库中创建外键约束        db_table=None,              # 默认创建第三张表时,数据库中表的名称

  

 

 

 

更多详见

一旦你建立好数据模型之后,django会自动生成一套数据库抽象的API,可以让你执行关于表记录的增删改查的操作。

 

 

创建命令

 

python manage.py makemigrations  #生成文件python manage.py migrate   #创建表

 

 

sql语句日志

 

在配置文件写

LOGGING = {    'version': 1,    'disable_existing_loggers': False,    'handlers': {        'console':{            'level':'DEBUG',            'class':'logging.StreamHandler',        },    },    'loggers': {        'django.db.backends': {            'handlers': ['console'],            'propagate': True,            'level':'DEBUG',        },    }}
View Code

 

单表操作

 

查询记录API:           (1)Student.objects.all()    #返回的QuerySet类型 查询所有记录    [obj1,obj2....]                       (2)Student.objects.filter() #返回的QuerySet类型 查询所有符合条件的记录           (3)Student.objects.exclude()#返回的QuerySet类型 查询所有不符合条件的记录           (4)Student.objects.get()    #返回的models对象   查询结果必须有且只有一个,否则报错           (5)Student.objects.all().first()      #返回的models对象   查询结果集合中的第一个           (6)Student.objects.filter().last()    #返回的models对象   查询结果集合中的最后一个           (7)Student.objects.all().values("name","class_id")  #返回的QuerySet类型  ,列表中存放的字典           (8)Student.objects.all().values_list("name","class_id")  #返回的QuerySet类型  ,列表中存放的元组           (9)Student.objects.all().order_by("class_id")   # 按指定字段排序,不指定,按主键排序           (9.1)Student.objects.all().order_by("-class_id")   # 按指定字段 降序 排序           (10)Student.objects.all().count()  # 返回的记录个数  数字类型           (11)Student.objects.all().values("name").distinct()  #字段去重,用在values() 后           (12)Student.objects.all().exist()  #判断是否为空,如果QuerySet包含数据,就返回True,否则返回False 原理是limit 1         单表查询之双下划线 __            Student.objects.filter()                models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值        lt 小于  gt大于             models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据            models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in                         models.Tb1.objects.filter(name__contains="ven")  #包含ven  区分大小写            models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感                         models.Tb1.objects.filter(id__range=[1, 2])      # 范围bettwen and  什么到什么之间(包含最后一个)                         startswith, #什么开头            istartswith, #什么开头,大小写不敏感            endswith,  #什么结尾            iendswith #什么结尾,大小写不敏感                   添加记录:          方式1:              s=Student(name='',birth='',class_id='')               s.save()                 方式2:           stu_obj=Student.objects.create(name='',birth='',class_id='') # stu_obj是添加的记录对象                        删除记录:            Student.objects.filter(nid=1).delete()  #  QuerySet类型调用                修改记录:             Student.objects.filter(nid=1).update(name="yuan")  #  QuerySet类型调用

补充:

only 和 defer

user_list = models.User.objects.all()				# 相当于SQL语句 select * from user				# user_list = QuerySet() = [obj(*),obj(*),obj(*) ]												user_list = models.User.objects.all().only('id','name')				# 只查询id,name这两个字段,不取所有				# select id,name from user 				# user_list = QuerySet() = [obj(id,name),obj(id,name),obj(id,name) ]				# 如果取id,name之外的字段就会再自动走一遍查询,会降低效率				# for item in user_list:				# 	item.id				# 	item.age  重新走数据库				user_list = models.User.objects.all().defer('id','name')				# 和only相反,不取这几个字段									user_list = models.User.objects.all().vlaues('id','name')				# select id,name from user 				# user_list = QuerySet() = [{'id':1,'name':'老男孩'}, ]				# for item in user_list:				# 	item['id']				# 	item['name']

  

 

 

 

 

添加表记录

 

普通字段

方式1publish_obj=Publish(name="人民出版社",city="北京",email="renMin@163.com")publish_obj.save() # 将数据保存到数据库方式2publish_obj=Publish.objects.create(name="人民出版社",city="北京",email="renMin@163.com")方式3表.objects.create(**request.POST.dict())

 

外键字段

方式1:   publish_obj=Publish.objects.get(nid=1)   Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=665,pageNum=334,publish=publish_obj) 方式2:   Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=665,pageNum=334,publish_id=1)  

 

多对多字段

book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-11-12",price=69,pageNum=314,publish_id=1) author_yuan=Author.objects.create(name="yuan",age=23,authorDetail_id=1)author_egon=Author.objects.create(name="egon",age=32,authorDetail_id=2) book_obj.authors.add(author_egon,author_yuan)    #  将某个特定的 model 对象添加到被关联对象集合中。   =======    book_obj.authors.add(*[]) book_obj.authors.add(1,2)   #可以直接放作者对象的idbook_obj.authors.create()      #创建并保存一个新对象,然后将这个对象加被关联对象的集合中,然后返回这个新对象。

 

解除关系

book_obj.authors.remove()     # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[])book_obj.authors.clear()       #清空被关联对象集合。 book_obj.authors.set()       #先清空再设置

 

基于对象的跨表查询:   子查询

 

一对多查询

# 查询nid=1的书籍的出版社所在的城市book_obj=Book.objects.get(nid=1)print(book_obj.publish.city) # book_obj.publish 是nid=1的书籍对象关联的出版社对象 

 

反向查询:(按表名book_set)

# 查询 人民出版社出版过的所有书籍     publish=Publish.objects.get(name="人民出版社")     book_list=publish.book_set.all()  # 与人民出版社关联的所有书籍对象集合     for book_obj in book_list:        print(book_obj.title)

 

 

一对一查询

正向查询(按字段:authorDetail):

# 查询egon作者的手机号     author_egon=Author.objects.get(name="egon")    print(author_egon.authorDetail.telephone)

反向查询(按表名:author):

# 查询所有住址在北京的作者的姓名     authorDetail_list=AuthorDetail.objects.filter(addr="beijing")     for obj in authorDetail_list:        print(obj.author.name)

 

 

多对多查询

正向查询 (按字段)

# 金瓶眉所有作者的名字以及手机号     book_obj=Book.objects.filter(title="金瓶眉").first()     authors=book_obj.authors.all()     for author_obj in authors:         print(author_obj.name,author_obj.authorDetail.telephone)

 

反向查询(按表名:book_set)

# 查询egon出过的所有书籍的名字     author_obj=Author.objects.get(name="egon")    book_list=author_obj.book_set.all() #与egon作者相关的所有书籍     for book_obj in book_list:        print(book_obj.title)

 

基于双下划线的跨表查询:  join查询

 

关键点:正向查询按字段,反向查询按表明。

 

一对多

查询活着的出版社名称        ret=Book.objects.filter(title="金瓶没").values("publish__name") # 
print(ret) Publish.objects.filter(book__title="金瓶没").values("name") 查询沙河出版社出版过的书籍名称 ret=Publish.objects.filter(name="人民出版社").values("book__title") print(ret) Book.objects.filter(publish__name="人民出版社").values("title")

 

多对多

查询活着3所有作者的名字        ret=Book.objects.filter(title="金瓶没4").values_list("authors__name")        print(ret)        查询alex出版过的所有书籍        ret=Author.objects.filter(name="alex").values("book__title")        print(ret)        Book.objects.filter(authors__name="alex").values("title")

 

一对一

查询地址在烟台并且email是789的作者的名字        ret=AuthorDetail.objects.filter(addr="烟台",email=789).values("author__name")        print(ret)         email以456开头的作者出版过的所有书籍名称以及出版社名称

 

多联

email以456开头的作者出版过的所有书籍名称以及出版社名称        ret=Book.objects.filter(authors__authordetail__email__startswith="456").values("title","publish__name")        print(ret)

 

聚合查询与分组查询

 

导入

from django.db.models import Avg,Sum,Count,Min,Max

 

 

聚合:aggregate(*args, **kwargs)

 

# 计算所有图书的平均价格    >>> from django.db.models import Avg    >>> Book.objects.all().aggregate(Avg('price'))    {
'price__avg': 34.35}

 

aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。

键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

>>> Book.objects.aggregate(average_price=Avg('price')){
'average_price': 34.35}

 

如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

>>> from django.db.models import Avg, Max, Min>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price')){
'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}

 

 

 

分组:annotate() 

 

为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。

annotate的返回值是querySet,如果不想遍历对象,可以用上valuelist:

查询每一个出版社出版过的书籍个数    ret=Publish.objects.all().annotate(c=Count("book__title"))    for pub_obj  in ret:        print(pub_obj.name,pub_obj.c)    查询每一本书的作者个数    ret=Book.objects.all().annotate(counts=Count("authors__id")).values("title","counts")    print(ret)    查询每一个作者出版过的书籍的平均价格    ret=Author.objects.all().annotate(avgprice=Avg("book__price")).values("name","avgprice")    print(ret)查询各个作者出的书的总价格:# 按author表的所有字段 group by    queryResult=Author.objects              .annotate(SumPrice=Sum("book__price"))              .values_list("name","SumPrice")    print(queryResult)    # 按authors__name group by    queryResult2=Book.objects.values("authors__name")              .annotate(SumPrice=Sum("price"))              .values_list("authors__name","SumPrice")    print(queryResult2)统计每一本以py开头的书籍的作者个数: queryResult=Book.objects.filter(title__startswith="Py").annotate(num_authors=Count('authors'))统计不止一个作者的图书:queryResult=Book.objects          .annotate(num_authors=Count('authors'))          .filter(num_authors__gt=1)根据一本图书作者数量的多少对查询集 QuerySet进行排序:Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

 

F 与 Q 查询

 

F查询 (可对字段的值进行操作,int类型)

 

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

# 查询评论数大于收藏数的书籍    from django.db.models import F   Book.objects.filter(commnetNum__lt=F('keepNum'))

Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

# 查询评论数大于收藏数2倍的书籍    Book.objects.filter(commnetNum__lt=F('keepNum')*2)

修改操作也可以使用F函数,比如将每一本书的价格提高30元:

Book.objects.all().update(price=F("price")+30) 

 

 

 

Q 查询( "|"  "&"  "~" )

 

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用对象

from django.db.models import QQ(title__startswith='Py')

 

Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

 

等同于下面的SQL WHERE 子句:

WHERE name ="yuan" OR name ="egon"

 

你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

 

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),                                  title__icontains="python"                                 )

 

补充用法:

from django.db.models import Qcondition = Q()condition.connector = "or" #默认是and关系condition.children.append(("title","linux"))condition.children.append(("price",100))#Book.objects.filter(condition) 相当于 Book.objects.filter(Q(title="linux")|Q(price=100))

  

 

ContentType

from django.db import modelsfrom django.contrib.contenttypes.models import ContentTypefrom django.contrib.contenttypes.fields import GenericForeignKey,GenericRelation# Create your models here.class Course(models.Model):    """    普通课程    """    title = models.CharField(max_length=32)    # 仅用于反向查找,不会生成真实的字段    pricepolicy_list = GenericRelation(to="PricePolicy")class DegreeCourse(models.Model):    """    学位课程    """    title = models.CharField(max_length=32)    # 仅用于反向查找,不会生成真实的字段    pricepolicy_list = GenericRelation(to="PricePolicy")class PricePolicy(models.Model):    """    价格策略    """    price = models.IntegerField()    period = models.IntegerField()    content_type = models.ForeignKey(ContentType,verbose_name="关联的表名称")    object_id = models.IntegerField(verbose_name="关联的表中的数据的行ID")    # 帮助你快速实现content_type操作,不会生成真实的字段    content_obj = GenericForeignKey('content_type',"object_id")# 会自动生成一张ContentType表,里面存着所有的表名称和对应的app名# 插入数据的两种方法# 方法一:#插入表id和数据id# cobj = ContentType.objects.first(model="course").first() #找到对应的表# obj = Course.objects.filter(title="python全栈").first() # 找到表里的对象# PricePolicy.objects.create(price=99,period=30,content_type_id=cobj.id,object_id=obj.id)## 方法二:#直接让content_obj等于一个数据对象# PricePolicy.objects.create(price=99,period=30,content_obj=obj)#查询# 3. 根据课程ID获取课程, 并获取该课程的所有价格策略course = models.Course.objects.filter(id=1).first()price_policys = course.pricepolicy_list.all().values("price","period","content_type__model","object_id").distinct()print(price_policys)

  

 

与性能相关

 

注意:    使用Foreignkey,原因:        - 约束        - 节省硬盘    大型程序:        FK,不用原因:        - 约束-->     自己代码判断        - 节省硬盘--> 可以浪费,因为要加速 链表查询速度会慢

 

 

1. select_related  主动进行链表查询

问题:查看所有用户,并打印用户姓名、年龄、用户所在部门名称。会有11次查询:	users = 用户表.objects.all()	for row in users:		row.name		row.age		row.dp.title #每执行一次链表查询一次			print(users.query) # 查看查询语句  select id,name,age,e,wpd from xxx解决方法一: 使用values	users = 用户表.objects.all().values('name','age','dp__title')	for row in users:		row['name']		row['age']		row['dp__title']解决方法二:使用select_related 指定链表	users = 用户表.objects.all().select_related('dp')	for row in users:		row.name		row.age		row.dp.title	print(users.query) # select id,name,age,e,wpd from 用户表 join 部门表

 

2. prefetch_related  两次单表查询

2次单表查询		select * from users;	# 将所有部门ID获取到:[1,2,3,4,8]        # 再去部门表查询相应的部门	select * from department where id in [1,2,3,4,8]	users = 用户表.objects.all().prefetch_related('dp')	for row in users:		row.name		row.age		row.dp.title

  

 

执行原生sql语句

 

1. connection, connections

from django.db import connection, connections        cursor = connections["default"].cursor()        cursor.execute("""select * from api_userinfo WHERE username=%s""",["zhou"])        row = cursor.fetchall()        print(row)  #[(1, '周军豪', 'zhou', '123', None)]        return HttpResponse("ok")
################### 原生SQL ###################    from django.db import connection, connections    cursor = connection.cursor()  # cursor = connections['default'].cursor()    cursor.execute("""SELECT * from auth_user where id = %s""", [1])    row = cursor.fetchone() # fetchall()/fetchmany(..)

  

2. raw

def raw(self, raw_query, params=None, translations=None, using=None):    # 执行原生SQL    models.UserInfo.objects.raw('select * from userinfo')    # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名    models.UserInfo.objects.raw('select id as nid from 其他表')    # 为原生SQL设置参数    models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])    # 将获取的到列名转换为指定列名    name_map = {
'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 指定数据库 models.UserInfo.objects.raw('select * from userinfo', using="default")

 

 

3. extra

# mysql 用date_format(date,format)  sqllist用strftime(format,date)        c = models.Comment.objects.extra(select={
'comment_data':"strftime('%%Y-%%m-%%d %%H:%%M:%%S',date)"}).values("comment_data") x = UserInfo.objects.extra(select={
'new_id': "select username from api_userinfo where api_userinfo.id > %s"}, select_params=(1,)).values() y = UserInfo.objects.extra(where=['id=%s'], params=[1,]).values() z = UserInfo.objects.extra(where=["username='zhou' OR username = 'yu'", "name = '周军豪'"]).values()

 

转载于:https://www.cnblogs.com/zhoujunhao/p/7999590.html

你可能感兴趣的文章
关于信息隐藏的感想及其它废话
查看>>
RCP学习:Bundle的生命周期
查看>>
现代 C++ 编程指南
查看>>
记录我的旅程8之JavaScript Dom学习笔记
查看>>
.NET中的加密算法总结(自定义加密Helper类续)
查看>>
sql 跨服务器数据库查询数据
查看>>
VBA SQLServer 基本操作
查看>>
在HTML语言网页中加载视频的代码
查看>>
POJ 1274 The Perfect Stall(二分图匹配)
查看>>
PHP全局错误处理
查看>>
数的1、2、3次方是否均为回文数
查看>>
kramdown 0.14.0,Ruby 的 Markdown 解析器
查看>>
[原创]ExtAspNet秘密花园(十五) — 表格概述
查看>>
GNU make manual 翻译( 一百四十四)
查看>>
第二十四章 异常和错误处理 1异常
查看>>
Java异常处理机制
查看>>
Linux 内核启动流程(转)
查看>>
reverse()的实现字符串反转和模板reverse的实现
查看>>
Qios.DevSuite 免费的winform控件库
查看>>
200多个js技巧代码(七)
查看>>