zoukankan      html  css  js  c++  java
  • models常用字段及参数,orm查询优化, choices参数及实际应用

    一、自定义字段类型

    from django.db import models
    
    # Create your models here.
    
    # 自定义CHAR类型
    from django.db.models import Field
    
    class RealCharField(Field):  # 这里是要继承Field类的
        def __init__(self, max_length, *args, **kwargs):
            self.max_length = max_length   # 拦截一个父类的方法 操作完之后 利用super调用父类的方法
            super().__init__(max_length=max_length, *args, **kwargs)
    
    
        def db_type(self, connection):
            return 'char(%s)' % self.max_length
    
    
    class Movie(models.Model):
        title = models.CharField(max_length=64)
        price = models.DecimalField(max_digits=8, decimal_places=2)
        publish_time = models.DateField()    # 年月日
        textField = RealCharField(max_length=64, null=True)   # 这里我们让它继承我们自定义的类型
        # publish_time = models.DateTimeField()   # 年月日 时分秒

    注意:设计完以后一定要记得去将数据tongue到数据库中,如果你从从事和django相关的工作,那么这两行代码将会相伴你终生,只要你动了和数据相关的操作都要去执行下面两行代码

      1、python manage.py makemigrations

      2、pythonmanage.py migrate

    - 效果演示

     二、models常用字段及参数

    1、models中常用字段

      1、AutoField(primary_key=True)            主键字段

      2、CharField(max_length=64)                vachar(64)   字符串  必须提供max_length参数, max_length表示字符长度。

      3、IntegerField()            int     整型

      4、BigIntegerField()         bigint   大整型

      5、DecimalField()             decimal   小数

      6、EmaiField()             varchar(254)  # 限制必须邮件类型

      7、DateField()            date     日期

      8、DateTimeField()          datetime  时间

          这里有两个参数需要我们注意:

            a:  auto_now:每次编辑数据的时候都会自动的更新该字段时间

            b:  auto_now_add:创建数据的时候更新

            举个例子:比如说你注册了个QQ,使用a你每编辑一下那么你的注册时间每次编辑完都会改变,而使用b的话                                只会记录你注册qq时的时间,除非你真的自己修改了注册时间不然编辑b不会改变之前的注册时间

      9、BooleanField(Field)                             布尔值类型          给该字段传布尔值会对应成0/1

        10、TextField(Field)           文本类型        用来储存大段文本时使用

      11、FileField(Field)          字符串      路径保存在数据库 ,文件上传到指定目录,只存文件路径

    2、models中字段合集

    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)
            - 二进制类型
    
     字段合集
    View Code

    3、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)',
    View Code

    4、字段内关键参数

    null
    用于表示某个字段可以为空。
    
    unique
    如果设置为unique=True 则该字段在此表中必须是唯一的 。
    
    db_index
    如果db_index=True 则代表着为此字段设置索引。
    
    default
    为该字段设置默认值。
    
    DateField和DateTimeField
    auto_now_add
    配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
    
    auto_now
    配置上auto_now=True,每次更新数据记录的时候会更新该字段。
    View Code

    5、关系字段

    1、ForeignKey            主键
    2、ManyToManyField    多对多
    3、OneToOneField        一对一
    View Code

    三、choice参数的使用

      当你的数据能够被列举完全,你就可以考虑使用choice参数,比如说学历,性别,婚否,在职状态等等,下面就来简单介绍下choice的使用

    # 自定义一个userinfo
    class userinfo(models.Model):
        username = models.CharField(max_length=32)
        gender_choices = (
            (1, ''),
            (2, ''),
            (3, '其他'),
        )
        gender = models.IntegerField(choices=gender_choices)
        # 该字段还可以存匹配关系之外的数字
    # 先存数据
        # models.Userinfo.objects.create(username='jason',gender=1)
        # models.Userinfo.objects.create(username='tank',gender=2)
        # models.Userinfo.objects.create(username='egon',gender=3)
        # models.Userinfo.objects.create(username='sean',gender=10)
    
        # 查数据
        # user_obj = models.Userinfo.objects.get(pk=1)
        # print(user_obj.username)
        # print(user_obj.gender)
        # # 针对choices参数字段 取值的时候   get_xxx_display()就可以看到数字对应的数据
        # print(user_obj.get_gender_display())
        # # 针对没有注释信息的数据  get_xxx_display()获取到的还是数字本身
        # user_obj = models.Userinfo.objects.get(pk=4)
        # print(user_obj.gender)
        # print(user_obj.get_gender_display())

     

    - choices的实际应用举例

    # class Customer(models.Model):
    #     """
    #     客户表
    #     """
    #     qq = models.CharField(verbose_name='qq', max_length=64, unique=True, help_text='QQ号必须唯一')
    #
    #     name = models.CharField(verbose_name='学生姓名', max_length=16)
    #     gender_choices = ((1, '男'), (2, '女'))
    #     gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
    #
    #     education_choices = (
    #         (1, '重点大学'),
    #         (2, '普通本科'),
    #         (3, '独立院校'),
    #         (4, '民办本科'),
    #         (5, '大专'),
    #         (6, '民办专科'),
    #         (7, '高中'),
    #         (8, '其他')
    #     )
    #     education = models.IntegerField(verbose_name='学历', choices=education_choices, blank=True, null=True, )
    #     graduation_school = models.CharField(verbose_name='毕业学校', max_length=64, blank=True, null=True)
    #     major = models.CharField(verbose_name='所学专业', max_length=64, blank=True, null=True)
    #
    #     experience_choices = [
    #         (1, '在校生'),
    #         (2, '应届毕业'),
    #         (3, '半年以内'),
    #         (4, '半年至一年'),
    #         (5, '一年至三年'),
    #         (6, '三年至五年'),
    #         (7, '五年以上'),
    #     ]
    #     experience = models.IntegerField(verbose_name='工作经验', blank=True, null=True, choices=experience_choices)
    #     work_status_choices = [
    #         (1, '在职'),
    #         (2, '无业')
    #     ]
    #     work_status = models.IntegerField(verbose_name="职业状态", choices=work_status_choices, default=1, blank=True,
    #                                       null=True)
    #     company = models.CharField(verbose_name="目前就职公司", max_length=64, blank=True, null=True)
    #     salary = models.CharField(verbose_name="当前薪资", max_length=64, blank=True, null=True)
    #
    #     source_choices = [
    #         (1, "qq群"),
    #         (2, "内部转介绍"),
    #         (3, "官方网站"),
    #         (4, "百度推广"),
    #         (5, "360推广"),
    #         (6, "搜狗推广"),
    #         (7, "腾讯课堂"),
    #         (8, "广点通"),
    #         (9, "高校宣讲"),
    #         (10, "渠道代理"),
    #         (11, "51cto"),
    #         (12, "智汇推"),
    #         (13, "网盟"),
    #         (14, "DSP"),
    #         (15, "SEO"),
    #         (16, "其它"),
    #     ]
    #     source = models.SmallIntegerField('客户来源', choices=source_choices, default=1)
    #     referral_from = models.ForeignKey(
    #         'self',
    #         blank=True,
    #         null=True,
    #         verbose_name="转介绍自学员",
    #         help_text="若此客户是转介绍自内部学员,请在此处选择内部学员姓名",
    #         related_name="internal_referral"
    #     )
    #     course = models.ManyToManyField(verbose_name="咨询课程", to="Course")
    #
    #     status_choices = [
    #         (1, "已报名"),
    #         (2, "未报名")
    #     ]
    #     status = models.IntegerField(
    #         verbose_name="状态",
    #         choices=status_choices,
    #         default=2,
    #         help_text=u"选择客户此时的状态"
    #     )
    #
    #     consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo', related_name='consultanter',limit_choices_to={'depart':1001})
    #
    #     date = models.DateField(verbose_name="咨询日期", auto_now_add=True)
    #     recv_date = models.DateField(verbose_name="当前课程顾问的接单日期", null=True)
    #     last_consult_date = models.DateField(verbose_name="最后跟进日期", )
    #
    #     def __str__(self):
    #         return self.name
    #
    # class ConsultRecord(models.Model):
    #     """
    #     客户跟进记录
    #     """
    #     customer = models.ForeignKey(verbose_name="所咨询客户", to='Customer')
    #     consultant = models.ForeignKey(verbose_name="跟踪人", to='UserInfo',limit_choices_to={'depart':1001})
    #     date = models.DateField(verbose_name="跟进日期", auto_now_add=True)
    #     note = models.TextField(verbose_name="跟进内容...")
    #
    #     def __str__(self):
    #         return self.customer.name + ":" + self.consultant.name
    #
    # class Student(models.Model):
    #     """
    #     学生表(已报名)
    #     """
    #     customer = models.OneToOneField(verbose_name='客户信息', to='Customer')
    #     class_list = models.ManyToManyField(verbose_name="已报班级", to='ClassList', blank=True)
    #
    #     emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='紧急联系人')
    #     company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True)
    #     location = models.CharField(max_length=64, verbose_name='所在区域', blank=True, null=True)
    #     position = models.CharField(verbose_name='岗位', max_length=64, blank=True, null=True)
    #     salary = models.IntegerField(verbose_name='薪资', blank=True, null=True)
    #     welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True)
    #     date = models.DateField(verbose_name='入职时间', help_text='格式yyyy-mm-dd', blank=True, null=True)
    #     memo = models.CharField(verbose_name='备注', max_length=256, blank=True, null=True)
    #
    #     def __str__(self):
    #         return self.customer.name
    #
    # class ClassStudyRecord(models.Model):
    #     """
    #     上课记录表 (班级记录)
    #     """
    #     class_obj = models.ForeignKey(verbose_name="班级", to="ClassList")
    #     day_num = models.IntegerField(verbose_name="节次", help_text=u"此处填写第几节课或第几天课程...,必须为数字")
    #     teacher = models.ForeignKey(verbose_name="讲师", to='UserInfo',limit_choices_to={'depart':1002})
    #     date = models.DateField(verbose_name="上课日期", auto_now_add=True)
    #
    #     course_title = models.CharField(verbose_name='本节课程标题', max_length=64, blank=True, null=True)
    #     course_memo = models.TextField(verbose_name='本节课程内容概要', blank=True, null=True)
    #     has_homework = models.BooleanField(default=True, verbose_name="本节有作业")
    #     homework_title = models.CharField(verbose_name='本节作业标题', max_length=64, blank=True, null=True)
    #     homework_memo = models.TextField(verbose_name='作业描述', max_length=500, blank=True, null=True)
    #     exam = models.TextField(verbose_name='踩分点', max_length=300, blank=True, null=True)
    #
    #     def __str__(self):
    #         return "{0} day{1}".format(self.class_obj, self.day_num)
    #
    # class StudentStudyRecord(models.Model):
    #     '''
    #     学生学习记录
    #     '''
    #     classstudyrecord = models.ForeignKey(verbose_name="第几天课程", to="ClassStudyRecord")
    #     student = models.ForeignKey(verbose_name="学员", to='Student')
    #
    #
    #
    #
    #
    #
    #
    #     record_choices = (('checked', "已签到"),
    #                       ('vacate', "请假"),
    #                       ('late', "迟到"),
    #                       ('noshow', "缺勤"),
    #                       ('leave_early', "早退"),
    #                       )
    #     record = models.CharField("上课纪录", choices=record_choices, default="checked", max_length=64)
    #     score_choices = ((100, 'A+'),
    #                      (90, 'A'),
    #                      (85, 'B+'),
    #                      (80, 'B'),
    #                      (70, 'B-'),
    #                      (60, 'C+'),
    #                      (50, 'C'),
    #                      (40, 'C-'),
    #                      (0, ' D'),
    #                      (-1, 'N/A'),
    #                      (-100, 'COPY'),
    #                      (-1000, 'FAIL'),
    #                      )
    #     score = models.IntegerField("本节成绩", choices=score_choices, default=-1)
    #     homework_note = models.CharField(verbose_name='作业评语', max_length=255, blank=True, null=True)
    #     note = models.CharField(verbose_name="备注", max_length=255, blank=True, null=True)
    #
    #     homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)
    #     stu_memo = models.TextField(verbose_name='学员备注', blank=True, null=True)
    #     date = models.DateTimeField(verbose_name='提交作业日期', auto_now_add=True)
    #
    #     def __str__(self):
    #         return "{0}-{1}".format(self.classstudyrecord, self.student)
    View Code

    四、orm数据库查询优化(面试可能会问)

      1、only与defer

      2、select_related与prefetch_related

    1、前期准备工作

      为了更好地观看这两组方法的效果,我们需要提前去settings中添加可以打印全部orm语句的SQL语法,把下面这段代码放到settings最下方即可

    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

    2、django的惰性

        # res = models.Book.objects.all()
        # # # django orm查询都是惰性查询,你只有在要用数据的时候它才会将SQL语句给你显示显示出来
        # print(res)

     3、数据查询优化的引入

    # res = models.Book.objects.values('title')
        # print(res)   [{},{},{}....]
    
        # for r in res:
        #     print(r.title)
    
        # 引入: 现在我想拿到一个一个的对象,那就必须要使用数据查询优化相关的功能

     4、only与defer

        res = models.Book.objects.only('title')
        # print(res)
        for i in res:
            # print(i.title)
            print(i.price)
    
        '''
        only 作用
            括号内传字段 得到的结果是一个列表套数据对象  该对象内只含有括号内指定的字段属性
            对象点字段属性是不会走数据库查询的  但是你一旦点了非括号内的字段 也能够拿到数据
            只是会重新走数据库查询
        '''
    
        res = models.Book.objects.defer('title')     # defer与only互为相反的关系
        for i in res:
            # print(i.title)
            print(i.price)
    
        '''
        defer与only想反
            括号内传字段 得到的结果是一个列表套数据对象 该对象内没有括号内指定的字段属性
            对象点该字段属性会重复走数据库 但是你一旦点了非括号内的字段 不会走数据库
        
        '''

     5、select_related与prefetch_related

        res = models.Book.objects.get(pk=1)
        print(res.publish.name)
    
        res = models.Book.objects.select_related('publish')
        for i in res:
            print(i.publish.name)
            print(i.publish.addr)
    
        """
           内部是连表操作 先将关系表全部链接起来拼接成一张大表 之后再一次性查询出来 封装到对象中
           数据对象之后在获取任意表中的数据的时候都不需要再走数据库了 因为全部封装成了对象的属性
    
           select_related括号内只能传外键字段 并且不能是多对多字段 只能是一对多和一对一
           select_related(外键字段1__外键字段2__外键字段3...)
           """
    
        # prefetch_related
        res = models.Book.objects.prefetch_related('publish')
        # print(res)
        for r in res:
            print(r.publish.name)
    
        """
            prefetch_related内部是子查询(即可能查询多次) 但是给你的感觉是连表操作
            内部通过子查询将外键管理表中的数据页全部给你封装到对象中
            之后对象点当前表或者外键关联表中的字段也都不需要走数据库了
            """
    
        """
            优缺点比较
            select_related连表操作 好处在于只走一次sql查询
                耗时耗在 连接表的操作  10s
    
            prefetch_related子查询  本题中只走两次sql查询
                耗时耗在 查询次数      1s
            """

     五、django orm开启事务

    1、事务的四大特性(ACID)

      原子性:事务是一个不可分割的单位

      一致性:跟原子性是绑在一起的,要么同时成功,要么同时失败

      隔离性:事务与事务之间互相不干扰

      持久性:事务的数据一旦用commit确认提交那么作用以及效果应该是永久的不可rollback

    2、mysql开启事务

      start transaction

    3、django开启事务

    from django.db import transaction
        with transaction.atomic():
            # 在with代码块中执行的orm语句同属于一个事务
            pass
    
        # 代码块运行结束 事务就结束了  事务相关的其他配置 你可以百度搜搜看

    六、MTV与MVC模型

    MTV与MVC模型
            MTV  django号称是MTV框架
                M:models
                T:templates
                V:views
            MVC
                M:models
                V:views
                C:controlnar  控制器(路由分发 urls.py)
            本质:MTV本质也是MVC

      

      

     

      

      

  • 相关阅读:
    mxGraph
    DrawIO二次开发(一)
    关于使用Draw.io画数据库E-R图的说明
    流程图软件draw.io值得你拥有
    diagrams
    http://www.avaloniaui.net/
    Qt音视频开发1-vlc解码播放
    Codeforces Round #548 (Div. 2) D 期望dp + 莫比乌斯反演
    线程
    牛客练习赛89E-牛牛小数点【数论】
  • 原文地址:https://www.cnblogs.com/yafeng666/p/12173683.html
Copyright © 2011-2022 走看看