2015-01-15 2 views
0

У меня есть следующая модель на Django 1.6.5Django делает рекурсивные вызовы на отношения

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 если доступно)

Любая идея hwo сделать это без необходимости делать тысячи звонков?

+3

Вы, наверное, хотите посмотреть на что-то вроде [Джанго-mptt] (HTTP: //django-mptt.github.io/django-mptt/), который позволяет вам делать эти запросы очень эффективно. –

+0

Давай, должен другой способ использовать стороннюю библиотеку. Это самая распространенная вещь в мире. – Fabiot

+1

Невозможно сделать это, если вы придерживаетесь иерархического хранения данных дерева в sql. Вы должны посмотреть в Nested Sets http://en.wikipedia.org/wiki/Nested_set_model моделей Materialized Path. django-mptt делает оба, насколько я помню – teferi

ответ

0

Возможно, я не понимаю ваш вопрос, но я думаю, что у меня подобная ситуация. В выпадающем меню вы хотите, чтобы объект был помечен именем location. Если для этого местоположения есть parent, вы должны указать имя этого родителя, а также в круглых скобках, следующих за именем местоположения.

Вы можете сделать это путем переопределения __init__ метод вашего ModelForm:

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

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) 

, а затем в форме я использую местоположения = forms.ChoiceField (по выбору = get_locations_with_parents(), validators = [validate_empty])

Это трюк, и он больше не делает 2000 запросов к БД. Есть некоторые валидаторы, чистые и так ... но на самом деле не имеют отношения к решению.

Смежные вопросы