django

Django 1.6 Models (I)

基本的就不记了,只记暂时不知道的:

1. primary_key 属性

每个模型可以设定一个字段的 primary_key 属性为 True,如果这样做,自动的 id 字段将不会生成;

2. 模型的关系

模型的关系有(一对多,多对多,一对一);

另外还有递归引用(指向自己的外键):使用 ‘self’ 作为第一个参数;

以及指向未定义的模型的关系:使用类名的字符串作为第一个参数;

3. 为多对多关系指定额外的字段

多对多关系里面可以放额外的字段,除了关联的两个表的主键之外存放其他字段信息;使用 through 字段来显式为这个中间表指定一个模型,而在这个中间模型里面,必须显式指定两个 ForeignKey 字段分别指向这两个关联的模型;

但是中间模型必须遵从以下的限制条件:

  1. 有且仅有一个 ForeignKey 指向多对多关系的源模型;
  2. 有且仅有一个 ForeignKey 指向多对多关系的目标模型;
  3. 例外:如果多对多关系的源和目标都是同一个模型,这时候就可以这么干;
  4. 但是,这样的话,ManyToManyField 定义的时候必须制定参数 symmetrical=False

不过实际使用起来的时候会比较麻烦:

不能通过 add / create 或者赋值来创建关系,也不能通过 remove 来删除关系,但是可以使用 clear 来清除(一个源或目标对象的)所有的关系;

如果需要创建一个关系,必须显式创建一个中间对象;不同的只是,创建完中间对象之后在源模型和目标模型的对象依然可以通过 ManyToManyField 对象访问到对方;

如果要访问中间对象的其他属性,也只能显式创建一个中间对象;不过还可以通过中间对象的 ForeignKey 的反向引用来获取中间对象;

4. 一对一关系可以模拟“继承”

旧版本的一对一外键默认会被作为主键,但是新版已经不这么干了,因此可以让一个对象与多个其他对象建立一对一关系;

 5. 可以跨 app 建立关系

这个此前已经实践过了;只需要 import 相关的模型类即可;

6. 自定义列类型

主要针对如果现有的 django 提供的模型字段数据类型不能满足需要的情况;可以通过 Writing custom model fields 查看具体方法;

7. 模型内定义的方法

这些是模型类标准的方法集,可以通过重载这些方法来修改一些模型类的标准行为:

  • __str__() 或者 __unicode__()
  • get_absolute_url()
  • save(): 注意在批量 create 和 update 方法调用时无效
  • delete(): 注意在 manager 批量删除的时候无效

注意,重载这些方法的时候记得调用基类的方法,并传入所有命名/非命名参数:

from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def save(self, *args, **kwargs): if self.name == "Yoko Ono’s blog": return # Yoko shall never have her own blog! else: super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.

 8. 模型的继承

继承有三种方式(关键在于基类的字段是另放一张表还是放在派生类的表中);

  1. 如果使用 abstract 抽象基类,那么基类字段会放在子类的数据库表中;
  2. 如果直接继承(可以是多继承),那么每个类都会有一个自己的表,然后通过外键关联基类和子类;
  3. 如果只想变更一些 Python 级别(非 Django 级别)的特性(譬如数据库表结构一样但行为不一样的),那么可以使用代理模式;
Abstract 模式:

只需要在 Meta 类中加入 abstract=True 即可;

注意在 abstract 模式下,Meta 内部类的继承规则:

  • 如果子类没有声明 Meta,那么父类的 Meta 会被继承(但是会自动刨除掉 abstract, db_table 等一些不应该继承的字段)
  • 如果子类声明了 Meta,那么父类的 Meta 会被覆盖;
  • 如果需要继承父类的 Meta,必须显式这么做;

from django.db import models

class CommonInfo(models.Model): # ... class Meta: abstract = True ordering = [’name’]

class Student(CommonInfo): # ... class Meta(CommonInfo.Meta): db_table = ’student_info’

related_name 的指向

有一个可以想象的问题:如果基类包含一个关系,那么其子类也会继承这个关系;

但是如果在关系的另一边进行 related_name 反向访问会这边的属性的时候,就会出现问题:到底获得的是基类还是子类,还是哪一个子类?而且关键的是,在数据库中,这些不同的子类分布在不同的数据库表中,这样没有办法通过一个单独的数据库外键来描述清楚这些关系;

因此基类的关系字段的 related_name 需要特殊处理:

具体的方法就是在 related_name 里面加入 ’%(app_label)s’ 和 ’%(class)s’ 标签,然后在关联对方引用字段就会动态生成几个不同的 related_name 以指向不同的模型(基类或者子类)。具体使用方法说不清楚了,还是直接看原文吧:Be careful with related_name

当然,如果不这样来指定,related_name 会直接根据子类的名称加 _set 来指定到不同的子类;

多表继承(相对于 Abstract 的普通继承)

这种模式下,基类会有一个表,子类会有另一个表,然后他们通过一个隐式的 OneToOneField 进行关联;

多表继承模式的 Meta

这种情况下的 Meta 仅仅会在子类没有定义 ordering  或者 get_latest_by 的情况下继承基类 Meta 的这些属性,其他的不会继承;

指定继承的 OneToOneField

前面说到,多表继承的关系通过一个“隐式”的 OneToOneField 实现,类似于前面说到 ManyToManyField 中间表的处理方式,我们也可以指定这一个字段,以方便我们通过基类获取子类或者通过子类获取基类;我们只需要在子类中显示定义个 OneToOneField 然后加入 parent_link=True 属性即可。当然这种情况下,只能有一个字段这么干。

Proxy 模式继承

如果不想子类创建新的表,可以在子类的 Meta 里面指定 proxy=True,然后子类会共用父类的表(不能增加数据库字段),然后可以对一些不涉及数据库结构的 Python 层面的方法重写。

Proxy 模式与 manager

简而言之,Proxy 模型子类会继承父类的所有 manager,如果重新定义则会覆盖父类的 manager。

Model 继承不允许字段覆盖

对于 models 字段(数据库字段),是不允许进行字段覆盖的,但是纯粹的 python 字段可以。


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2014/03/django-models-1.html【Django 1.6 Models (I)】

发表评论

电子邮件地址不会被公开。 必填项已用*标注