Django2.0入门教程:模型元数据Meta选项详解

管理后台与model模型文章里,我们创建了一个简单的数据模型,迁移数据,创建了管理帐号,并进入了Django管理后台。

3.jpg

现在我们在后台添加两个文章分类,然后添加几篇文章。在添加文章的时候,我们选择之前添加的文章分类,显示如下:

1.jpg

文章添加成功之后,在后台显示如下:

2.jpg


大家可以仔细看看上边的三张图片,我用红框标记的地方。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,              # 默认创建第三张表时,数据库中表的名称

多表或者说多数据模型之间的关系,请查看:多个数据模型间的关系

该文章例子的代码:

mysite.zip


文章评论 0