python怎样实现多表连接_python – Django views.py SQL连接多表查询的版...

好吧,那些是一些不清楚的表和字段名称,但最好我可以告诉该查询看起来像:

(Restaurant.objects.filter(city=8,

cuisine__cuisinetype__cuisine="Italian").distinct().order_by('name')[:20])

但除非您被锁定在该数据库架构中,否则您的模型看起来会更好:

class CuisineType(models.Model):

name = models.CharField(max_length=50)

class Meta:

db_table = 'cuisinetype'

class Restaurants(models.Model):

city = models.ForeignKey("City", null=True, blank=True) # Apparently defined elsewhere. Should be part of location?

name = models.CharField(max_length=50)

location = models.ForeignKey("Location", null=True, blank=True) # Apparently defined elsewhere.

cuisines = models.ManyToManyField(CuisineType)

然后查询更像是:

Restaurant.objects.filter(city=8, cuisines__name="Italian").order_by('name')[:20]

好的,假设您的代码没有任何更改,让我们一起浏览您的查询.我们将从子查询开始.

SELECT DISTINCT res_id FROM cuisine

JOIN cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`

WHERE cuisinetype.`cuisine` = 'Italian'

我们查看WHERE子句,看看我们需要一个JOIN.要进行连接,必须在其中一个连接的模型中声明一个关系字段(Django将添加一个反向关系,我们应该命名).因此我们将cuisine.cuisineid与`cuisinetype.cuisineid相匹配.这是一个可怕的命名.

这是一个多对多的关系,所以我们需要一个ManyToManyField.那么,看看烹饪模型,它真的是这个M2M的加入表. Django希望连接表有两个ForeignKey字段,一个指向关节的每一边.通常它会为你创造这个以节省理智.显然你不是那么幸运.所以你必须手动连接它.

似乎“GID”字段是记录的(无用的)ID字段,所以让我们假设它是自动增量整数. (当然,请检查CREATE TABLE命令.)现在我们可以将Cuisine模型重写为接近理智的东西:

class Cuisine(models.Model):

cuisinegid = models.AutoField(primary_key=True, db_column='CuisineGID')

cuisineid = models.ForeignKey("Cuisinetype", null=True,

db_column='CuisineID', blank=True)

res_id = models.ForeignKey("Restaurant", null=True, db_column='Res_ID',

blank=True)

class Meta:

db_table = 'cuisine'

引用模型名称是因为模型尚未定义(它们稍后在文件中).现在不要求Django字段名称与列名匹配,所以让我们将它们更改为更具可读性的东西.记录ID字段通常只是id,而外键通常以它们的相关名称命名:

class Cuisine(models.Model):

id = models.AutoField(primary_key=True, db_column='CuisineGID')

cuisine_type = models.ForeignKey("CuisineType", null=True,

db_column='CuisineID', blank=True)

restaurant = models.ForeignKey("Restaurant", null=True, db_column='Res_ID',

blank=True)

class Meta:

db_table = 'cuisine'

好的,我们已经完成了我们的联合表的定义.当我们在这里时,让我们将相同的东西应用到我们的Cuisinetype模型中.请注意更正的驼峰案例类名称:

class CuisineType(models.Model):

id = models.AutoField(primary_key=True, db_column='CuisineID')

name = models.CharField(max_length=50, db_column='Cuisine', blank=True)

class Meta:

db_table = 'cuisinetype'

所以我们终于到了我们的餐厅模型.请注意,名称是单数;一个对象只代表一条记录.

我注意到它缺少任何dp_table或db_column的东西,所以我出去了,并猜测Django正在创建它.这意味着我们可以让它为我们创建id字段,我们可以从代码中省略它. (如果不是这样,那么我们就像其他模型一样添加它.但是你真的不应该有一个可以为空的记录ID.)这就是我们的菜肴类型ManyToManyField所在的地方:

class Restaurants(models.Model):

