如何优化一对多关系模型的嵌套循环查询

问题描述 投票:0回答:1

我有两个具有一对多关系的模型。数据库中每个模型类都有多个对象。我创建了一个自定义查询集,它迭代所有父对象和所有子对象,然后将它们加载到字典中,然后将其用作查询集。

我的问题是如何优化nested_query_loop函数以减少访问数据库的次数?我尝试合并 select_lated() 和 prefetch_lated() 但永远无法让它工作,因为我需要将其作为向后关系进行查询,以便让每个子对象与其父对象在一起。

问题的第二部分:我尝试通过创建parent_object和child_object参数使函数可重用,但这不起作用,因为我必须使用ObjectName_set()方法,该方法要求对象名称小写。此外,ObjectName_set() 有一个下划线,因此 child_object_set() 甚至 ChildObject_set() 无法识别并引发错误。在我的例子中,子对象模型名称的首字母大写。所以我的问题是:有什么方法可以将函数内的模型名称全部小写吗?或者解决这个问题的唯一方法是将源中的模型名称更改为小写?或者甚至更好的问题:是否有一个我没有看到的 django 类或函数可以为我完成所有这一切?我不想重新发明轮子并让事情变得更糟。

请参阅下面的模型和视图。 view Models

'''蟒蛇

class MasterListView(ListView):
    template_name = 'passdown/master_list.html'
    context_object_name = 'entries'

    def nested_query_loop(self):
        object_list = []
        all_objects = PassDown.objects.all() #queryset containing all passdown objects
        for object in all_objects:
            object_list.append(object.pk) #list containing all passdown primary keys (object_list)

        query_dict={}
        for i in object_list:
            temp_obj = PassDown.objects.get(pk=i) #ith passdown object itself
            sub_object_pk_list=[]
            all_i_entries = temp_obj.entry_set.all() #queryset containing all entry objects of i
            for j in all_i_entries:
                sub_object_pk_list.append(j.pk) #list containing all entry primary keys of i (sub_object_pk_list)
                
            sub_object_list = []
            for k in sub_object_pk_list:
                sub_object_list.append(all_i_entries.get(pk=k)) #list containing all ith entry objects (sub_object_list)
            query_dict.__setitem__(temp_obj, sub_object_list)

        return query_dict

    def get_queryset(self):
        queryset = PassDown.objects.all()
        return queryset
    
    def get_context_data(self, **kwargs):
        context = super(MasterListView, self).get_context_data(**kwargs)
        queryset = self.nested_query_loop()
        context.update({
            "parent_child_dict": queryset
        })
        return context

'''

'''蟒蛇

class PassDown(models.Model):
    shiftList = [("Days", "Days"),
                 ("Nights", "Nights"),
                 ("Mids", "Mids")]
    shift = models.CharField(max_length=10, choices=shiftList)
    date_time = models.DateTimeField(default=timezone.now)
    notes = models.TextField()
    entered_by = models.ForeignKey(User, on_delete=models.DO_NOTHING)
    #entry = models.ForeignKey(Entry, on_delete=models.DO_NOTHING)

    def __str__(self):
        return f"{self.shift} {self.date_time}"

class Entry(models.Model):
    modex = models.IntegerField()
    discrepancy = models.CharField(max_length=50)
    text_body = models.TextField()
    passdown = models.ForeignKey(PassDown, on_delete=models.CASCADE, default=PassDown.objects.last)

    def __str__(self):
        return f"{self.modex} {self.discrepancy} {self.passdown.date_time}"

'''

django postgresql django-models orm django-queryset
1个回答
0
投票

我不明白你的代码和下面的代码之间的区别

def nested_query_loop(self):
        passdowns =  PassDown.objects.all()
        return {passdown: passdown.entry_set.all() for passdown in passdowns}

如果我没有错过任何事情的话。您可以使用简单的预取将查询数量减少到两次。

def nested_query_loop(self):
        passdowns =  PassDown.objects.prefetch_related("entry_set")
        return {passdown: passdown.entry_set.all() for passdown in passdowns}

但是我不知道你的字典可以用来做什么,因为你可以在模板中调用 related_manager 。

这是经典列表视图的样子

class MasterListView(ListView):
    model PassDown
    template_name = 'passdown/master_list.html'
    context_object_name = 'passdowns'

    def get_queryset(self):
        # Only define for performance reasons
        queryset = super().get_queryset()
        queryset = queryset.prefetch("entry_set")
        return queryset
{{ for passdown in passdowns }}
  # Render your passdown object
  {{ for entry in passdown.entry_set.all }}
    # Render your related entry
© www.soinside.com 2019 - 2023. All rights reserved.