django框架之模型层

🍁 Django ORM 常用字段和参数

1常用字段

AutoField

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

IntegerField

整数类型,范围在 -2147483648 to 2147483647

CharField

字符类型,必须提供max_length参数,表示字符长度。对应MySQL数据库中的varchar类型,没有设置对应char类型的字段,但Django可以自定义新的字段

DateField

日期字段,格式 YYYY-MM-DD,相当于Python中的datetime.date()实例

DateTimeField

日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例

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

 字段合集
字段补充
对应关系:
    '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字段对应关系
ORM字段与MySQL字段对应关系
from django.db import models


class MyCharField(models.Field):
    def __init__(self, max_length, *args, **kwargs):
        self.max_length = max_length
        super().__init__(max_length=max_length, *args, **kwargs)

    def db_type(self, connection):
        return 'char(%s)' % self.max_length
自定义字段

 

2字段参数

null          表示某个字段可以为空

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

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

default       为该字段设置默认值。

choices    该字段为选择字段,是一个元组套元组的数据提供选择,子元组第一个参数为实际存的数据;第二个参数为展示的数据

choices = ((1, ''), (2, ''), (3, '其他'))
gender = models.IntegerField(choices=choices, default=2)

res = models.User.objects.filter(id=1).first()
print(res.gender)   # 2
print(res.get_gender_display())  # 女  获取编号对应的注释

 

3 DateField & DateTimeField

auto_now_add    配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。

auto_now        配置上auto_now=True,每次更新数据记录的时候会更新该字段。

 orm操作

class User(models.Model):
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    register_time = models.DateTimeField(auto_now_add=True)
    ...
    
    def save(self):
        # 在对象调用save保存到数据库之前,在这里可以拦截进行相应的操作
        super().save()
    
    def delete(self):
        # 在对象调用delete删除数据之前,在这里可以拦截进行相应的操作
        super().delete()

 

🍁 django ORM 关联字段

 字段参数: 

to              设置要关联的表

to_field        设置要关联的表字段

on_delete       删除关联表中的数据时,当前表与其关联行的行为

models.CASCADE  删除关联数据,与之关联也删除,django2.0以上版本需要添加该参数

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(可执行对象)
View Code

 

1 ForeignKey

 外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方;ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

  

2 OneToOneField

一对一字段,通常用来扩展已有字段,关联字段放在相关联的常用那张表里面;

比如一个人的信息:常用信息一张表,隐私不常用的信息另一张表,通过一对一外键关联

  3 ManyToManyField

  多对多关系,关联关系建立常用的那张表一方,关联关系在创建的第三张表中

 

🍁 一般操作

配置一下参数,使得我们可以直接在Django页面中运行我们的测试脚本

import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day5.settings")
    import django
    django.setup()
    from app01 import models

save & update 的区别

save():将数据的字段重新保存一遍 ,相对之下效率降低

update():只更改修改了的字段

数据库查询优化:select_related predfetch_related

 

🍁 查询必会十三条***********

<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()非常相似,它返回的是一个元组序列
<13> distinct():           从返回结果中剔除重复纪录

其中:红色方法返回QuerySet对象,

  values返回包含字典的QuerySet对象、values_list返回包含元组的QuerySet对象

  get、first、last返回数据对象,count返回数字,exists返回布尔值.....

单表操作

新增数据
models.User.objects.create(name='pok', age=31, register_time='2018-01-21')  # create新增数据
user_obj = models.User(name='lkj', age=20, register_time='2018-12-03')  # 对象绑定方法 新增数据
user_obj.save()
from datetime import datetime
ctime = datetime.now()   # 相当于 DateField(auto_now_add=True)
models.User.objects.create(name='xsd', age=18, register_time=ctime)

修改数据
user_obj = models.User.objects.filter(name='qq').first()  # 基于对象
user_obj.age = 41
user_obj.save()
models.User.objects.filter(name='ee').update(age=88)  # 基于QuerySet

删除数据
models.User.objects.filter(**kwargs).delete()  # 基于QuerySet,批量操作
user_obj = models.User.objects.filter(name='pok').first()   # 基于对象
user_obj.delete()

