【问题标题】:Django makemigrations error on many to many relationship多对多关系上的Django makemigrations错误
【发布时间】:2021-07-06 21:57:17
【问题描述】:

我想要什么:

存储有关人群运行的信息。

我做了什么:

from django.db import models
from django.contrib.auth.models import User
from datetime import timedelta


class Route(models.Model):
    name = models.CharField(max_length=50)


class Run(models.Model):
    date = models.DateField()
    type = models.ForeignKey(Route, on_delete=models.PROTECT)
    runners = models.ManyToManyField(User, through='RunnerResult', through_fields=["user", "run"])


class RunnerResult(models.Model):
    user = models.ForeignKey(User, on_delete=models.PROTECT)
    run = models.ForeignKey('Run', on_delete=models.PROTECT)
    result = models.DurationField(default=timedelta())

问题:

当我执行makemigrations 时,出现以下错误:

SystemCheckError: System check identified some issues:

ERRORS:
run.Run.runners: (fields.E339) 'RunnerResult.run' is not a foreign key to 'User'.
        HINT: Did you mean one of the following foreign keys to 'User': user?
run.Run.runners: (fields.E339) 'RunnerResult.user' is not a foreign key to 'Run'.
        HINT: Did you mean one of the following foreign keys to 'Run': run?

试图通过_fields 和模型在彼此之间以及其他一些操作之间交换。我开始思考我对 M2M 关系的误解。

【问题讨论】:

    标签: django django-models orm m2m dbm


    【解决方案1】:

    您在错误的顺序中指定了through_fields。您首先应该指定引用 source 的关系,然后再指定引用 target 的关系,所以:

    class Run(models.Model):
        date = models.DateField()
        type = models.ForeignKey(Route, on_delete=models.PROTECT)
        runners = models.ManyToManyField(
            User,
            through='RunnerResult',
            through_fields=('run', 'user')
        )

    由于ForeignKeyRunUser 只有一个,因此您不需要指定through_fields=… parameter [Django-doc]。因此,您可以将其实现为:

    class Run(models.Model):
        date = models.DateField()
        type = models.ForeignKey(Route, on_delete=models.PROTECT)
        runners = models.ManyToManyField(
            User,
            through='RunnerResult'
            # no through_fields
        )

    注意:通常使用settings.AUTH_USER_MODEL [Django-doc] 引用用户模型比直接使用User model [Django-doc] 更好。更多信息可以查看referencing the User model section of the documentation

    【讨论】:

    • 这有助于“makemigrations”。但是迁移后我遇到了以下问题: ValueError: Cannot alter field run.Run.runners into run.Run.runners - 它们不是兼容的类型(您不能更改 M2M 字段或从 M2M 字段更改,或在 M2M 字段上添加或删除 through=)现在将尝试修复此问题。
    • @Naur:您是否已经迁移到ManyToManyField没有through=...?因为添加 through=... 并不是 Django 正确迁移的东西。我认为在这种情况下,您最好删除 m2m,迁移,然后使用 through 创建一个新的。
    • 我已经按照你说的做了,没有M2M迁移,然后返回这段代码,再次迁移,一切正常。非常感谢!