问题 Django模型 - 分配id而不是object


如果我的问题变得愚蠢,我很抱歉,但我对Django很新,我无法在任何地方找到答案。

我有以下型号:

class BlackListEntry(models.Model):
  user_banned = models.ForeignKey(auth.models.User,related_name="user_banned")
  user_banning = models.ForeignKey(auth.models.User,related_name="user_banning")

现在,当我尝试创建这样的对象时:

BlackListEntry.objects.create(user_banned=int(user_id),user_banning=int(banning_id))

我收到以下错误:

Cannot assign "1": "BlackListEntry.user_banned" must be a "User" instance.

当然,如果我用这样的东西替换它:

user_banned = User.objects.get(pk=user_id)
user_banning = User.objects.get(pk=banning_id)
BlackListEntry.objects.create(user_banned=user_banned,user_banning=user_banning)

一切正常。问题是:

我的解决方案是否访问数据库以检索两个用户,如果是,是否可以避免它,只是传递ID?


6425
2017-10-01 22:54


起源



答案:


你的问题的答案是:是的。

Django将在数据库中(至少)3次,2次检索两个User对象,第三次提交所需信息。这将导致绝对不必要的开销。

你试一试:

BlackListEntry.objects.create(user_banned_id=int(user_id),user_banning_id=int(banning_id))

这些是Django ORM生成的FK字段的默认名称模式。这样,您可以直接设置信息并避免查询。

如果要查询已保存的BlackListEntry对象,可以使用双下划线导航属性,如下所示:

BlackListEntry.objects.filter(user_banned__id=int(user_id),user_banning__id=int(banning_id))

这是您访问Django查询集中的属性的方法。双下划线。然后,您可以比较属性的值。

虽然非常相似,但它们完全不同。第一个直接设置属性,而第二个由django解析,将其拆分为'__',并以正确的方式查询数据库,第二部分是属性的名称。

你可以随时比较 user_banned 和 user_banning 使用实际的User对象,而不是它们的ID。但如果您还没有这些对象,则没有用处。

希望能帮助到你。


13
2017-10-01 23:10



这给了我:'user_banning__id'是这个函数的无效关键字参数 - Marcin Kulus
对不起,我刚刚意识到你正在创造这个对象。因此,您需要使用单个下划线进行访问。我将编辑我对门诊原因的回答。 - Francisco
谢谢,现在它的工作原理。我会给你加+1,但我还不能那样做。 - Marcin Kulus
没问题。很高兴它有所帮助。 - Francisco


答案:


你的问题的答案是:是的。

Django将在数据库中(至少)3次,2次检索两个User对象,第三次提交所需信息。这将导致绝对不必要的开销。

你试一试:

BlackListEntry.objects.create(user_banned_id=int(user_id),user_banning_id=int(banning_id))

这些是Django ORM生成的FK字段的默认名称模式。这样,您可以直接设置信息并避免查询。

如果要查询已保存的BlackListEntry对象,可以使用双下划线导航属性,如下所示:

BlackListEntry.objects.filter(user_banned__id=int(user_id),user_banning__id=int(banning_id))

这是您访问Django查询集中的属性的方法。双下划线。然后,您可以比较属性的值。

虽然非常相似,但它们完全不同。第一个直接设置属性,而第二个由django解析,将其拆分为'__',并以正确的方式查询数据库,第二部分是属性的名称。

你可以随时比较 user_banned 和 user_banning 使用实际的User对象,而不是它们的ID。但如果您还没有这些对象,则没有用处。

希望能帮助到你。


13
2017-10-01 23:10



这给了我:'user_banning__id'是这个函数的无效关键字参数 - Marcin Kulus
对不起,我刚刚意识到你正在创造这个对象。因此,您需要使用单个下划线进行访问。我将编辑我对门诊原因的回答。 - Francisco
谢谢,现在它的工作原理。我会给你加+1,但我还不能那样做。 - Marcin Kulus
没问题。很高兴它有所帮助。 - Francisco


我确实相信当你获取用户时,它会击中数据库......

要避免它,您必须使用此处描述的方法编写原始sql以执行更新:

https://docs.djangoproject.com/en/dev/topics/db/sql/

如果您决定走这条路线,请记住,您有责任保护自己免受SQL注入攻击。

另一种方法是缓存user_banned和user_banning对象。

但很有可能,只需抓住用户并创建BlackListEntry就不会导致任何明显的性能问题。缓存或执行原始sql只会提供一个小的好处。在此成为问题之前,您可能会遇到其他问题。


0
2017-10-01 22:55