如何过滤相关对象?

时间:2012-12-22 22:28:40

标签: django django-models django-orm

我有两种模式:

class Game(models.Model):
    title = models.CharField(max_length='255', blank=False, db_index=True)

class GameImage(models.Model):

    TYPES = (
        ('small_image', 'Small Image'),
        ('medium_image', 'Medium Image'),
        ('feature_image', 'Feature Image'),
        ('subfeature_image', 'Sub-feature Image'),
        ('sc1', 'Screenshot 1'),
        ('sc2', 'Screenshot 2'),
        ('sc3', 'Screenshot 3'),
    )

    game = models.ForeignKey("Game", related_name="images", editable=False)
    image = ImageField(upload_to=gameimage_storage_path, max_length=255)
    type = models.CharField(max_length=16, choices=TYPES, db_index=True)

如果我这样做

games = Games.objects.prefetch_related('images').all()

如果我这样做,它将附加所有“图像”相关对象:

games = Games.objects.prefetch_related('images').filter(images__type__contains='small_image').all()

它将显示具有'small_image'类型图像的游戏,但仍将加载与游戏相关的所有GameImage对象。

如何加载游戏列表,其中每个游戏都只有类型为''small_image'的GameImages相关对象(它不会加载与游戏相关的其他GameImage对象)?我可以通过原始sql执行此操作,但如何通过Django ORM执行此操作?请帮忙。

更新 这是我想通过ORM实现的SQL查询:

SELECT * FROM game g LEFT JOIN gameimage i ON g.id = i.game_id AND i.type = 'small_image';

2 个答案:

答案 0 :(得分:1)

加入

GameImage.objects.filter(img_type='small_image').select_related('game')

左加入游戏

from django.db.models import Q

GameImage.objects.filter(
    Q(img_type='small_image') | 
    Q(game__isnull=True)
).select_related('game')

左连接游戏图像

Game.objects.filter(
    Q(images__img_type='small_image') |
    Q(id__isnull=True)
).select_related('images')

答案 1 :(得分:0)

所以你想要所有游戏,但想要在不加载额外相关图像的情况下检查游戏是否有small_image:

models.py:

from django.core.exceptions import ObjectDoesNotExist

Class Game(models.Model):
    title = models.CharField(max_length='255', blank=False, db_index=True)

    def get_small_image(self):
        try:
            return self.images.get(type='small_image')
        except ObjectDoesNotExist:
            return None

views.py:

games = Game.objects.all()
for game in games:
    small_image = game.get_small_image()
    if small_image:
        print small_image.image.url
    else:
        print 'there is no small image for this game'