Django灵魂之ORM操作

2 篇文章 0 订阅

一、什么是ORM

点击产看《ORM概念,ORM到底是个什么鬼,怎么用》

二、Django的ORM

在这里插入图片描述

Django 的一个强大的功能是它的对象关系映射Object-Relational Mapper(ORM),它允许你就像使用 SQL 一样去和你的数据库交互。事实上,Django 的 ORM 就是创建 SQL 去查询和操作数据库的一个 Python 式方式,并且获得 Python 风格的结果。 我说的是一种方式,但实际上,它是一种非常聪明的工程方法,它利用了 Python 中一些很复杂的部分,而使得开发者更加轻松。

Django orm的优势:

Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite…,如果数据库迁移,只需要更换Django的数据库引擎即可;

三、Django的常用字段和参数

补充知识点:如何新建一个test.py文件单独作为测试models

1、先去项目的manege.py文件下,copy下图中的代码

在这里插入图片描述

2、在应用下新建一个test.py文件,将复制的代码粘贴进去,并添加代码:
import django
django.setup()

在这里插入图片描述

3.1常用字段

AutoField

int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。

IntegerField

一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)

CharField

字符类型,必须提供max_length参数, max_length表示字符长度。(只对应mysql中的varchar类型,如需char类型,需要自定义)

小补充:自定义字段

在这里插入图片描述
代码示例:

from django.db import models

Django中没有对应的char类型,需要自定义创建

class FixCharField(models.Field):
		'''
    		自定义的char类型的字段类
  		 '''
  		 def ___init__(self,max_length,*args, **kwargs):
  		 		self.max_length = max_length
  		 		super(). __init__(max_length,*args, **kwargs)

		def db_type(self, connection):
			'''
			限定生成的数据库表字段类型char,长度为max_length指定的值
			'''
			    return 'char(%s)' % self.max_length

#应用上面自定义的char类型
class Class(models.Model):
    id=models.AutoField(primary_key=True)
    title=models.CharField(max_length=32)
    class_name=FixCharField(max_length=16)
    gender_choice=((1,'男'),(2,'女'),(3,'保密'))
    gender=models.SmallIntegerField(choices=gender_choice,default=3)
DateField和DateTimeField

日期字段,日期格式,
DateField:表示年月日,相当于Python中的datetime.date()实例。

DateTimeField:表示年月日时分秒 ,相当于Python中的datetime.datetime()

字段下的两个属性:auto_now:每次操作该字段的时间,每操作一次,时间自动更新;
auto_now_add:第一次新增该字段时的时间,往后的操作时间不会改变

其他字段合集(重要)
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

    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)
        - 二进制类型

 字段合集
orm字段与mysql数据库字段的对应关系
对应关系:
    '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)',

ORM字段与MySQL字段对应关系

3.2字段参数

null

用于百事某个字段可以为空

unique

如果设置为unique=True 则该字段在此表中必须是唯一的 。

db_index

如果db_index=True 则代表着为此字段设置索引。

default

为该字段设置默认值

3.3关系字段

3.3.1 ForeignKey

外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多’中'多'的一方

ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

字段参数:
to:

设置要关联的表

to_field:

设置要关联的表的字段

on_delete

当删除关联表的数据时,当前表与其关联的行(hang)的行为

models.CASCADE

删除关联数据,与之关联也删除(级联删除)

db_constraint

是否在数据库中创建外键约束,默认是True

其他字段参数
models.DO_NOTHING
删除关联数据,引发错误IntegrityError


models.PROTECT
删除关联数据,引发错误ProtectedError


models.SET_NULL
删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)


models.SET_DEFAULT
删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)


models.SET

删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

其余字段参数
3.3.2 OneToOneField

一对一字段
通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)

字段参数
to,to_field,on_delete参照外键的字端参数用法
3.3.3 ManyToManyField

多对多字段
Django会自动创建一张虚拟的多对多表

字段参数to(设置要关联的表)

四、单表查询

4.1查询数据必会的13条

<1> all():                  查询所有结果
<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
<4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
<5> order_by(*field):       对查询结果排序('-id')/('price')

