没有外键的Django JOIN查询

时间:2013-05-21 11:56:32

标签: 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'

链接表对系统中给定的URL进行了更具描述性的翻译,这对于系统将生成的某些报告是必需的。

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

3 个答案:

答案 0 :(得分:11)

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

.raw()就是这样。即使它可能会比原始SQL慢很多。

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

答案 1 :(得分:7)

只需重新发布一些相关答案,这样每个人都可以看到它。 取自这里:Most efficient way to use the django ORM when comparing elements from two lists

  

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

     

我假设您的Model1Model2无关,   否则你就可以使用Django's related objects了   接口。您可以采取以下两种方法:

     
      
  1. 使用extra和SQL子查询:

    Model1.objects.extra(where = ['field in (SELECT field from myapp_model2 WHERE ...)'])
    
         

    在某些数据库中,子查询的处理效率不高   (特别是MySQL)所以这可能不如下面的#2那么好。

  2.   
  3. 使用raw SQL query

    Model1.objects.raw('''SELECT * from myapp_model1
                       INNER JOIN myapp_model2
                       ON myapp_model1.field = myapp_model2.field
                       AND ...''')
    
  4.         

    第二个问题:枚举结果

         

    两种方法:

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

      enumerate(Model1.objects.all())
      
    2.   
    3. 您可以使用this answer中描述的技术在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 ...''')
      
    4.   

答案 2 :(得分:0)

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

尝试一下:

request_url = models.ForeignKey(UserActivityLink, to_field='url_description', null=True, on_delete=models.SET_NULL, db_constraint=False)

请注意,db_constraint=False必需的,如果没有ALTER TABLE `user_activity` ADD CONSTRAINT `xxx` FOREIGN KEY (`request_url`) REFERENCES `user_activity_link` (`url_description`);" ,Django将会构建如下的SQL:

$a = 1 ;DO { 'Starting Loop' ; $vischk = get-process | where-object {$_.mainwindowhandle -ne 0 -and $_.MainWindowTitle -eq 'Start - Microsoft Edge'} | select-object name, mainwindowtitle ; if (!($vischk))  {Write-Warning 'Microsoft Edge is off'}else{Write-Warning 'Closing Chrome' Stop-Process -name chrome} ; Write-Warning 'Active surveillance' ; Start-Sleep -s 15} While ($a -le 2)

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

希望有帮助。