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