【问题标题】:How to make an Inner Join in django?如何在 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

【问题讨论】:

标签: python mysql django orm inner-join


【解决方案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 %}
      

      【讨论】:

      • 反向关系呢?
      猜你喜欢
      • 1970-01-01
      • 2019-03-22
      • 2011-03-18
      • 2016-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-06
      • 2020-06-27
      相关资源
      最近更新 更多