zoukankan      html  css  js  c++  java
  • Django之模型层

    Django ORM常用字段和参数

    常用字段

    AutoField

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

    IntegerField

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

    CharField

    字符类型,必须提供max_length参数, max_length表示字符长度。

    DateField

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

    DateTimeField

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

    自定义字段

    from django.db import models
    
    # Create your models here.
    #Django中没有对应的char类型字段,但是我们可以自己创建
    class FixCharField(models.Field):
        '''
        自定义的char类型的字段类
        '''
        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):
            '''
            限定生成的数据库表字段类型char,长度为max_length指定的值
            :param connection:
            :return:
            '''
            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)
    

    字段集合

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

    字段参数

    null

    用于表示某个字段可以为空。

    unique

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

    db_index

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

    default

    为该字段设置默认值。

    时间字段DataTimeFiled 和 DataFiled

    auto_now_add

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

    auto_now

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

    关系字段

    1.ForeignKey

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

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

    字段参数:

    to

    设置要关联的表

    to_field

    设置要关联的表的字段

    on_delete

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

    models.CASCADE

    删除关联数据,与之关联也删除

    db_constraint

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

    2.OneToOneFiled

    一对一字段。

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

    字段参数:

    to

    设置要关联的表。

    to_field

    设置要关联的字段。

    on_delete

    级联操作 当删除关联表中的数据时,当前表与其关联的行的行为。

    3.ManyToManyFiled

    字段参数与一对多类似,不同在于不在表中产生具体字段,只是标识了多对多关系,Django自动产生第三张表

    在Python脚本调用Django环境

    从manage.py取下面代码置于脚本环境中

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

    单表操作

    class Book(models.Model):
      	name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=8,decimal_place=2)
        publish = models.CharField(max_length=32)
        author = models.CharField(max_length=32)
        create_time = models.DateField(null=True)
        # 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
        # 配置上auto_now=True,每次更新数据记录的时候会更新该字段。
    

    新增数据

    		# 第一种:有返回值,并且就是当前被创建的数据对象
        modles.Book.objects.create(name='',price='',publish='',author='',create_time='2019-5-1')
        # 第二种:先实例化产生对象,然后调用save方法保存
        book_obj = models.Book(name='',price='',publish='',author='',create_time='2019-5-1')
        book_obj.save()
        # 2.验证时间格式字段即可以传字符串也可以传时间对象
        import datetime
        ctime = datetime.datetime.now()
        book = models.Book.objects.create(name='',price='',author='',create_time=ctime)
    

    删除数据

    		"""删除数据"""
        # 1.删除书名为xxx的这本书  queryset方法
        res = models.Book.objects.filter(name='').delete()
        # 2.删除书名为xxx的这本书  对象方法
        res = models.Book.objects.filter(name='').first()
        res.delete()
    

    修改数据

    	# 1.queryset修改
        models.Book.objects.filter(name='').update(price='')
        # 2.对象修改
        book = models.Book.objects.filter(name='').first()
        book.price = 66.66
        book.save()  # 对象只有保存方法 这样也能实现修改需求
    

    查询数据

    	<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):  它返回的是一个元组序列,
        <13> distinct():            从返回结果中剔除重复纪录
    上述返回QuerySet对象的有:all(),filter(),exclude(),
    						order_by(),reverse(),distinct()
    返回特殊QuerySet对象的有:values(),values_list() 
       		   返回具体对象:get(),first(),last()
    # ******************* 
       	# 必须完全一样才可以去重(意味着带了id就没有意义了)
       	# res = models.Book.objects.all().values('name').distinct()  先查一个重复的值再去重
        
    

    基于双下划线的查询

    # 价格 大于 小于 大于等于 小于等于
    filter(price__gt='90')
    filter(price__lt='90')
    filter(price_gte='90')
    filter(price_lte='90')
    
    # 存在与某几个条件中
    filter(price__in=['11','22','33'])
    # 在某个范围内
    filter(price__range=[50,90])
    
    # 模糊查询
    filter(title__contains='西')
    filter(title__icontains='P') # 忽略字母大小写
    
    # 以什么开头 以什么结尾
    filter(name__startswith='j')
    filter(name__endswith='n')
    # 按年查询
    filter(create_time__year='2011')
    

    正向反向概念

    # 正向与方向的概念解释
    
    # 一对一
    # 正向:author---关联字段在author表里--->authordetail		按字段
    # 反向:authordetail---关联字段在author表里--->author		按表名小写
    	# 查询jason作者的手机号   正向查询
    	# 查询地址是 :山东 的作者名字   反向查询
      
    # 一对多
    # 正向:book---关联字段在book表里--->publish		按字段
    # 反向:publish---关联字段在book表里--->book		按表名小写_set.all() 因为一个出版社对应着多个图书
    
    # 多对多
    # 正向:book---关联字段在book表里--->author		按字段
    # 反向:author---关联字段在book表里--->book		按表名小写_set.all() 因为一个作者对应着多个图书
      
      
    
    # 连续跨表
    	# 查询图书是三国演义的作者的手机号,先查书,再正向查到作者,在正向查手机号
    
    # 总结:基于对象的查询都是子查询,这里可以用django配置文件自动打印sql语句的配置做演示
    

    Django终端打印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',
            },
        }
    }
    

    多表操作

    一对多操作

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

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

    新增数据

    # 直接写id
    models.Book.objects.create(title='红楼梦',price=66.66,publish_id=1)
    # 传数据对象
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.create(title='三国义',price=199.99,publish=publish_obj)
    

    删除数据

    models.Book.objects.filter(pk=1).delete()
    models.Publish.objects.filter(pk=1).delete() # 会进行级联删除
    
    book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.delete()
    

    修改数据

      # queryset修改
    models.Book.objects.filter(pk=1).update(publish_id=3)
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.filter(pk=1).update(publish=publish_obj)
      # 对象修改
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.publish_id = 3  # 点表中真实存在的字段名
    book_obj.save()
    
    publish_obj = models.Publish.objects.filter(pk=2).first()
    book_obj.publish = publish_obj  # 点orm中字段名 传该字段对应的表的数据对象
    book_obj.save()
    

    查询数据

    1正向查找

    a,对象查找

    语法:
    
    对象.关联字段.字段
    
    要点:先拿到对象,再通过对象去查对应的外键字段,分两步
    
    示例:
    
    book_obj = models.Book.objects.first()  # 第一本书对象(第一步)
    print(book_obj.publisher)  # 得到这本书关联的出版社对象
    print(book_obj.publisher.name)  # 得到出版社对象的名称
    

    b,字段查找

    语法:
    
    关联字段__字段
    
    要点:利用Django给我们提供的神奇的双下划线查找方式
    
    示例:
    
    models.Book.objects.all().values("publisher__name")
    #拿到所有数据对应的出版社的名字,神奇的下划线帮我们夸表查询
    

    2反向查询

    a,对象查找

    语法:
    
    obj.表名_set
    
    要点:先拿到外键关联多对一,一中的某个对象,由于外键字段设置在多的一方,所以这里还是借用Django提供的双下划线来查找
    
    示例:
    
    publisher_obj = models.Publisher.objects.first()  # 找到第一个出版社对象
    books = publisher_obj.book_set.all()  # 找到第一个出版社出版的所有书
    titles = books.values_list("title")  # 找到第一个出版社出版的所有书的书名
    结论:如果想通过一的那一方去查找多的一方,由于外键字段不在一这一方,所以用__set来查找即可
    

    b,字段查找

    语法:
    
    表名__字段
    
    要点:直接利用双下滑线完成夸表操作
    
    titles = models.Publisher.objects.values("book__title")
    

    一对多的书籍记录增删改查总结:

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

    多对多操作

    add()

     # 给书籍绑定与作者之间的关系
        # 添加关系 add:add支持传数字或对象,并且都可以传多个
        book_obj = models.Book.objects.filter(pk=3).first()
        book_obj.authors.add(1)
        book_obj.authors.add(2,3)
        
        author_obj = models.Author.objects.filter(pk=1).first()
        author_obj1 = models.Author.objects.filter(pk=3).first()
        book_obj.authors.add(author_obj)
        book_obj.authors.add(author_obj,author_obj1)
    

    set()

    # 修改书籍与作者的关系  set()  set传的必须是可迭代对象!!!
        book_obj = models.Book.objects.filter(pk=3).first()
        # 可以传数字和对象,并且支持传多个
        book_obj.authors.set((1,))
        book_obj.authors.set((1,2,3))
        
        author_list = models.Author.objects.all()
        book_obj = models.Book.objects.filter(pk=3).first()
        book_obj.authors.set(author_list)
    

    remove() | clear()

     # 删除书籍与作者的绑定关系
        book_obj = models.Book.objects.filter(pk=3).first()
        book_obj.authors.remove(1)
        book_obj.authors.remove(2,3)
        
        author_obj = models.Author.objects.all().first()
        author_list = models.Author.objects.all()
        book_obj.authors.remove(author_obj)
        book_obj.authors.remove(*author_list)  # 需要将queryset打散
    
        # 清空  clear()  清空的是你当前这个表记录对应的绑定关系
        book_obj = models.Book.objects.filter(pk=3).first()
        book_obj.authors.clear()
    

    多对多的书籍与作者的增删改查总结:

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

    基于双下划线的查询

    # 一对一
    -连表查询
    		-一对一双下划线查询
    			-正向:按字段,跨表可以在filter,也可以在values中
    			-反向:按表名小写,跨表可以在filter,也可以在values中
        
    总结 其实你在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名来查即可
    比如:
    	1.查询出版社为北方出版社的所有图书的名字和价格
    	res1 = Publish.objects.filter(name='').values('book__name','book__price')
    	res2 = Book.objects.filter(publish__name='').values('name','price')
    	2.查询北方出版社出版的价格大于19的书
    	res1 = Publish.objects.filter(name='',book__price__gt=19).values('book__name','book__price)
    """
    

    聚合分组查询

    聚合查询aggregate

    单纯使用聚合函数

        from django.db.models import Max,Min,Count,Sum,Avg
    # 查询所有书籍的作者个数
    models.Book.objects.filter(pk=3).aggregate(count_num=Count('authors'))
    # 查询所有出版社出版的书的平均价格
    models.Publish.objects.aggregate(avg_price=Avg('book__price'))
    models.Publish.objects.filter(name='东方出版社').aggregate(count_num=Count('book__id'))
    

    分组查询annotate、

    分组聚合

        from django.db.models import Max,Min,Count,Sum,Avg
    # 统计每个出版社出版的书的平均价格
    models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
    # 统计每一本书的作者个数
    models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')
    # 统计出每个出版社卖的最便宜的书的价格
    models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
    # 查询每个作者出的书的总价格
    models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
    
  • 相关阅读:
    进程及进程调度
    加强版水王:找出出现次数刚好是一半的数字
    寻找最小的k个数(四种方法)
    Count Primes
    深入理解计算机系统结构——并发编程
    深入理解计算机系统——系统级I/O
    深入理解计算机系统结构——虚拟存储器
    老生常谈:关于undo表空间的使用率
    OSW 快速安装部署
    Oracle参数设置之set与reset的实际案例
  • 原文地址:https://www.cnblogs.com/9527mwz/p/11013157.html
Copyright © 2011-2022 走看看