查询数据13条
models.User.objects.all()  # 查询所有数据
models.User.objects.filter(name='pok', age=31)  # 多个条件and关系
models.User.objects.get(name='vsf')  # 数据不存在会报错 User matching query does not exist.
models.User.objects.exclude(name='qq')  # 除了qq以外的
models.User.objects.order_by('name')  # name字段升序
models.User.objects.order_by('-name')  # name字段降序
models.User.objects.order_by('age')  # age字段升序
models.User.objects.order_by('-age')  # age字段降序
models.User.objects.order_by('age').reverse()  # 排序好的数据,reverse反序
models.User.objects.count()  # user表共有6条数据
models.User.objects.all().count()
models.User.objects.all().first()  # 返回第一条数据
models.User.objects.all()[0]  # 不支持负数索引 Negative indexing is not supported.
models.User.objects.all().last()  # 最后一条记录
models.User.objects.all().exists()  # QuerySet是否有数据
models.User.objects.filter(name='ee', age=15).exists()
models.User.objects.values('name')  # 包含搜索字段键值对字典的QuerySet对象<QuerySet [{'name': 'qq'}, {'name': 'ww'}]>
models.User.objects.values('name', 'age')  # <QuerySet [ {'name': 'ww', 'age': 22}]>
models.User.objects.values_list('name')  # 包含搜索字段值组成元组的QuerySet对象<QuerySet [('qq',), ('pok',)]>
models.User.objects.values_list('name', 'age')  # <QuerySet [('qq', 41), ('pok', 31)]>
models.User.objects.values('age').distinct()  # 查询结果去重 <QuerySet [ {'age': 18}, {'age': 31}]>

两个特殊的查询:

# only 与 defer
res = models.Product.objects.values('name')  # 拿到name字典的列表
res = models.Product.objects.only('name')  # 拿到name字段数据的对象,可以再查其他字段,price*4  name*1(执行sql语句次数)
res = models.Product.objects.defer('name')  # 拿到除了name以外字段的对象,可以再查name, price*1  name*4
print(res)
for i in res:
    print(i.name)
print(type(res))

 

🍁 查询之神奇的双下划线

# 神奇的双下划线查询
models.User.objects.filter(age__gt=31)   # 年龄>31岁<QuerySet [<User: 对象qq>, <User: 对象ee>]>
models.User.objects.filter(age__gte=31)  # 年龄>=31岁<QuerySet [<User: 对象qq>,...]>
models.User.objects.filter(age__lt=31)  # 年龄<31岁<QuerySet [<User: 对象ww>,...]>
models.User.objects.filter(age__lte=31)  # 年龄<31岁<QuerySet [<User: 对象ww>,...]>
models.User.objects.filter(age__in=[15, 18])  # 年龄15或18的人<QuerySet [<User: 对象xsd>]>
models.User.objects.filter(age__range=[20, 30])  # 20<=年龄<=30的人<QuerySet [<User: 对象ww>,...]>
models.User.objects.filter(name__range=['a', 'l'])  # 'a'<name首字母<'l'的人<QuerySet [<User: 对象ee>,...]>
models.User.objects.filter(register_time__year='2015')  # 注册年份为2015的人<QuerySet [<User: 对象pojE>]>
models.User.objects.filter(name__contains='e')  # name包含‘e’的人<QuerySet [<User: 对象ee>,...]>
models.User.objects.filter(name__icontains='e')  # 无视大小写 <QuerySet [<User: 对象ee>, <User: 对象pojE>]>
models.User.objects.filter(name__startswith='l')  # name 以‘l’开头
models.User.objects.filter(name__endswith='k')  # name 以‘q’开头

 

🍁 Django框架之多表查询

多表操作如何确立表关系:

一个A能否有多个B   一个B能否有对个A

如果两者都成立                     多对多

如果只有一方可以                   一对多

如果双方都不可以但是两者却有关系   一对一

 

1 正向与反向的概念

正向:两个相关联的表,建立关联字段那张表向被关联表跨表查询数据

反向:两个相关联的表,被关联表向建立关联字段那张表跨表查询数据

2一对多字段的增删查改

#
models.Book.objects.create(publish_id=1)

publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(publish=publish_obj)


#
book_obj = models.Book.objects.filter(id=12).first()
publish_obj = models.Publish.objects.all()


#
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish = new_publish_obj

book_obj = models.Book.objects.filter(pk=1).update(publish_id=2)
book_obj = models.Book.objects.filter(pk=1).update(publish=publish_obj)


#
models.Book.objects.filter(id=12).delete()

book_obj = models.Book.objects.filter(title='红楼梦').first()
book_obj.delete()

 

3多对多字段绑定关系的增删改

添加    add() 支持传入多个 数字&对象

修改    set() 必须传入可迭代对象(元素:数字&对象)

删除  remove() 支持传入多个 数字&对象,不能接收可迭代对象

清空  clear() 不用传参

# book & author 建立绑定关系
book_obj = models.Book.objects.filter(pk=11).first()
book_obj.authors.add(1)
book_obj.authors.add(3, 2)
author_obj = models.Author.objects.filter(pk=4).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj, author_obj1)

# book & author 修改绑定关系
book_obj = models.Book.objects.filter(pk=5).first()
book_obj.authors.set((2,1))
author_list = models.Author.objects.all()
book_obj = models.Book.objects.filter(pk=6).first()
book_obj.authors.set(author_list)

# book & author 删除绑定关系
book_obj = models.Book.objects.filter(pk=6).first()
book_obj.authors.remove(1, 3)
author_obj = models.Author.objects.all().first()
author_list = models.Author.objects.exclude(pk=2)
book_obj.authors.remove(author_obj)
book_obj.authors.remove(*author_list)

