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

 

 

 

  

 

  

 

 

 

  

 

 

 

 

  

posted @ 2020-01-09 21:43  alen_zhan  阅读(984)  评论(1编辑  收藏  举报
返回顶部