附加“_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过滤器并失败的主要内容,如果未能解决你的问题,请参考以下文章
Django 中的 OneToOne、ManyToMany 和 ForeignKey 字段有啥区别?
ForeignKey vs OneToOne 字段 django [重复]