<6> reverse():              对查询结果反向排序 	>>>前面要先有排序才能反向
<7> count():                返回数据库中匹配查询(QuerySet)的对象数量。
<8> first():                返回第一条记录
<9> last():                返回最后一条记录
<10> exists():              如果QuerySet包含数据,就返回True,否则返回False
<11> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
<12> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<13> distinct():            从返回结果中剔除重复纪录

详解

<1>all():查询所有结果

在这里插入图片描述
注意⚠️:支持索引取值,但是不能取负数取值
在这里插入图片描述

<2>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象

在这里插入图片描述

<3>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

在这里插入图片描述
异常:
在这里插入图片描述

<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象(可以理解为取反)

在这里插入图片描述

<5> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列

在这里插入图片描述

<6> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

在这里插入图片描述

<7> order_by(*field): 对查询结果排序(默认升序,字段前加“-”减号,变为降序)
reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
<9> distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
<10> count(): 返回数据库中匹配查询(QuerySet)的对象数量。

在这里插入图片描述

<11> first(): 返回第一条记录

在这里插入图片描述

<12> last(): 返回最后一条记录
<13> exists(): 如果QuerySet包含数据,就返回True,否则返回False

4.2必会操作总结

返回QuerySet对象的方法有
all()

filter()

exclude()

order_by()

reverse()

distinct()
特殊的QuerySet
values()       返回一个可迭代的字典序列

values_list() 返回一个可迭代的元祖序列
返回具体对象的
get()

first()

last()
返回布尔值的方法有:
exists()  可作为逻辑判断条件
返回数字
count()

4.3单表操作的增删改

在这里插入图片描述

在这里插入图片描述

删除

在这里插入图片描述

4.4 单表查询值双下划线(重点)

 # 查询年轻大于44岁的用户
    # res = models.User.objects.filter(age__gt=44)
    # print(res)
    # 查询年轻小于44岁的用户
    # res = models.User.objects.filter(age__lt=44)
    # print(res)
    # 查询年轻大于等于44岁的用户
    # res = models.User.objects.filter(age__gte=44)
    # print(res)
    # 查询年轻小于等于44岁的用户
    # res = models.User.objects.filter(age__lte=44)
    # print(res)

    # 查询年龄是44或者22或者73的用户
    # res = models.User.objects.filter(age__in=[44,22,73])
    # print(res)

    # 查询年龄在22到44范围内
    # res = models.User.objects.filter(age__range=[22,44])
    # print(res)


    # 用的是mysql数据库
    # 查询年份
    # res = models.Book.objects.filter(publish_date__year=2019)
    # print(res)


    # 查询名字中包含字母n的用户  sqlite数据库演示不出来大小写的情况!!!
    # res = models.Author.objects.filter(name__contains='n')
    # res = models.Author.objects.filter(name__icontains='n')
    # print(res)
    # res = models.User.objects.filter(name__icontains='e')  # 无视大小写
    # print(res)
    # 查询名字以j开头的用户
    # res = models.User.objects.filter(name__startswith='j')
    # print(res)
    # 查询名字以n结尾的用户
    # res = models.User.objects.filter(name__endswith='n')
    # print(res)

    # 查询注册是在2017年的用户
    # res = models.User.objects.filter(register_time__year=2017)  # sqlite对日期格式不太精准
    # print(res)

集锦

五、多表查询

5.1外键与一对一的关联

创建图书管理系统表(给作者表加一张作者详情表为了一对一的查询),诠释一对一关联其实就是外健关联再加一个唯一性约束而已

ForeignKey(unique=Ture)		>>>		OneToOneField()		
# 即一对一可以用ForeignKey来做,但是需要设唯一性约束并且会报警告信息,不建议使用,建议用OneToOneField
# 用了OneToOneField和用ForeignKey会自动在字段后面加_id
# 用了ManyToMany会自动创建第三张表

5.2 一对多的增删改查(基于书籍记录)

针对外键关联的字段 两种添加方式
第一种通过publish_id
第二种通过publish传出版社对象
删除书籍直接查询删除即可,删除出版社会级联删除
编辑数据也是两种对应的方式(对象点的方式(这里能点publish和publish_id)最后点save(),queryset方式update())

