首页 > 其他 > 详细

django框架之模型层

时间:2019-06-13 23:50:43      阅读:224      评论:0      收藏:0      [点我收藏+]

?? 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)    

 

?6?annotate 分组查询

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)

 

 

django框架之模型层

原文:https://www.cnblogs.com/zhouyongv5/p/11011606.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!