如何在 django 中进行内部连接?

Posted

技术标签:

【中文标题】如何在 django 中进行内部连接?【英文标题】:How to make an Inner Join in django? 【发布时间】:2018-06-16 03:47:29 【问题描述】:

我想在 html 中显示出版物所在城市、州和国家/地区的名称。但它们位于不同的表中。

这是我的 models.py

class country(models.Model):
    country_name = models.CharField(max_length=200, null=True)
    country_subdomain = models.CharField(max_length=3, null=True)
    def __str__(self):
        return self.country_name

class countrystate(models.Model):
    state_name = models.CharField(max_length=200, null=True)
    country = models.ForeignKey(country, on_delete=models.CASCADE, null=True)
    importance = models.IntegerField(null=True)
    def __str__(self):
        return self.state_name

class city(models.Model):
    city_name = models.CharField(max_length=200, null=True)
    countrystate = models.ForeignKey(countrystate, on_delete=models.CASCADE, null=True)
    def __str__(self):
        return self.city_name

class publication(models.Model):
    user = ForeignKey(users, on_delete=models.CASCADE, null=False)
    title= models.CharField(max_length=300, null=True)
    country=models.ForeignKey(country, on_delete=models.CASCADE, null=True)
    countrystate=models.ForeignKey(countrystate, on_delete=models.CASCADE, null=True)
    city=models.ForeignKey(city, on_delete=models.CASCADE, null=True)

    def __str__(self):
        return self.title

这是我的意见.py

def publications(request):
    mypublications = publication.objects.filter(user_id=request.session['account_id'])
    dic.update("plist": mypublications )
    return render(request, 'blog/mypublications.html', dic)

在 django 视图中,下一个 sql 查询的等价物是什么?

SELECT p.user_id, p.title, c.cuntry_id, c.country_name, s.state_id, s.state_name, y.city_id, y.city_name FROM publication AS p
INNER JOIN country AS c ON c.id = p.country_id
INNER JOIN countrystate AS s ON s.id = p.countrystate_id
INNER JOIN city AS y ON y.id = p.city_id

【问题讨论】:

你必须使用 Q 函数 - 见例子***.com/questions/30418162/… 【参考方案1】:

这应该对你有用:

publication = publication.objects.select_related('yourfield', 'yourfield', 'yourfield')

【讨论】:

【参考方案2】:
from django.db import models

class Course(models.Model):
    name=models.CharField(max_length=10)
    courseid=models.CharField(max_length=30,primary_key=True)
class Enrollment(models.Model):
    course=models.ForeignKey(Course,on_delete=models.CASCADE)
    enrollid=models.CharField(max_length=20)

#Queryset:
k=Enrollment.objects.filter(course__courseid=1).values('id','course__courseid','course__name','enrollid')

print(k.query)
SELECT "app1_enrollment"."id", "app1_enrollment"."course_id", "app1_course"."name", "app1_enrollment"."enrollid" FROM "app1_enrollment" INNER JOIN "app1_course" ON ("app1_enrollment"."course_id" = "app1_course"."courseid") WHERE "app1_enrollment"."course_id" = 1

【讨论】:

嗨,Bapan Biswas,欢迎您。请考虑添加代码说明。 上面的例子展示了如何使用 django ORM 和 Queryset 执行 INNER JOIN。【参考方案3】:

对于这个简单的案例,您不需要 INNER JOIN 或 select_related,因为您可以直接在模板中遍历到 citycountrystatecountry——基于我刚刚在我的项目。

由于您的 QuerySet 是通过上下文 dic['plist'] 设置的,因此,在模板中您可以:

% for itero in plist %

 itero.title 
 itero.city.city_name 
 itero.citystate.citystate_name 
 itero.country.country_name 

% endfor %

【讨论】:

是否也可以前向遍历模板中的所有 FK 依赖项? itero.city.citystate.citystate_name itero.city.citystate.country.country_name 如果可行,您可以从publication 中删除citystatecountry 的FK。 它可以工作,但是对于大量数据它的性能很差。如果初始查询中没有“select_related”, itero.city.city_name 将导致每次循环迭代都有额外的 db 命中,因为尚未检索到 city 条目。 country 和 city_state 以及它们各自的属性也是如此。如果您有 50 个 pub,您将从 1 个 db 查询变为 151 个,因为 ORM 必须检索 3 个相关对象以查找它们的属性 50 次。【参考方案4】:

让我从描述术语的含义开始,然后按顺序进行......

InnerJoin 意味着两个(或更多)表之间的“公共”部分。正如您的 SQL 查询所建议的那样,每个都一个接一个地执行。

通过您的 SQL 查询,您将 Publication 视为主要查询,您的所有查询都是发布中的外键,从而为您提供了整个数据集。

如果我的理解正确,您在 Django 等效项中寻找的是过滤器,链式(而不是查询),因为 Q 会分别为您提供每个 Q 的结果并将它们连接起来,而您希望将一个结果应用于另一个。

(我不知道 dic.update("plist": mypublications ) 做了什么,不清楚.. 解决方案: country = country.objects.all() # 获取国家表中的所有国家。 country_state = countrystate.objects.all() # 获取所有 countrystate 对象 city = city.objects.all() # 获取所有城市对象

解决方案1:在python3中你需要使用__in,这在Python2中可以正常工作。并将为您提供来自表国家(非无)、表国家(非无)、表城市(非无)的任何内容,所以如果他们中的任何一个有任何东西,它会提供。 注意:“无”(python)=“空”(SQL 数据库) 获取所有具有上述任何内容的出版物(实际上会给你带来任何东西。 publications_list = publication.objects.filter(country = country, countrystate = country_state, city = city) # 获取“id”(基于哪个是对象)匹配的任何人中的任何人,这使其本身成为内连接。

【讨论】:

【参考方案5】:

您可能正在寻找select_related,这是实现此目的的自然方式:

pubs = publication.objects.select_related('country', 'country_state', 'city')

您可以通过str(pubs.query) 检查生成的 SQL,这应该会导致以下行的输出(示例来自 postgres 后端):

SELECT "publication"."id", "publication"."title", ..., "country"."country_name", ...  
FROM "publication" 
INNER JOIN "country" ON ( "publication"."country_id" = "country"."id" ) 
INNER JOIN "countrystate" ON ( "publication"."countrystate_id" = "countrystate"."id" ) 
INNER JOIN "city" ON ( "publication"."city_id" = "city"."id" ) 

然后将返回的游标值转换为适当的 ORM 模型实例,这样当您遍历这些发布时,您可以通过它们自己的对象访问相关表的值。但是,这些沿预选前向关系的访问不会导致额外的数据库命中:

% for p in pubs %
      p.city.city_name  # p.city has been populated in the initial query
     # ...
% endfor %

【讨论】:

反向关系呢?

以上是关于如何在 django 中进行内部连接?的主要内容,如果未能解决你的问题,请参考以下文章

在使用 ORM 的 Django 中,如何对不同的值进行多个自连接

如何通过不同级别的枢轴聚合然后在pyspark中进行内部连接?

构造一个 django 查询集,用于对内部连接进行排序

我将如何将这些多个连接作为 Django 查询集进行?

如何在Django模板的内部for循环中使用外部for循环值

如何优化涉及内部连接的条件子选择?