如何在 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
,因为您可以直接在模板中遍历到 city
、countrystate
和 country
——基于我刚刚在我的项目。
由于您的 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
中删除citystate
和country
的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中进行内部连接?