Django之Model
内置用户,权限,分组:Django-内置用户、权限、分组模块 - 丶荧惑守芯 - 博客园 (cnblogs.com)
配置数据库连接:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'Public', 'USER': 'root', 'PASSWORD': '123456', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" } }, 'service': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'service', 'USER': 'root', 'PASSWORD': '123456', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", 'charset': 'utf8mb4' } } }
# 注意: 如果要存储的数据支持utf8mb4, 则连接配置中需要设置charset=utf8mb4即可
字段类型:
1、models.AutoField ---自增列 = int(11) 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。 2、models.CharField ---字符串字段 单行输入,用于较短的字符串,如要保存大量文本, 使用 TextField。必须 max_length 参数,django会根据这个参数在数据库层和校验层限制该字段所允许的最大字符数。 3、models.BooleanField ---布尔类型=tinyint(1) 不能为空,Blank=True 4、models.ComaSeparatedIntegerField ---用逗号分割的数字=varchar 继承CharField,所以必须 max_lenght 参数, 5、models.DateField ---日期类型 date 对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。 6、models.DateTimeField ---日期类型 datetime 同DateField的参数 7、models.Decimal ---十进制小数类型 = decimal 必须指定整数位max_digits和小数位decimal_places 8、models.EmailField ---字符串类型(正则表达式邮箱) =varchar 对字符串进行正则表达式 一个带有检查 Email 合法性的 CharField,不接受 maxlength 参数。 9、models.FloatField ---浮点类型 = double 浮点型字段。 必须提供两个 参数, 参数描述: max_digits:总位数(不包括小数点和符号) decimal_places:小数位数。如:要保存最大值为 999 (小数点后保存2位),你要这样定义字段:models.FloatField(…,max_digits=5, decimal_places=2),要保存最大值一百万(小数点后保存10位)的话,你要这样定义:models.FloatField(…,max_digits=19, decimal_places=10) 10、models.IntegerField ---整形 用于保存一个整数 11、models.BigIntegerField ---长整形 integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), } 12、models.IPAddressField ---字符串类型(ip4正则表达式) 一个字符串形式的 IP 地址, (如 “202.1241.30″)。 13、models.GenericIPAddressField ---字符串类型(ip4和ip6是可选的) 参数protocol可以是:both、ipv4、ipv6 验证时,会根据设置报错 14、models.NullBooleanField ---允许为空的布尔类型 类似 BooleanField, 不过允许 NULL 作为其中一个选项。 推荐使用这个字段而不要用 BooleanField 加 null=True 选项。 admin 用一个选择框 <select> (三个可选择的值: “Unknown”, “Yes” 和 “No” ) 来表示这种字段数据。 15、models.PositiveIntegerField ---正Integer 类似 IntegerField, 但取值范围为非负整数(这个字段应该是允许0值的…可以理解为无符号整数) 16、models.PositiveSmallIntegerField ---正smallInteger 正小整型字段,类似 PositiveIntegerField, 取值范围较小(数据库相关)SlugField“Slug” 是一个报纸术语。 slug 是某个东西的小小标记(短签), 只包 含字母,数字,下划线和连字符。它们通常用于URLs。 若你使用 Django 开发版本,你可以指定 maxlength。 若 maxlength 未指定, Django 会使用默认长度: 50,它接受一个额外的参数: prepopulate_from: 来源于slug的自动预置列表 17、models.SlugField ---减号、下划线、字母、数字 它们通常用于URLs。 18、models.SmallIntegerField ---数字 数据库中的字段有:tinyint、smallint、int、bigint. 类似 IntegerField, 不过只允许某个取值范围内的整数。(依赖数据库) 19、models.TextField ---字符串=longtext ,一个容量很大的文本字段, admin 管理界面用 <textarea>多行编辑框表示该字段数据。 20、models.TimeField ---时间 HH:MM[:ss[.uuuuuu]] 时间字段,类似于 DateField 和 DateTimeField。 21、models.URLField ---字符串,地址正则表达式 用于保存URL。若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在(即URL是否被有效装入且没有返回404响应). 22、models.BinaryField ---二进制 23、models.ImageField ---图片 类似 FileField, 不过要校验上传对象是否是一个合法图片。它有两个可选参数:height_field 和 width_field,如果提供这两个参数,则图片将按提供的高度和宽度规格保存。 该字段要求 Python Imaging 库。 24、models.FilePathField ---选择指定目录按限制规则选择文件,有三个参数可选, 其中”path”必需的,这三个参数可以同时使用, 参数描述: path:必需参数,一个目录的绝对文件系统路径。 FilePathField 据此得到可选项目。 Example: “/home/images”; match:可选参数, 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名。 注意这个正则表达式只会应用到 base filename 而不是路径全名。 Example: “foo。*\。txt^”, 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif; recursive:可选参数, 是否包括 path 下全部子目录,True 或 False,默认值为 False。 match 仅应用于 base filename, 而不是路径全名。 如:FilePathField(path=”/home/images”, match=”foo.*”, recursive=True)…会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif 25、models.FileField ---文件上传字段。 要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径。 这个路径必须包含 strftime formatting, 该格式将被上载文件的 date/time 替换(so that uploaded files don’t fill up the given directory)。在一个 model 中使用 FileField 或 ImageField 需要以下步骤:在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件。 (出于性能考虑,这些文件并不保存到数据库。) 定义 MEDIA_URL 作为该目录的公共 URL。 要确保该目录对 WEB 服务器用户帐号是可写的。在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django 使用 MEDIA_ROOT 的哪个子目录保存上传文件。你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT)。 出于习惯你一定很想使用 Django 提供的 get_<fieldname>_url 函数。举例来说,如果你的 ImageField 叫作 mug_shot, 你就可以在模板中以 {{ object。get_mug_shot_url }} 这样的方式得到图像的绝对路径。 26、models.PhoneNumberField ---一个带有合法美国风格电话号码校验的 CharField(格式:XXX-XXX-XXXX) 27、models.USStateField ---美国州名缩写,由两个字母组成(天朝人民无视)。 28、models.XMLField ---XML字符字段,校验值是否为合法XML的 TextField,必须提供参数: schema_path:校验文本的 RelaxNG schema 的文件系统路径。
Field选项:
.null :缺省设置为false.通常不将其用于字符型字段上,比如 CharField,TextField上.字符型字段如果没有值会返回空字符串。 .blank:该字段是否可以为空。如果为假,则必须有值 .choices:一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。如SEX_CHOICES= ((‘F’,'Female’),(‘M’,'Male’),) .core:db_column,db_index 如果为真将为此字段创建索引 .default:设定缺省值 .editable:如果为假,admin模式下将不能改写。缺省为真 .help_text:admin模式下帮助文档 .primary_key:设置主键,如果没有设置django创建表时会自动加上: .radio_admin:用于admin模式下将select转换为radio显示。只用于ForeignKey或者设置了choices .unique:数据唯一 unique=True. Only one .unique_for_date:日期唯一,如下例中系统将不允许title和pub_date两个都相同的数据重复出现 .title = meta.CharField(maxlength=30,unique_for_date=’pub_date’) .unique_for_month / unique_for_year:用法同上 .validator_list:有效性检查。非有效产生 django.core.validators.ValidationError 错误
Meta参数:
1.abstract 这个属性是定义当前的模型是不是一个抽象类。所谓抽象类是不会对应数据库表的。一般我们用它来归纳一些公共属性字段,然后继承它的子类可以继承这些字段。 Options.abstract 如果abstract = True 这个model就是一个抽象类 2.app_label 这个选型只在一种情况下使用,就是你的模型不在默认的应用程序包下的models.py文件中,这时候需要指定你这个模型是哪个应用程序的。 Options.app_label 如果一个model定义在默认的models.py,例如如果你的app的models在myapp.models子模块下,你必须定义app_label让Django知道它属于哪一个app app_label = 'myapp' 3.db_table db_table是指定自定义数据库表名的。Django有一套默认的按照一定规则生成数据模型对应的数据库表明。 Options.db_table 定义该model在数据库中的表名称 db_table = 'Students' 如果你想使用自定义的表名,可以通过以下该属性 table_name = 'my_owner_table' 4.db_teblespace Options.db_teblespace 定义这个model所使用的数据库表空间。如果在项目的settin中定义那么它会使用这个值 5.get_latest_by Options.get_latest_by 在model中指定一个DateField或者DateTimeField。这个设置让你在使用model的Manager上的lastest方法时,默认使用指定字段来排序 6.managed Options.managed 默认值为True,这意味着Django可以使用syncdb和reset命令来创建或移除对应的数据库。默认值为True,如果你不希望这么做,可以把manage的值设置为False 7.order_with_respect_to 这个选项一般用于多对多的关系中,它指向一个关联对象,就是说关联对象找到这个对象后它是经过排序的。指定这个属性后你会得到一个get_xxx_order()和set_xxx_order()的方法,通过它们你可以设置或者回去排序的对象 8.ordering 这个字段是告诉Django模型对象返回的记录结果集是按照哪个字段排序的。这是一个字符串的元组或列表,没有一个字符串都是一个字段和用一个可选的表明降序的'-'构成。当字段名前面没有'-'时,将默认使用升序排列。使用'?'将会随机排列 ordering=['order_date'] # 按订单升序排列 ordering=['-order_date'] # 按订单降序排列,-表示降序 ordering=['?order_date'] # 随机排序,?表示随机 ordering=['-pub_date','author'] # 以pub_date为降序,在以author升序排列 9.permissions permissions主要是为了在Django Admin管理模块下使用的,如果你设置了这个属性可以让指定的方法权限描述更清晰可读。Django自动为每个设置了admin的对象创建添加,删除和修改的权限。 permissions = (('can_deliver_pizzas','Can deliver pizzas')) 10.proxy 这是为了实现代理模型使用的,如果proxy = True,表示model是其父的代理 model 11.unique_together unique_together这个选项用于:当你需要通过两个字段保持唯一性时使用。比如假设你希望,一个Person的FirstName和LastName两者的组合必须是唯一的,那么需要这样设置: unique_together = (("first_name", "last_name"),) 一个ManyToManyField不能包含在unique_together中。如果你需要验证关联到ManyToManyField字段的唯一验证,尝试使用signal(信号)或者明确指定through属性。 12.verbose_name verbose_name的意思很简单,就是给你的模型类起一个更可读的名字一般定义为中文,我们: verbose_name = "学校" 13.verbose_name_plural 这个选项是指定,模型的复数形式是什么,比如: verbose_name_plural = "学校" 如果不指定Django会自动在模型名称后加一个’s’
查询数据集
all() 返回所有数据
filter() 返回符合条件的数据
exclude() 过滤点符合条件的数据
order_by() 排序 升序:order_by('id') 降序:order_by('-id')
values() 一条数据就是一个字段, 返回一个列表
返回单个数据
get() 返回一个满足条件的对象, 如果没有找到符合条件的对象, 会引发模型类的DoesNotExist异常, 如果找到多个, 会引发模型类的MultiObjectsReturned异常 first() 返回查询集中的第一个对象 last() 返回查询集中的最后一个对象 count() 返回当前查询集中的对象的个数 exists() 判断查询集中是否有数据, 如果有数据则返回TRUE
1.多表连接查询
class A(models.Model): name = models.CharField(u'名称') class B(models.Model): aa = models.ForeignKey(A) B.objects.filter(aa__name__contains='searchtitle')
1.5 反向查询,后来插入记录
class A(models.Model): name = models.CharField(u'名称') class B(models.Model): aa = models.ForeignKey(A,related_name="FAN") bb = models.CharField(u'名称')
查A: A.objects.filter(FAN__bb='XXXX'),都知道related_name的作用,A.FAN.all()是一组以A为外键的B实例,可前面这样的用法是查询出所有(B.aa=A且B.bb=XXXX)的A实例,然后还可以通过__各种关系查找!
2.条件选取querySet的时候,filter表示=,exclude表示!=。
querySet.distinct() 去重复
__exact 精确等于 like 'aaa'
__iexact 精确等于 忽略大小写 ilike 'aaa'
__contains 包含 like '%aaa%'
__icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以...开头
__istartswith 以...开头 忽略大小写
__endswith 以...结尾
__iendswith 以...结尾,忽略大小写
__range 在...范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull=True/False
例子:
>> q1 = Entry.objects.filter(headline__startswith="What") >> q2 = q1.exclude(pub_date__gte=datetime.date.today()) >> q3 = q1.filter(pub_date__gte=datetime.date.today()) >>> q = q.filter(pub_date__lte=datetime.date.today()) >>> q = q.exclude(body_text__icontains="food") 即q1.filter(pub_date__gte=datetime.date.today())表示为时间>=now,q1.exclude(pub_date__gte=datetime.date.today())表示为<=now
关于缓存:
queryset是有缓存的
a = A.objects.all(),print [i for i in a].
第一次执行打印会查询数据库,然后结果会被保存在queryset内置的cache中,再执行print的时候就会取自缓存。
很多时候会遇到仅需判断queryset是否为空的情况,
1.if queryset:pass 2.if queryset.count>0:pass 3.if queryset.exists():pass. 三种方式性能依次提升。
当queryset非常巨大时,cache会成为问题。此时可以queryset.iterator(),迭代器的用处就不多说了,根据具体需求情况使用。
其他操作:
示例:
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=200) email = models.EmailField() def __str__(self): return self.name class Entry(models.Model): blog = models.ForeignKey(to=Blog,on_delete=models.CASCADE) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __str__(self): return self.headline
1.创建对象
模型类表示数据库表,该类的实例表示数据库表中的特定记录也就是数据值 要创建对象,请使用模型类的关键字参数对其进行实例化,然后调用save()以将其保存到数据库中 假设模型存在于mysite/app01/models.py文件中 from app01.models import Blog b = Blog(name='beatles blog',tagline='all the latest beatles news.') b.save()
它会在后台执行SQL语句INSERT,如果不调用save()方法,Django不会立刻将该操作反应到数据库中,save()方法没有返回值,它可以接受一些额外的参数
#修改对象的值,在后台会执行一条SQL语句的UPDATE b.name = 'python is django' b.save() Blog.objects.all() <QuerySet [<Blog: python is django>]>
如果想要一行代码完成上面的操作,请使用create()方法,它可以省略save的步骤:
Blog.objects.create(name='Blog title',tagline='this is one blog title name') Blog.objects.filter(name='Blog title') #查询数据 <QuerySet [<Blog: name:Blog title;tagline:this is one blog title name>]>
2、保存ForeignKey和ManyToManyField字段
保存一个ForeignKey字段和保存普通字段没什么区别,只需要注意值的类型要正确,下面的例子,有一个Entry的实例和一个Blog的实例,然后把cheese_blog作为值赋给了entry的blog属性,最后调用save方法进行保存。
from app01.models import Blog,Entry entry = Entry.objects.get(pk=1) cheese_blog = Blog.objects.get(name='Blog title') entry.blog = cheese_blog entry.save()
ManyToManyField字段的保存稍微有点区别,需要调用add()方法,而不是直接给属性赋值,但它不需要调用save方法,如下示例:
from app01.models import Author joe = Author.objects.create(name='Joe') entry.authors.add(joe)
在对对多关系中可以一次性添加多条记录,只需在调用add()时指定多个值即可:
john = Author.objects.create(name='John') paul = Author.objects.create(name='Paul') george = Author.objects.create(name='George') ringo = Author.objects.create(name='Ringo') entry.authors.add(john,paul,george,ringo) #如指定了错误的类型对象,将引发异常
指定查询特定的字段, model提供了两个方法 values 和values_list
values
from attendence.models import Employee from attendence.models import EmployeeIP #获取一个字段 ipList = EmployeeIP.objects.values("IP").first() print(type(ipList)) # <class 'dict'> print(ipList) # {'IP': '192.168.1.41'} #获取多个字段 empList = Employee.objects.values("first_name", "last_name", "email")[0:2] print(type(empList)) # <class 'django.db.models.query.QuerySet'> print(empList) # [ # {'last_name': 'Wei', 'first_name': 'Vena', 'email': 'Vena@test.com'}, # {'last_name': 'Wan', 'first_name': 'Mark', 'email': 'mwan@test.com'} # ]
values_list
ipList = EmployeeIP.objects.values_list("IP").first() print(type(ipList)) # <class 'tuple'> print(ipList) # ('192.168.1.111',) ipList = EmployeeIP.objects.values_list("IP")[0:2] print(type(ipList)) # <class 'django.db.models.query.QuerySet'> print(ipList) # [('192.168.1.41',), ('192.168.1.44',)] print(type(ipList[0])) # <class 'tuple' > print(ipList[0]) # 192.168.1.111
可以查看values和values_list的区别点:
vlaues - 单条记录 - <class 'dict'> 多条记录 - <class 'django.db.models.query.QuerySet'> vlaues_list - 单条记录 - <class 'tuple'> 多条记录 - <class 'django.db.models.query.QuerySet'>
Distinct)
使用方式: 需要和values进行联合使用
a = Category.objects.values('parentcode').distinct() 对字段parentcode进行去重 如果想同时对多个字段进行去重 Category.objects.values('parentcode','email').distinct() 这样就会对两个字段进行去重
聚合查询)
对数据表计算统计值,需要使用 aggregate 方法,提供的参数可以是一个或者多个聚合函数,aggregate 是 QuerySet 的一个子句,它的返回值是一个字典类型,键是聚合的关键字,值是聚合后的统计结果。
不带分组的聚合查询是指对将全部数据进行集中统计查询,Django 定义了一些常用的聚合函数,比如求平均值(Avg)、计数(Count)、求最值(Max和Min)以 Sum 求和。它们统一定义在 django.db.models
模块中,所以再使用聚合函数时,同样需要提前导入,为了方便使用,我们采用下面的方式引入:
from django.db.models import *
它的语法格式如下所示,它的返回值是一个字典,以统计结果变量名为 key,以统计值为 value:
MyModel.objects.aggregate(统计结果变量名=聚合函数('列名'))
我们通过求所有书籍的价格平均值与所书籍数量来进行实例演练:
#求所有书籍的平均价格 from index.models import Book from django.db.models import * result =Book.objects.aggregate(myAvg=Avg('price')) print("平均价格是:", result['myAvg']) print("result=", result) #result= {'myAvg': Decimal('47.800000')} #求一共有多少本书 result =Book.objects.aggregate(MyCulate=Count('title')) print("数据记录总个数是:", result['MyCulate']) print("result=", result) #result= {'MyCulate': 5} #传递多个聚合函数一起求值 result=Book.objects.aggregate(l=Min("price"),m=Max("price"),n=Avg("retail_price")) print("result=",result) #result= {'l': Decimal('25.00'), 'm': Decimal('65.00'), 'n': Decimal('127.800000')}
聚合分组查询)
分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。简单的理解就是对 QuerySet中的每一个 Model 对象都生成一个统计值。分组聚合使用 annotate 方法完成。它的语法格式和聚合查询一样如下所示:
QuerySet.annotate(结果变量名=聚合函数('列名'))
分组聚合的实现主要两个步骤:首先使用 MyModel.objects.values 获得要分组聚合的列,它的返回结果是一个 QuerySet 类型的字典,然后通过 QuerySet.annotate(变量名=聚合函数('列名')) 的方法分组聚合得到相应的结果。下面我们通过实例进行说明,通过分组聚合查询获取价格相同的书籍数量:
#在index/views.py 添加代码 from django.db.models import Count from index.models import Book,PubName def test_annotate(request): # 得到所有出版社的查询集合QuerySet bk_set = Book.objects.values('price') # bk=Book.objects.get(id=1) # print('书名:',bk.title,'出版社是:',bk.pub.pubname) # 根据出版社QuerySet查询分组,出版社和Count的分组聚合查询集合 bk_count_set = bk_set.annotate(myCount=Count('price')) # 返回查询集合 for item in bk_count_set: #通过外键关联进行查询bk_set.pub.pubname print("价格是:", item['price'], "同等价格书籍数量:", item['myCount']) return HttpResponse('请在CMD命令行控制台查看结果') #路由配置为忘记:path('annotate/',views.test_annotate)
结果:
价格是: 59.00 同等价格书籍数量: 1 价格是: 25.00 同等价格书籍数量: 1 价格是: 45.00 同等价格书籍数量: 2 价格是: 65.00 同等价格书籍数量: 1
由于 annotate 的返回值是一个 QuerySet 对象,所以我可以通过 query 属性查看其执行的 SQL 语句,如下所示:
SELECT `index_book`.`price`, COUNT(`index_book`.`price`) AS `myCount` FROM `index_book` GROUP BY `index_book`.`price` ORDER BY NULL
从 SQL 语句可以得出,annotate 按照 price 分组,并且在 SELECT 中对 price 进行了计数。默认情况下,annotate 会对每一个 Model 对象计算统计值。但是,如果使用了 values 方法中指定的字段,Django 会先按照该字段对 Model 对象进行分组,再去对每个分组计算统计值。
在这里大家还要注意,annotate 和 values 方法的顺序非常重要,会影响实际的查询效果。上面实例就是 values 在前的情况,如果 annotate 在前会产生不同的影响,如下所示:
In [41]: Book.objects.annotate(t=Max('price')).values('id','t') Out[41]: <QuerySet [{'id': 1, 't': Decimal('59.00')}, {'id': 2, 't': Decimal('25.00')}, {'id': 3, 't': Decimal('45.00')}, {'id': 4, 't': Decimal('65.00')}, {'id': 5, 't': Decimal('45.00')}]>#按照values提供的参数分别作为键和值。
or和and查询
from django.db.models import Q
# or Url.objects.filter(Q(path__contains='aaa') | Q(name__contains='aaa')).all()
# and
Url.objects.filter(Q(path__contains='aaa') & Q(name__contains='aaa')).all()
# ~Q not
Url.objects.filter(Q(path__contains='aaa') & !Q(name__contains='aaa')).all()
在model中使用枚举类型(enum)类型非varchar
若是想要在Django中使用Mysql的枚举(ENUM)类型,需要安装一个Django的Mysql扩展,名为django-mysql 项目地址。
[安装]
python -m pip install django-mysql
很简单,就如同安装其他python第三方包一样。然后还需在setting.py
中的INSTALLED_APPS
栏填入django_mysql
,注意在代码中要用下划线而非横杠
INSTALLED_APPS = ( ... 'django_mysql',#注意在代码中要用下划线而非横杠 )
使用示例:
from django.db import models import django_mysql.models class User0(models.Model): username = models.CharField(max_length=20, verbose_name='用户名') STATUS_LIST = ( ('A', '正常'), ('B', '封禁中'), ('C', '已注销'), ) status = django_mysql.models.EnumField(choices=STATUS_LIST) def __str__(self): return self.username
更多参考: https://segmentfault.com/a/1190000039690303
更多操作: https://www.cnblogs.com/zhangxinqi/p/10716674.html#_label9
常见问题:
1.插入数据库错误 UnicodeEncodeError: 'utf-8' codec can't encode characters in position 6215-6216: surrogates not allowed
原因: 出现特殊字符,例如emoji的数据插入到表中的时候发生错误
解决:
1)保证数据库和表使用的是utf8mb4的字符
2)将字符进行转化之后再保存
示例: import json ll={'data':'#熊二来电 狗熊来电\ud83d\ude4b @趙雲哥哥\ud83d\udd31(风华绝代浪浪) @《龍七团》姜少❗️(风华浪浪)'} tt = json.dumps(ll) 转成字符串 dd = json.loads(tt) 再转成dict 再写入数据库 tableName.objects.create(**dd)