没有外键的Django JOIN查询

xXP*_*2Xx 6 django django-models django-queryset

在Django中是否有一种方法可以使用ORM编写查询,而不是原始SQL允许您在没有外键的情况下在另一个表上加入?通过查看文档,为了使One to One关系起作用,必须存在外键?

在下面的模型中,我想在UserActivity.request_url上使用JOIN运行一个查询到UserActivityLink.url.

class UserActivity(models.Model):
    id = models.IntegerField(primary_key=True)
    last_activity_ip = models.CharField(max_length=45L, blank=True)
    last_activity_browser = models.CharField(max_length=255L, blank=True)
    last_activity_date = models.DateTimeField(auto_now_add=True)
    request_url = models.CharField(max_length=255L, blank=True)
    session_id = models.CharField(max_length=255L)
    users_id = models.IntegerField()
    class Meta:
        db_table = 'user_activity'

class UserActivityLink(models.Model):
    id = models.IntegerField(primary_key=True)
    url = models.CharField(max_length=255L, blank=True)
    url_description = models.CharField(max_length=255L, blank=True)
    type = models.CharField(max_length=45L, blank=True)
    class Meta:
        db_table = 'user_activity_link'
Run Code Online (Sandbox Code Playgroud)

链接表具有系统中给定URL的更具描述性的转换,这是系统将生成的一些报告所需的.

我尝试从UserActivity.request_url创建外键到UserActivityLink.url但它失败并出现以下错误:错误1452:无法添加或更新子行:外键约束失败

Hen*_*son 11

不,不幸的是没有一种有效的方法.

.raw()就是确切的事情.即使它可能会比原始SQL慢很多.

这里有一篇博客文章,详细说明如何使用它,query.join()但正如他们自己指出的那样.这不是最好的做法.


Xia*_*eng 11

DjangoForeignKey与 SQL ForeignKey 不同。Django ForeignKey 只是代表一个关系,它可以指定是否使用数据库约束。

尝试这个:

request_url = models.ForeignKey(UserActivityLink, to_field='url_description', null=True, on_delete=models.SET_NULL, db_constraint=False)
Run Code Online (Sandbox Code Playgroud)

请注意,db_constraint=Falserequired,没有它 Django 将构建一个 SQL,如:

ALTER TABLE `user_activity` ADD CONSTRAINT `xxx` FOREIGN KEY (`request_url`) REFERENCES `user_activity_link` (`url_description`);" 
Run Code Online (Sandbox Code Playgroud)

我遇到了同样的问题,经过大量研究,我找到了上述方法。

希望能帮助到你。


Vas*_*yev 7

只需重新发布一些相关的答案,这样每个人都可以看到它.摘自此处:比较两个列表中的元素时使用django ORM的最有效方法

第一个问题:加入不相关的模型

我假设您Model1和您Model2没有关系,否则您将能够使用Django的相关对象 界面.您可以采取以下两种方法:

  1. 使用extra和SQL子查询:

    Model1.objects.extra(where = ['field in (SELECT field from myapp_model2 WHERE ...)'])
    
    Run Code Online (Sandbox Code Playgroud)

    在某些数据库(尤其是MySQL)中,子查询的处理效率不高,因此这可能不如下面的#2那么好.

  2. 使用原始SQL查询:

    Model1.objects.raw('''SELECT * from myapp_model1
                       INNER JOIN myapp_model2
                       ON myapp_model1.field = myapp_model2.field
                       AND ...''')
    
    Run Code Online (Sandbox Code Playgroud)

第二个问题:枚举结果

两种方法:

  1. 您可以使用内置enumerate函数枚举Python中的查询集:

    enumerate(Model1.objects.all())
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您可以使用此答案中描述的技术在MySQL中进行枚举.像这样的东西:

    Model1.objects.raw('''SELECT *, @row := @row + 1 AS row
                       FROM myapp_model1
                       JOIN (SELECT @row := 0) rowtable
                       INNER JOIN myapp_model2
                       ON myapp_model1.field = myapp_model2.field
                       AND ...''')
    
    Run Code Online (Sandbox Code Playgroud)