Django对关系进行递归调用

时间:2015-01-15 13:33:45

标签: python django django-models

我在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)

任何想法都可以做到这一点,而无需拨打数千个电话?

2 个答案:

答案 0 :(得分:1)

最后我这样做了:

在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次查询。有一些验证器和清洁等......但与解决方案并不真正相关。

答案 1 :(得分:0)

我可能误解了你的问题,但我认为我有类似的情况。在下拉列表中,您希望使用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