iblogc

Django 关联对象字段

2015-12-10 · 7 min read
Django

关联字段

ForeignKey多对一关系

class ForeignKey(othermodel[, **options])

如果关联模型还没有创建,可以使用该模型的名字而不是模型本身来指定

options

limit_chices_to

对关联对象进行过滤,可以是一个字典, 一个 Q 对象, 或者一个可调用的返回字典或者Q对象的对象

related_name
在关联对象上返回这个对象的名称,替代默认的xxx_set
django字段选项related_name和related_query_name.md

在关联对象上进行查询时使用的名称

to_field

指定关联到关联对象的字段名称,默认使用关联对象主键

db_constraint

是否在数据库中为这个外键创建约束的控制。默认值为 True, 而且这几乎一定是你想要的效果。如果设置成 False 对数据集成来说是很糟糕的。即便如此,有一些场景你也许想要这么设置:

  • 你有遗留的无效数据。
  • 你正在对数据库缩容。
    如果被设置成 False, 访问一个不存在的关联对象将抛出 DoesNotExist 异常。

on_delete

当此外键引用的对象被删除时,这个字段的行为

  • CASCADE 级联删除,默认
  • PROTECT 抛出ProtectedError,阻止被引用对象删除,django.db.IntegrityError的一个子类
  • SET_NULL 把此字段设置为null,null必须为True
  • SET_DEFAULT 设置成默认值, default必须设置
  • SET() 设置一个自定义的值,可以是一个返回相应值的方法
  • DO_NOTHING 不做任务操作,不过可能会抛出IntegrityError异常,需要捕获异常并手动删除约束

swappable

allow_unsaved_instance_assignment

ManyToManyField多对多关系

class ManyToManyField(othermodel[, **options])

同ForeignKey.related_name

同ForeignKey.related_query_name

limit_choices_to

同ForeignKey.limit_choices_to

symmetrical

只有在关联自身情况下使用,默认是对称的,即如果a是b的好友,默认b也是a的好友,要取消对称设置symmetrical为False

from django.db import models
 
class Person(models.Model):
    friends = models.ManyToManyField("self")

through

djagno默认会自动创建一个表来管理多对多的关系,但是你可以自己建立中介表,然后来手动指定。详细
注意:手动指定中间表后,关联表的add create remove将不可用,但clear还是可以用的
(http://python.usyiyi.cn/django/ref/models/fields.html#django.db.models.ManyToManyField.through)

through_fields

在中间表中对应的字段名,只能在自定义中间表时使用[详细]

db_table

指定中间表名称

db_constraint

是否为外键创建约束,默认为True

swappable

allow_unsaved_instance_assignment

OneToOneField一对一关系

这个是一个对一关联关系。总体上,这个字段类很像是ForeignKey设置了unique=True, 不同的是它会直接返回关系的另一边的对象。

from django.conf import settings
from django.db import models
 
class MySpecialUser(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    supervisor = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='supervisor_of')

>>> user = User.objects.get(pk=1)
>>> hasattr(user, 'myspecialuser')
True
>>> hasattr(user, 'supervisor_of')
True

关联对象参考

import datetime
from django.db import models
 
class Blog(models.Model):
    ...
 
class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    published = models.DateTimeField(default=datetime.datetime.now)
    ...

有以下方法
blog.entry_set
entry.blog

class Topping(models.Model):
    # ...
    pass
 
class Pizza(models.Model):
    toppings = models.ManyToManyField(Topping)

有以下方法
topping.pizza_set
pizza.toppings

add(obj1[, obj2, ...])

把指定的模型对象添加到关联对象集中。

>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.add(e) # Associates Entry e with Blog b.

不需要调用save()方法

create(**kwargs)

创建一个新的对象,保存对象,并将它添加到关联对象集之中。返回新创建的对象:

>>> b = Blog.objects.get(id=1)
>>> e = b.entry_set.create(
...     headline='Hello',
...     body_text='Hi',
...     pub_date=datetime.date(2005, 1, 1)
... )
# No need to call e.save() at this point -- it's already been saved.

这完全等价于(不过更加简洁于):

>>> b = Blog.objects.get(id=1)
>>> e = Entry(
...     blog=b,
...     headline='Hello',
...     body_text='Hi',
...     pub_date=datetime.date(2005, 1, 1)
... )
>>> e.save(force_insert=True)

要注意我们并不需要指定模型中用于定义关系的关键词参数。在上面的例子中,我们并没有传入blog参数给create()。Django会明白新的 Entry对象blog 应该添加到b中。

remove(obj1[, obj2, ...])

从关联对象集中移除执行的模型对象(不是删除)

>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.remove(e) # Disassociates Entry e from Blog b.

和add()相似,上面的例子中,e.save()可会执行更新操作。但是,多对多关系上的remove(),会使用QuerySet.delete()删除关系,意思是并不会有任何模型调用save()方法:如果你想在一个关系被删除时执行自定义的代码,请监听m2m_changed信号。

对于ForeignKey对象,这个方法仅在null=True时存在。如果关联的字段不能设置为None (NULL),则这个对象在添加到另一个关联之前不能移除关联。在上面的例子中,从b.entry_set()移除e等价于让e.blog = None,由于blog的ForeignKey没有设置null=True,这个操作是无效的。

对于ForeignKey对象,该方法接受一个bulk参数来控制它如果执行操作。如果为True(默认值),QuerySet.update()会被使用。而如果bulk=False,会在每个单独的模型实例上调用save()方法。这会触发pre_save和post_save,它们会消耗一定的性能。

clear()

从关联对象集中移除一切对象(不是删除)

>>> b = Blog.objects.get(id=1)
>>> b.entry_set.clear()

注意这样不会删除对象 —— 只会删除他们之间的关联。
就像 remove() 方法一样,clear()只能在 null=True的ForeignKey上被调用,也可以接受bulk关键词参数。

注意
注意对于所有类型的关联字段,add()、create()、remove()和clear()都会马上更新数据库。换句话说,在关联的任何
端,都不需要再调用save()方法。
同样,如果你再多对多关系中使用了中间模型,一些关联管理的方法会被禁用。

直接赋值

通过赋值一个新的可迭代的对象,关联对象集可以被整体替换掉。

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set = new_list 

如果外键关系满足null=True,关联管理器会在添加new_list中的内容之前,首先调用clear()方法来解除关联集中一切已存在对象的关联。否则, new_list中的对象会在已存在的关联的基础上被添加。

Powered by Gridea && Deployed by 部署状态