Django原始查询在所有模型上给出相同的结果

时间:2019-06-01 11:09:25

标签: django django-models django-orm

我有3个模型Product, Photo, and ProductLikeDilike。我正在所有3个模型上执行左外部联接。首先,我将ProductPhoto连接在一起,然后将结果表(temp)与ProductLikeDilike连接在一起。下面是原始sql。

注意olx是Django应用的名称。

data = Product.objects.raw('select * from (select 
    olx_product.id,olx_product.name,olx_photo.file,olx_photo.cover_photo_flag 
    from olx_product left outer join olx_photo on 
    (olx_product.id=olx_photo.reference_id_id) where 
    olx_photo.cover_photo_flag="yes" or olx_photo.cover_photo_flag is null) as 
    temp left outer join olx_productlikedislike on 
    (temp.id=olx_productlikedislike.product_id_id and 
    olx_productlikedislike.product_liked_by_id_id=2)')

for x in data:
  print(x.name)

我想了解的是,当我使用上述3种模型中的任何一种来运行原始sql时,为什么得到相同的结果,即

当我这样做

data = Product.objects.raw('select *.....')
for x in data:
  print(x.name)

data = Photo.objects.raw('select *......') 
for x in data:
  print(x.name)

data = ProductLikeDislike.raw('select *.....')
for x in data:
  print(x.name)

我得到相同的结果。为什么? 请帮助我理解这一点。

下面是models.py文件

from django.db import models
from django.urls import reverse
from django.dispatch import receiver
from django.contrib.auth.models import User



    class Product(models.Model):
        category = models.ForeignKey(Category ,on_delete=models.CASCADE)
        name = models.CharField(max_length = 200, db_index = True)
        slug = models.SlugField(max_length = 200, db_index = True)     
        description = models.TextField(blank = True)    
        price = models.DecimalField(max_digits = 10, decimal_places = 2 )#Not used FloatField to avoid rounding issues
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)

        contact= models.BigIntegerField(default=None,blank=True, null=True)
        created_by = models.CharField(max_length = 200, default=None,blank=True, null=True)
        uploaded_by_id = models.IntegerField(default=0)
        status = models.IntegerField(default=0) # 0-->Active,1-->Inactive
        mark_as_sold = models.IntegerField(default=0) # 0-->not sold,1-->sold

        def get_absolute_url(self):
            return reverse('olx:edit_product', kwargs={'pk': self.pk})



        class Meta:
            ordering = ('-created',)
            index_together = (('id','slug'),)# we want to query product by id and slug using together index to improve performance

        def __str__(self):
            return self.name


    class Photo(models.Model):

        reference_id = models.ForeignKey(Product, null=True,on_delete=models.CASCADE) 
        photo_type = models.CharField(max_length = 70, db_index = True)
        file = models.FileField(upload_to='photos/',default='NoImage.jpg')
        cover_photo_flag = models.CharField(default=0,max_length = 5, db_index = True)
        uploaded_at = models.DateTimeField(auto_now_add=True)
        uploaded_by_id = models.IntegerField(default=0)
        status = models.IntegerField(default=0) # 0-->Active,1-->Inactive



        class Meta:
            ordering = ('-uploaded_at',)


    class ProductLikeDislike(models.Model):
        product_id = models.ForeignKey(Product,models.SET_DEFAULT,default=0) 
        product_liked_by_id = models.ForeignKey(User,models.SET_DEFAULT,default=0) 
        status = models.BooleanField(default=False)

如果可能的话,还请教我如何用纯Django方式编写它?

2 个答案:

答案 0 :(得分:0)

类似这样的东西:

    user_i_care_about = User.objects.get(username='user2')
    productlikedislike_set = models.Prefetch('productlikedislike_set',
                                             ProductLikeDislike.objects.select_related('user') \
                                                               .filter(user=user_i_care_about).order_by('id'))
    photo_set = models.Prefetch('photo_set', Photo.objects.order_by('id'))

    products = Product.objects.prefetch_related(photo_set, productlikedislike_set) \
                              .filter(models.Q(photo__cover_photo_flag=True) | models.Q(photo__isnull=True)) \
                              .filter(productlikedislike__user=user_i_care_about, productlikedislike__like=True)

然后您可以使用:

for product in products:
    for pic in product.photo_set.all():
        print(x.name)

如果您的模型看起来像这样:

class Product(models.Model):
    name = models.CharField(max_length=50)

class Photo(models.Model):
    cover_photo_flag = models.BooleanField()
    name = models.CharField(max_length=50)
    product = models.ForeignKey(Product, db_column='reference_id', on_delete=models.CASCADE)

class ProductLikeDislike(models.Model):
    product = models.ForeignKey(Product, db_column='product_id', on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    like = models.BooleanField()

完整的WITH测试示例可以在此处查看:https://gist.github.com/kingbuzzman/05ed095d8f48c3904e217e56235af54a

答案 1 :(得分:0)

  

我得到相同的结果。为什么?请帮助我理解这一点。

因为.raw(..) [Django-doc]仅接受原始查询并执行它。执行原始操作的模型无关紧要。

我们可以生成如下查询:

from django.db.models import Q

Product.objects.filter(
    Q(photo__photo_flag__isnull=True) | Q(photo__photo_flag='yes'),
    Q(likedislike__product_liked_by_id_id=2)
)

因此,在这里,我们接受所有Product的相关Photo对象具有flag的{​​{1}}(如果JOIN不产生任何标记),或者NULLphoto_flag)。此外,应该有一个'yes'Likedislike的{​​{1}}对象。

请注意,通常ForeignKey [Django-doc]的后缀为 no liked_by_id_id或前缀2。为此设置一个_id也有点“奇怪”,特别是因为大多数数据库仅将严格个正值分配为主键,并且固有地偏爱{{ 1}}仍然在另一个对象上。