一、自定义字段类型
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