city_id = models.ForeignKey(null=True, blank=True)

name = models.CharField(max_length=50, blank=True)

location = models.ForeignKey(null=True, blank=True)

cuisine_types = models.ManyToManyField(CuisineType, through=Cuisine,

null=True, blank=True)

注意,M2M字段的名称是复数,因为该关系导致多个记录.

我们想要添加到此模型的另一件事是反向关系的名称.换句话说,如何从其他车型回到餐厅.我们通过添加related_name参数来完成此操作.他们是一样的并不罕见.

class Restaurant(models.Model):

city_id = models.ForeignKey(null=True, blank=True,

related_name="restaurants")

name = models.CharField(max_length=50, blank=True)

location = models.ForeignKey(null=True, blank=True,

related_name="restaurants")

cuisine_types = models.ManyToManyField(CuisineType, through=Cuisine,

null=True, blank=True, related_name="restaurants")

现在我们终于确定了.那么让我们来看看你的查询:

SELECT restaurants.`name`, restaurants.`address`, cuisinetype.`cuisine`

FROM restaurants

JOIN cuisinetype ON cuisinetype.cuisineid = restaurants.`cuisine`

WHERE city_id = 8 AND restaurants.id IN (

SELECT DISTINCT res_id FROM cuisine

JOIN cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`

WHERE cuisinetype.`cuisine` = 'Italian')

ORDER BY restaurants.`name`

LIMIT 20

由于这是FROM餐馆,我们将从该模型的默认对象管理器开始,对象:

Restaurant.objects

在这种情况下,WHERE子句是一个filter()调用,所以我们为第一个术语添加它:

Restaurant.objects.filter(city=8)

您可以在该术语的右侧使主键值或City对象枯萎.但是,查询的其余部分会变得更复杂,因为它需要JOIN. Django中的连接看起来像通过关系字段解除引用.在查询中,这意味着使用双下划线连接相关的字段名称:

Restaurant.objects.filter(city=8, cuisine_type__name="Italian")

Django知道要加入哪些字段,因为它在Cuisine表中声明,这是由cuisine_types中的through = Cuisine参数引入的.它也知道做一个子查询,因为你正在经历一个M2M关系.

这样我们的SQL就等同于:

SELECT restaurants.`name`, restaurants.`address`

FROM restaurants

WHERE city_id = 8 AND restaurants.id IN (

SELECT res_id FROM cuisine

JOIN cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`

WHERE cuisinetype.`cuisine` = 'Italian')

中途那里.现在我们需要SELECT DISTINCT,因此我们不会获得同一记录的多个副本:

Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()

而且您需要提供美食类型以供展示.事实证明,您所拥有的查询效率低下,因为它只会将您带到连接表,您需要运行更多查询以获取相关的CuisineType记录.猜猜看:Django让你满意.

(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()

.prefetch_related("cuisine_types"))

Django将运行两个查询:一个像你一样获取联合ID,另一个查询获取相关的CuisineType记录.然后通过查询结果访问不需要返回数据库.

最后两件事是订购:

(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()

.prefetch_related("cuisine_types").order_by("name"))

和LIMIT:

(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()

.prefetch_related("cuisine_types").order_by("name")[:20])

并且您的查询(以及相关查询)被打包成两行Python.请注意,此时查询尚未执行.在做任何事情之前,你必须把它放在像模板这样的东西上:

def cuisinesearch(request, cuisine):

return render_to_response('cuisinesearch.html', {

'restaurants': (Restaurant.objects.filter(city=8,

cuisine_type__name="Italian").distinct()

.prefetch_related("cuisine_types").order_by("name")[:20])

})

模板:

{% for restaurant in cuisinesearch %}

{{ restaurant.name }}

{{ restaurant.location }}

Cuisines:

  • {% for ct in restaurant.cuisine_types.all %}
  • {{ ct.name }}{% endfor %}

{% endfor %}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值