Django QuerySet在SELECT语句中包含更多列

0 投票
2 回答
1642 浏览
提问于 2025-04-16 17:00

我一直在尝试使用查询集(queryset)创建一个反向关系,连接的部分工作得很好,但就是没有把其他连接的表包含在选定的列中。下面是我的模型、查询集和查询的str()打印结果。

class Main(models.Model):
    slug       = models.SlugField()
    is_active  = models.BooleanField(default=True)
    site       = models.ForeignKey(Site)
    parent     = models.ForeignKey('self', blank=True, null=True, limit_choices_to={'parent' : None})
    class Meta:
        unique_together = (("slug", "parent"))
    def __unicode__(self):
        return self.slug

class MainI18n(models.Model):
    main                = models.ForeignKey(Main)
    language            = models.CharField(max_length=2, choices=settings.LANGUAGES)
    title               = models.CharField(max_length=100)
    label               = models.CharField(max_length=200, blank=True, null=True)
    description         = models.TextField(blank=True, null=True)
    disclaimer          = models.TextField(blank=True, null=True)
    class Meta:
        unique_together = (("language", "main"))
    def __unicode__(self):
        return self.title
class List(models.Model):
    main        = models.ForeignKey(Main)
    slug        = models.SlugField(unique=True)
    is_active   = models.BooleanField(default=True)
    parent      = models.ForeignKey('self', blank=True, null=True)

    def __unicode__(self):
        return self.slug
class ListI18n(models.Model):
    list        = models.ForeignKey(List)
    language    = models.CharField(max_length=2, choices=settings.LANGUAGES)
    title       = models.CharField(max_length=50)
    description = models.TextField()
    class Meta:
        unique_together = (("language", "list"))
    def __unicode__(self):
        return self.title

我的查询集是

Main.objects.select_related('main', 'parent').filter(list__is_active=True, maini18n__language='en', list__listi18n__language='en')

这是我的查询打印的结果

'SELECT `category_main`.`id`, `category_main`.`slug`, `category_main`.`is_active`, `category_main`.`site_id`, `category_main`.`parent_id`, T5.`id`, T5.`slug`, T5.`is_active`, T5.`site_id`, T5.`parent_id` FROM `category_main` INNER JOIN `category_maini18n` ON (`category_main`.`id` = `category_maini18n`.`main_id`) INNER JOIN `category_list` ON (`category_main`.`id` = `category_list`.`main_id`) INNER JOIN `category_listi18n` ON (`category_list`.`id` = `category_listi18n`.`list_id`) LEFT OUTER JOIN `category_main` T5 ON (`category_main`.`parent_id` = T5.`id`) WHERE (`category_maini18n`.`language` = en  AND `category_list`.`is_active` = True  AND `category_listi18n`.`language` = en )'

有没有人能帮我显示来自 list 和 listi18n 的列?我尝试过 extra,但它不允许我像 category_list.* 这样传递内容。

谢谢!

更新

感谢 Daniel 的方法,我成功让它工作了,但我不得不从 ListI18n 开始。

ListI18n.objects.select_related('list', 'list__main', 'list__main__parent', 'list__main__i18nmain').filter(list__is_active=True, list__main__maini18n__language='en', language='en').query.__str__()

现在一切都运作得很好,但我无法包含 list_main_maini18n,下面是输出的查询结果。

'SELECT `category_listi18n`.`id`, `category_listi18n`.`list_id`, `category_listi18n`.`language`, `category_listi18n`.`title`, `category_listi18n`.`description`, `category_list`.`id`, `category_list`.`main_id`, `category_list`.`slug`, `category_list`.`is_active`, `category_list`.`parent_id`, `category_main`.`id`, `category_main`.`slug`, `category_main`.`is_active`, `category_main`.`site_id`, `category_main`.`parent_id`, T5.`id`, T5.`slug`, T5.`is_active`, T5.`site_id`, T5.`parent_id` FROM `category_listi18n` INNER JOIN `category_list` ON (`category_listi18n`.`list_id` = `category_list`.`id`) INNER JOIN `category_main` ON (`category_list`.`main_id` = `category_main`.`id`) INNER JOIN `category_maini18n` ON (`category_main`.`id` = `category_maini18n`.`main_id`) LEFT OUTER JOIN `category_main` T5 ON (`category_main`.`parent_id` = T5.`id`) WHERE (`category_list`.`is_active` = True  AND `category_listi18n`.`language` = en  AND `category_maini18n`.`language` = en )'

有没有什么办法可以把 MainI18n 包含在查询结果中?我应该使用 extra 并包含这些表,然后在 where 子句中做关系吗?还是有更好的方法?

2 个回答

0

在我看来,这实际上是可以工作的(你在选择语句中用到的T5)。在Django中,你总是可以通过类似my_obj.parent.is_active的方式访问相关实例的字段。如果你之前使用了select_related,那么这些字段会在第一次查询时就被包含进来。如果你没有在select_related中指定它,那么像my_obj.parent.is_active这样的调用就会额外进行一次数据库查询。

2

在这个例子中,Main和List之间的关系是一个反向的外键(也就是说,外键在List上指向Main)。而select_related这个功能并不适用于这种情况。想想看,这其实是对的:每个Main可以有很多个List,所以说“给我这个Main的一个List”是没有意义的,这正是select_related想要做的事情。

如果你从List开始,那就可以正常工作了:

List.objects.select_related('main__parent').filter(is_active=True, main__maini18n__language='en', listi18n__language='en')

因为那样你只是沿着正向的关系在查找。你可能会发现,可以调整你的视图或模板,以这种方式来使用查询。

撰写回答