确定 M2M 字段是否具有自定义直通模型
Determine if an M2M field has a custom through model
对于 M2M 关系的自定义直通模型,.add()
、.create()
和 .remove()
被禁用。
目前,我尝试使用 .add()
(或其他)并捕获并处理那些自定义 M2M 关系的 AttributeError
。
是否有 'official' 方法通过模型识别自定义,使用 Meta
API 或其他方式?在我处理的这个阶段,我宁愿通过关系尽可能通用地处理所有自定义(而不是大量 if m2m_field.related.through == FooBar
语句)
(为 Django 1.8 找到了一个解决方案,但我开始为 2.2 悬赏)
看起来好像
m2m_field.related.through._meta.auto_created is False
完成任务。
从 Django 2.2 开始,.add()
、.create()
等方法可以使用自定义 through
模型,只要您为所需字段提供相应的值使用 through_defaults
:
的中间模型
You can also use add(), create(), or set() to create relationships, as long as you specify through_defaults for any required fields:
>>> beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
You may prefer to create instances of the intermediate model directly.
.remove()
方法的行为需要一点注意:
If the custom through table defined by the intermediate model does not enforce uniqueness on the (model1, model2) pair, allowing multiple values, the remove()
call will remove all intermediate model instances:
>>> Membership.objects.create(person=ringo, group=beatles,
... date_joined=date(1968, 9, 4),
... invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
>>> beatles.members.all()
<QuerySet [<Person: Paul McCartney>]>
关于 _meta
字段我无法从 m2m 字段访问它,但文档的上述部分似乎允许避免访问 _meta
的“体操”。
如果我发现任何有趣的事情,我会相应地更新我的答案。
对于django 2.2你可以直接检查through模型是否自动创建
这可以通过像下面这样的直接检查来检查
# check for the auto_created value
m2m_field.through._meta.auto_created == False
为了对此进行测试,我创建了一些具有多个 M2M 字段的示例类,一个具有自定义直通字段,一个具有默认 class。
from django.db import models
import uuid
class Leaf(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(null=True, max_length=25, blank=True)
# Create your models here.
class MainTree(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
new_leaves = models.ManyToManyField(Leaf, through='LeafTree')
leaves = models.ManyToManyField(Leaf, related_name='main_branch')
class LeafTree(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
tree = models.ForeignKey(MainTree, on_delete=models.CASCADE)
leaf = models.ForeignKey(Leaf, on_delete=models.CASCADE)
测试我们的方法
In [2]: from trees.models import MainTree
In [3]: m = MainTree()
In [4]: m.leaves.through._meta
Out[4]: <Options for MainTree_leaves>
In [5]: m.leaves.through._meta.auto_created
Out[5]: trees.models.MainTree
In [6]: m.new_leaves.through._meta.auto_created
Out[6]: False
In [7]: m.new_leaves.through._meta.auto_created == False
Out[7]: True
In [8]: m.leaves.through._meta.auto_created == False
Out[8]: False
对于 M2M 关系的自定义直通模型,.add()
、.create()
和 .remove()
被禁用。
目前,我尝试使用 .add()
(或其他)并捕获并处理那些自定义 M2M 关系的 AttributeError
。
是否有 'official' 方法通过模型识别自定义,使用 Meta
API 或其他方式?在我处理的这个阶段,我宁愿通过关系尽可能通用地处理所有自定义(而不是大量 if m2m_field.related.through == FooBar
语句)
(为 Django 1.8 找到了一个解决方案,但我开始为 2.2 悬赏)
看起来好像
m2m_field.related.through._meta.auto_created is False
完成任务。
从 Django 2.2 开始,.add()
、.create()
等方法可以使用自定义 through
模型,只要您为所需字段提供相应的值使用 through_defaults
:
You can also use add(), create(), or set() to create relationships, as long as you specify through_defaults for any required fields:
>>> beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)}) >>> beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)}) >>> beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
You may prefer to create instances of the intermediate model directly.
.remove()
方法的行为需要一点注意:
If the custom through table defined by the intermediate model does not enforce uniqueness on the (model1, model2) pair, allowing multiple values, the
remove()
call will remove all intermediate model instances:>>> Membership.objects.create(person=ringo, group=beatles, ... date_joined=date(1968, 9, 4), ... invite_reason="You've been gone for a month and we miss you.") >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]> >>> # This deletes both of the intermediate model instances for Ringo Starr >>> beatles.members.remove(ringo) >>> beatles.members.all() <QuerySet [<Person: Paul McCartney>]>
关于 _meta
字段我无法从 m2m 字段访问它,但文档的上述部分似乎允许避免访问 _meta
的“体操”。
如果我发现任何有趣的事情,我会相应地更新我的答案。
对于django 2.2你可以直接检查through模型是否自动创建
这可以通过像下面这样的直接检查来检查
# check for the auto_created value
m2m_field.through._meta.auto_created == False
为了对此进行测试,我创建了一些具有多个 M2M 字段的示例类,一个具有自定义直通字段,一个具有默认 class。
from django.db import models
import uuid
class Leaf(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(null=True, max_length=25, blank=True)
# Create your models here.
class MainTree(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
new_leaves = models.ManyToManyField(Leaf, through='LeafTree')
leaves = models.ManyToManyField(Leaf, related_name='main_branch')
class LeafTree(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
tree = models.ForeignKey(MainTree, on_delete=models.CASCADE)
leaf = models.ForeignKey(Leaf, on_delete=models.CASCADE)
测试我们的方法
In [2]: from trees.models import MainTree
In [3]: m = MainTree()
In [4]: m.leaves.through._meta
Out[4]: <Options for MainTree_leaves>
In [5]: m.leaves.through._meta.auto_created
Out[5]: trees.models.MainTree
In [6]: m.new_leaves.through._meta.auto_created
Out[6]: False
In [7]: m.new_leaves.through._meta.auto_created == False
Out[7]: True
In [8]: m.leaves.through._meta.auto_created == False
Out[8]: False