新增

在这里插入图片描述

修改

在这里插入图片描述

删除

在这里插入图片描述

5.3 多对多的增删改查

“”“前提:先获取书籍对象,再通过书籍对象点authors来进行书籍作者的增删改查”""
#1.给书籍新增作者add
1.add可以传作者id,也可以直接传作者对象,并且支持传多个位置参数(不要混着用)
2.给书籍删除作者remove
# 1.remove同样可以传id,对象,并且支持传多个位置参数(不要混着用)
3.直接清空书籍对象所有的作者数据clear()不用传任何参数
4.修改书籍对象所关联的作者信息set,注意点set括号内必须传可迭代对象,里面可以传id,对象

总结:一对多增删改,多对多add,remove,clear,set

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

清空

在这里插入图片描述

六、正向、反向概念

6.1 解释

一对一:
# 一对一
# 正向:author---关联字段在author表里--->authordetail		按字段
# 反向:authordetail---关联字段在author表里--->author		按表名小写

在这里插入图片描述
在这里插入图片描述

一对多:
# 一对多
# 正向:book---关联字段在book表里--->publish		按字段
# 反向:publish---关联字段在book表里--->book		按表名小写_set.all() 因为一个出版社对应着多个图书

在这里插入图片描述
在这里插入图片描述

多对多
# 多对多
# 正向:book---关联字段在book表里--->author		按字段
# 反向:author---关联字段在book表里--->book		按表名小写_set.all() 因为一个作者对应着多个图书

在这里插入图片描述
在这里插入图片描述

6.2 基于双划线的查询

-连表查询
			-正向:按字段,跨表可以在filter,也可以在values中
			-反向:按表名小写,跨表可以在filter,也可以在values中
正向在这里插入图片描述
反向

在这里插入图片描述

练习集锦
# 查询jason作者的手机号
    # 正向
    # res = models.Author.objects.filter(name='jason').values('authordetail__phone')
    # print(res)
    # 反向
    # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
    # print(res)

    # 查询出版社为东方出版社的所有图书的名字和价格
    # 正向
    # res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')
    # print(res)
    # 反向
    # res = models.Book.objects.filter(publish__name='东方出版社').values('title','price')
    # print(res)

    # 查询东方出版社出版的价格大于400的书
    # 正向
    # res = models.Publish.objects.filter(name="东方出版社",book__price__gt=400).values('book__title','book__price')
    # print(res)
    # 反向
    # res = models.Book.objects.filter(price__gt=400,publish__name='东方出版社').values('title','price')
    # print(res)

总结:总结 其实在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照“正向按字段”反向“按表名小写”来查即可

七、聚合查询(aggregate)

aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

用到的内置函数
rom django.db.models import Avg, Sum, Max, Min, Count
示例:
from django.db.models import Max, Min, Count, Sum, Avg
    # 查询所有书籍的作者个数
    # res = models.Book.objects.filter(pk=3).aggregate(count_num=Count('authors'))
    # print(res)
    # 查询所有出版社出版的书的平均价格
    # res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
    # print(res)  # 4498.636
    # 统计东方出版社出版的书籍的个数
    # res = models.Publish.objects.filter(name='东方出版社').aggregate(count_num=Count('book__id'))
    # print(res)

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

>>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}

八、分组查询(annotate)

在这里插入图片描述

这里需要注意的是annotate分组依据就是他前面的值,如果前面没有特点的字段,则默认按照ID分组,这里有Publish字段,所以按照Publish字段分组

示例集锦:

# 统计每个出版社出版的书的平均价格
    # res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
    # print(res)
    # 统计每一本书的作者个数
    # res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')
    # print(res)
    # 统计出每个出版社卖的最便宜的书的价格
    # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
    # print(res)
    # 查询每个作者出的书的总价格
    # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
    # print(res)

总结:

1、value里面的参数对应的是sql语句中的select要查找显示的字段,
2、filter里面的参数相当于where或者having里面的筛选条件
3、annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值

魔鬼补充:
在这里插入图片描述

参考博客老司机jason

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值