附加“_id”的OneToOne字段上的Django过滤器并失败

Posted

技术标签:

【中文标题】附加“_id”的OneToOne字段上的Django过滤器并失败【英文标题】:Django filter on OneToOne field appending "_id" and failing 【发布时间】:2020-07-06 14:31:14 【问题描述】:

在我的 Django 应用程序中,我有以下模型:

class Provider(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, primary_key=True)
    company = models.ForeignKey(Company, on_delete=models.CASCADE)

    def __str__(self):
        return str(self.user)

注意user 是我的 CustomUser 表的 OneToOneField,也是该表的主键。

views.py 中,我尝试使用Provider.objects.filter(user=request.user) 查询此表并获得django.db.utils.OperationalError: (1054, "Unknown column 'appname_provider.user_id' in 'field list'")。检查我的 mysql 数据库,我看到列是 (user, company_id)。那么,当我尝试过滤时,为什么 Django 会在 user 中添加“_id”?

我的 CustomUser 模型:

class CustomUser(AbstractUser):
    is_provider = models.BooleanField()
    is_admin = models.BooleanField()
    first_name = models.CharField(max_length=128)
    last_name = models.CharField(max_length=128)
    email = models.EmailField(unique=True)
    REQUIRED_FIELDS = ["is_provider", "email"]
    objects = CustomUserManager()

    def __str__(self):
        return str(self.username)

【问题讨论】:

可能重复:https://***.com/questions/13116130/django-suffix-foreignkey-field-with-id @RobMoll 这是不同的,因为这里 Django 不是在数据库中添加“_id”,而是在查询中添加。我尝试添加db_column=user_id,但迁移后列在mysql中仍然命名为user,问题仍然存在。 您的CustomUser 模型是什么样的? request.user 长什么样子?是用户的ID吗?您是否尝试在查询之前检索实例?例如。 Provider.objects.filter(user=CustomUser.objects.get(pk=request.user))?您还可以使用跨越关系的查找,例如Provider.objects.filter(user__id=request.user)。假设您拥有用户的 ID。 @yvesonline request.user 是 <SimpleLazyObject: <CustomUser: username>>,而不是 id,因此这些查询不起作用。不幸的是,即使Provider.objects.filter(user__id=request.user.id) 也因我最初遇到的错误而失败。在其他地方,对于user 是 ForeignKey 的表,我可以说 user=request.user,因为 Django 附加了“_id”,但它不适用于 OneToOne 字段。我在问题中添加了我的CustomUser 模型。 【参考方案1】:

我是这样解决这个问题的:

    撤消所有迁移:rm -rf appname/migrations/0* appname/__pycache__ 和在 mysql 中:DELETE FROM django_migrations; 删除mysql中的Provider表:DROP TABLE appname_provider; 在 mysql 中使用列 user_id 而不是 user 重新创建 Provider 表:CREATE TABLE appname_provider (user_id INT PRIMARY KEY, company_id INT); 重置内置应用程序的迁移:python manage.py migrate --fake 为此应用程序进行迁移:python manage.py makemigrations appname 假运行迁移,因为所有表仍在数据库中:python manage.py migrate --fake 然后我需要将company_id 设为外键,因为我在第3 步中没有这样做,所以在Provider 中我做了company = models.IntegerField(),进行并运行迁移,然后将其设置回company = models.ForeignKey(Company, on_delete=models.CASCADE),再次进行并运行迁移。这有点 hacky,但是如果没有这种来回更改,Django 没有检测到它必须将 company_id 设为外键。

现在Provider 在数据库中包含user_id 列而不是user,因此查询有效!请注意,使用这种方法会丢失Provider 表中的所有数据,但会保留数据库的其余部分。我从这个答案中得到了一些步骤:https://***.com/a/29898483/7632019。

【讨论】:

以上是关于附加“_id”的OneToOne字段上的Django过滤器并失败的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB - 使用迭代更新集合上的每个“_id”字段

Django 中的 OneToOne、ManyToMany 和 ForeignKey 字段有啥区别?

Django OneToOne 字段到自我

ForeignKey vs OneToOne 字段 django [重复]

如何在 Django Admin 中更改 OneToOne 模型字段默认消息?

MongoDB 聚合两个集合,返回附加字段作为计数