在两个第三方模型之间添加Django M2M关系

在两个第三方模型之间添加Django M2M关系,django,django-models,many-to-many,Django,Django Models,Many To Many,我需要在两个模型之间创建多对多关系。在Django中,您通常会向两个模型之一添加一个ManyToManyField。然而,就我而言: 这两个模型来自第三方库,通常是User和Car 这两个字段都是非抽象的,例如,我想避免多表继承的复杂性,只需添加一个M2M字段(实际上两个表中都不需要额外的列) 我的工作假设其他人会像(如果不是字面上的)第三方库一样使用它,所以我真的想提供标准接口,尽管有限制 显然,我可以创建一个“手动”M2M表: class UserCar(models.Model):

我需要在两个模型之间创建多对多关系。在Django中,您通常会向两个模型之一添加一个
ManyToManyField
。然而,就我而言:

  • 这两个模型来自第三方库,通常是
    User
    Car
  • 这两个字段都是非抽象的,例如,我想避免多表继承的复杂性,只需添加一个M2M字段(实际上两个表中都不需要额外的列)
  • 我的工作假设其他人会像(如果不是字面上的)第三方库一样使用它,所以我真的想提供标准接口,尽管有限制
显然,我可以创建一个“手动”M2M表:

class UserCar(models.Model):
    user = models.ForeignKey(User)
    car = models.ForeignKey(Car)

    class Meta:
        unique_together = ('user', 'car')
。。。但是Django会将这两个
ForeignKey
字段视为一对多,因此标准的“魔法”访问器将不可用:

user.cars.add(car)
car in user.cars
User.objects.filter(cars=car)

有没有一种简单的方法可以在双方的关系中注入M2M的魔力
UserCar
基本上是一个
到=
表。我是否可以创建一个虚拟字段并调用一两个方法(例如,
contribute\u to_class
contribute\u to_related\u class
)来完成此操作?我试图通过
ForeignKey
manytomy
来迷惑,但我对正常的字段级处理还不够熟悉,甚至无法猜测关键方法(更不用说排序和延迟处理了)。

在评论中,@Alexandratarinov建议在通过表创建
之后立即使用
add_to_class
ManyToManyField
添加到
Car
。我仍然对更好的答案持开放态度,但这肯定是一个答案(也是目前最好的答案)。假设我们使用如下代码:

# guard against repeated import
if not hasattr(Car, 'users'):
    field = models.ManyToManyField(User, through=UserCar, related_name='cars')
    field.contribute_to_class(Car, 'users')
这种方法的效果(包括缺点)是:

  • 魔法访问器添加到关系的两侧
  • 将在应用程序中为
    Car
    添加迁移(添加M2M字段)。此迁移不会提交到我的包的存储库,可能会导致一些奇怪的问题。例如
    • 如果开发人员使用my package作为依赖项,则当开发人员调用
      makemigrations
      时,将(重新)创建迁移。如果以后升级了
      Car
      包(包括新的迁移),这可能会导致开发机器上出现类似“两个叶节点”的错误
  • 当我删除
    Car
    迁移以模拟生产场景案例时,一个简单的测试确实起作用(例如,在创建了两个相关对象之后,
    user.places
    place.users
    工作正常)
  • 因为M2M表定义为一个
    表,所以像
    place.users.add()
    这样的方法不能立即使用(即使M2M表与该字段自动创建的表完全相同)
由于手动创建的
到=
模型上的
auto_created=False
引发了
place.users.add()
问题。如果我在
UserCar.Meta
中设置
auto\u created=Car
,神奇的方法会起作用,但不会创建迁移。为了利用默认迁移和恢复行为,我可以使用以下方法:

@receiver(request_started)
def set_auto_created(**kwargs):
    UserCar._meta.auto_created = Car
编辑:在早期的迭代中,我使用了
auto\u created=True
。这导致了
TransactionTestCase
中的
FLUSH
出现问题。在挖掘M2M字段代码后,似乎需要将自动创建的
指向包含
ManyToManyField
的模型。我认为这与如何在
TransactionTestCase
中管理自动创建的表有关

EDIT2:我还尝试将信号附加到
post\u migrate
。这对于测试很好(因为它们总是迁移),但在生产环境中不起作用<代码>请求\u已启动
似乎对这两者都有效


通过此增强,应用程序中为
Car
创建的额外迁移是此策略的唯一主要问题。

您可以尝试使用
User。将_添加到_类('cars',models.ManyToManyField(..)
)中,但我对此不确定。它可能会抱怨迁移,如果这是第三方软件包,我不知道下一步该怎么办。可能会创建到该包的新迁移)。无论如何,给它一个机会。另外,它也会给你提到的课程打电话。我一定会试试这个。“通过”模型应该以任何一种方式创建。。。要么它被选为直通车,要么它不是,它只是一个一等公民,是自己创造的。是的,我理解。然而,当您添加ManyToManyField时,即使使用through表,django仍然会创建一个迁移来跟踪迁移历史中的该字段,即使这不会改变数据库中的任何内容。我现在不确定,但有一个很大的机会)我使用了一个简单的
如果不是hasattr
作为防止重复调用
add\u to\u class
。它添加了字段,但迁移是在与
Car
相同的包中创建的(我将字段添加到
Car
),因此它们不会提交到我的repo.Hmm。可以在第三方内部创建迁移吗?也许他们只是一种增加关系经理的方式?也许你应该看看很多领域。为班级做贡献。。。