Django 对关系进行递归调用

Django making recursive calls on relationship

我在 Django 1.6.5 上有以下模型

class Location(models.Model):
    parent = models.ForeignKey('Location', blank=True, null=True)
    name = models.CharField(max_length=50)

    class Meta:
        db_table = 'locations'
        ordering = ('parent__name', 'name')

    def __unicode__(self, ):
        if self.parent!= None:
            return self.name + " (" + self.parent.name +  ")"
        else:
            return self.name        

我在下拉列表中列出了这些位置,所以我想显示名称 +(parent.name 如果可用)

知道如何在无需进行数千次调用的情况下执行此操作吗?

最后我这样做了:

在forms.py我创建了一个方法:

def get_locations_with_parents():
    location_list = [(0,'Select One ...')]
    locations = Position.objects.raw('select l.id, l.name, p.name as parent from locations l left join locations p on l.parent_id = p.id order by parent, l.name')
    for l in locations:
        if l.parent:
            location = (int(l.id), l.name + " (" + l.parent + ")")
        else:
            location = (int(l.id), l.name)

        location_list.append(location)

    return tuple(location_list)

然后以我使用的形式 locations = forms.ChoiceField(choices=get_locations_with_parents(), validators=[validate_empty])

它成功了,不再对数据库执行 2000 次查询。有一些验证器和清洁器等等......但与解决方案并不真正相关。

我可能误解了你的问题,但我想我也有类似的情况。在下拉列表中,您希望使用 location 的名称标记对象。如果该位置有 parent,您希望在位置名称后的括号内显示该父项的名称。

您可以通过覆盖 ModelForm 的 __init__ 方法来完成此操作:

def __init__(self, *args, **kwargs):
    def new_label_from_instance(self, obj):
        try:
            #see if there is a parent or not
            p = obj.parent 
        except:   
            #no parent; use the location's default label
            rep = obj.description
            return rep
        #if we find a location's parent, p=parent label and d=location label
        d = obj.description
        rep = "%s (%s)" % (d, p)
        return rep

    super(PublisherCreateTSCForm, self).__init__(*args, **kwargs)
    funcType = type(self.fields['location'].label_from_instance)
    self.fields['location'].label_from_instance = funcType(new_label_from_instance, self.fields['location'], forms.models.ChoiceField)

在你做之前你应该知道这样做的后果。看看这个老问题:

Django CheckboxSelectMultiple override 'choices' from ModelForm

以及此处与 label_from_instance 相关的文档(链接部分的底部):https://docs.djangoproject.com/en/1.7/ref/forms/fields/#modelchoicefield