# 清空当前表记录对应的绑定关系
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.clear()

 

4基于对象的表查询

  原则:正向查询按字段,反向查询按表名小写

结果多个:正向字段.all(),反向表名小写_set.all()

book = models.Book.objects.filter(title='三国演义').first()    # 一对多:正向
email = book.publish.email

book = models.Book.objects.filter(title='西游记’).first()    # 多对多:正向
author = book.authors.all()

author = models.Author.objects.filter(name='jason').first()     # 一对一:正向
phone = author.authordetail.phone    

publish = models.Publish.objects.filter(name='东方出版社').first()    # 一对多:反向
books = publish.book_set.all()    

authordetail = models.AuthorDetail.objects.filter(phone=110).first()  # 一对一:反向    
author = authordetail.author.name    

author = models.Author.objects.filter(name='jason').first()      # 多对多:反向
books = author.book_set.all()    

 

5 基于双下划线的表查询

关于查询的两个条件

filter:为过滤条件,字段名不加引号

values:展示的字段名,字段名加引号

查询原则

正向查询按字段,反向查询按表名小写

条件字段名一问  ◔ ‸◔?

条件字段名在当前表,用表字段名;不在当前表,跨的每个表原则名__,直到目标字段名

跨一表查询

# 正向
addr = models.Book.objects.filter(title='三国演义').values('publish__addr','title')
author = models.Book.objects.filter(title='西游记').values('authors__name','title')    
au_addr = models.Author.objects.filter(name='json').values('authordetail__addr')    

# 反向
books = models.Publish.objects.filter(name='南方出版社').values('book__title')    
books = models.Author.objects.filter(name='json').values('book__title')    
author = models.AuthorDetail.objects.filter(phone=120).values(author__name')    

跨二表查询

# 正向
phone = models.Book.objects.filter(title='三国演义').values('authors__authordetail__phone')    

# 反向
models.Author.objects.filter(name='jason').values('authordetail__phone')    
models.AuthorDetail.objects.filter(author__name='jason').values('phone')    
    
models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')    
models.Book.objects.filter(publish__name='东方出版社').values('title','price')    
    
models.Publish.objects.filter(name='东方出版社',book__price__gt=400).values('book__title','book__price')    
models.Book.objects.filter(publish__name='东方出版社').values('title','price')    

 

6annotate分组查询

from django.db.models import Max,Min,Count,Avg,Count
models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')

 示例:

    # 统计每个出版社出版的书的平均价格
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)

 

7 aggregate 聚合查询

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)

 

🍁 Django终端输出SQL语句

在django中,只有QuerySet.query拥有查询SQL语句的方法,当其他对象需要查询SQL语句怎么办呢?

django提供了执行对数据库进行操作时,在终端输出SQL语句的方法,需在django项目的settings.py配置以下代码:

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

🍁 F查询和Q查询

过滤器:将字段值与设定的常量作比较;

F查询:两个字段值作比较,

1. F对象可以与F对象和常数可做加减乘除取模操作

2. 字符串拼接,需要用到Concat操作,和拼接值Value

Q查询:之前的方法中,逗号隔开的条件关系为 and,Q对象提供 or |、 not ~的关系

查询函数可以混合使用Q 对象和关键字参数,之间的关系将为"AND”;但是如果出现Q 对象,它必须在所有关键字参数的前面

# 查询出卖出数大于库存数的商品
from django.db.models import F
ret=models.Product.objects.filter(maichu__gt=F('kucun'))
print(ret)

# 将每个商品的价格提高100块
models.Product.objects.update(price=F('price')+100)

# 符串的拼接,参数位置决定了拼接前后,Value里面是要新增的拼接值
from django.db.models.functions import Concat
from django.db.models import Value
ret3=models.Product.objects.update(name=Concat(F('name'),Value('新款')))


# 卖出数大于100 或者 价格小于100块的 from django.db.models import Q models.Product.objects.filter(Q(maichu__gt=100)|Q(price__lt=100)) # 查询 库存数是100 并且 卖出数不是0 的产品 models.Product.objects.filter(Q(kucun=100)&~Q(maichu=0)) # 查询产品名包含新款, 并且库存数大于60的 models.Product.objects.filter(Q(kucun__gt=60), name__contains="新款")

 

🍁 事务

将多个sql语句操作变成原子性操作,要么同时成功,有一个失败则回滚到原来的状态,保证数据的完整性和一致性

所有放在with范围的的sql语句,作为一个事务执行,不在with范围内则事务结束

# 售出一件商品,同时减少一件库存商品
from django.db.models import F
from django.db import transaction
# 开启事务处理
try:
    with transaction.atomic():
        models.Order.objects.create(num="110110111", product_id=1, count=1)
        models.Product.objects.filter(id=1).update(kucun=F("kucun")-1, maichu=F("maichu")+1)
except Exception as e:
    print(e)

 

 

posted @ 2019-06-13 23:02  zhoyong  阅读(168)  评论(0编辑  收藏  举报