Django2.0入门教程:模型元数据Meta选项详解
在管理后台与model模型文章里,我们创建了一个简单的数据模型,迁移数据,创建了管理帐号,并进入了Django管理后台。
现在我们在后台添加两个文章分类,然后添加几篇文章。在添加文章的时候,我们选择之前添加的文章分类,显示如下:
文章添加成功之后,在后台显示如下:
大家可以仔细看看上边的三张图片,我用红框标记的地方。Blog应用下的三个类、分类与标签里的内容对象、文章里的内容对象,显示的是一些复数的类名,或者是一些类的对象。这样的的体验很不好,不是我们想要的。这时我们可以通过models继承的一些方法和Meta选项来提升用户体验。
看代码:
blog/models.py from django.db import models from django.contrib.auth.models import User class Category(models.Model): name = models.CharField('分类',max_length=100) #下面为新增代码 class Meta: verbose_name = '分类' verbose_name_plural = verbose_name def __str__(self): return self.name class Tags(models.Model): name = models.CharField('标签',max_length=100) #下面为新增代码 class Meta: verbose_name = '标签' verbose_name_plural = verbose_name def __str__(self): return self.name class Article(models.Model): title = models.CharField('标题',max_length=70) intro = models.TextField('摘要', max_length=200, blank=True) category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name='分类', default='1') tags = models.ManyToManyField(Tags, blank=True) body = models.TextField() user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='作者') created_time = models.DateTimeField('发布时间',auto_now_add=True) #下面为新增代码 class Meta: verbose_name = '文章' verbose_name_plural = verbose_name def __str__(self): return self.title
我们给每个类都增加了一个内部类Meta和__str__方法属性。
由于我们的model实例继承自models.Model,所以它自动继承了models.Model的大量方法。
__str__()是Python3的写法,它相当于python2的unicode,这是一个Python的"魔术方法",它以unicode方式返回任何对象的陈述。Python和Django需要输出字符串陈述时使用。例如在交互式控制台或管理后台显示的输出陈述。有时候默认的实现并不能很好的满足需要,所以最好自定义这个方法。而Meta是一个内部类,它用于定义一些Django模型类的行为特性。
注意:每个模型都可以有自己的元数据类,每个元数据类也只对自己所在模型起作用。
下面我们来看看添加上面代码之后,会有什么样的效果:
红框标记的地方,与原来对比,让人更加容易理解。内部类Meta对于models来说,不是必须的,但对于用户来说在实际使用中具有重要的作用,有些元数据选项能给予我们极大的帮助。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主要是为了在DjangoAdmin管理模块下使用的,如果你设置了这个属性可以让指定的方法权限描述更清晰可读。Django自动为每个设置了admin的对象创建添加,删除和修改的权限。
permissions=(('can_deliver_pizzas','Candeliverpizzas'))
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’
一些常见的元信息的例子:
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 db_table = "table_name" # 联合索引 index_together = [ ("pub_date", "deadline"), ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # admin中显示的表名称 verbose_name # verbose_name加s verbose_name_plural
多表关系和参数的例子:
ForeignKey(ForeignObject) # ForeignObject(RelatedField) to, # 要进行关联的表名 to_field=None, # 要关联的表中的字段名称 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为 - models.CASCADE,删除关联数据,与之关联也删除 - models.DO_NOTHING,删除关联数据,引发错误IntegrityError - models.PROTECT,删除关联数据,引发错误ProtectedError - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空) - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值) - models.SET,删除关联数据, a. 与之关联的值设置为指定值,设置:models.SET(值) b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象) def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id" on_delete=models.SET(func),) related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') db_constraint=True # 是否在数据库中创建外键约束 parent_link=False # 在Admin中是否显示关联数据 OneToOneField(ForeignKey) to, # 要进行关联的表名 to_field=None # 要关联的表中的字段名称 on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为 ###### 对于一对一 ###### # 1. 一对一其实就是 一对多 + 唯一索引 # 2.当两个类之间有继承关系时,默认会创建一个一对一字段 # 如下会在A表中额外增加一个c_ptr_id列且唯一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1) ManyToManyField(RelatedField) to, # 要进行关联的表名 related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段 # 做如下操作时,不同的symmetrical会有不同的可选字段 models.BB.objects.filter(...) # 可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定义第三张表时,使用字段用于指定关系表 through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表 from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在数据库中创建外键约束 db_table=None, # 默认创建第三张表时,数据库中表的名称
多表或者说多数据模型之间的关系,请查看:多个数据模型间的关系