2013-06-26 4 views
3

Я пытаюсь отобразить форму с комбо, которая показывает связанные объекты. Поэтому я использую ModelChoiceField.Django: Как использовать django.forms.ModelChoiceField с сырым SQL-запросом?

Этот подход работает хорошо, пока мне не нужно было ограничивать, какие объекты показывать. Если я использую простое выражение запроса, оно также работает хорошо, но все происходит, если я использую необработанный SQL-запрос.

Так что мой код, который работает, устанавливает запрос в выражение фильтра.

class ReservationForm(forms.Form): 
    location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time") 

def __init__(self,*args,**kwargs): 
    city_id = kwargs.pop("city_id")  # client is the parameter passed from views.py 
    super(ReservationForm, self).__init__(*args,**kwargs) 

    # TODO: move this to a manager   
    self.fields['location_time_slot'].queryset = LocationTimeSlot.objects.filter(city__id = city_id) 

НО, если я изменю это на необработанный запрос, у меня возникают проблемы. Код, который не работает:

class ReservationForm(forms.Form): 
     location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time") 

    def __init__(self,*args,**kwargs): 
     city_id = kwargs.pop("city_id")  # client is the parameter passed from views.py 
     super(ReservationForm, self).__init__(*args,**kwargs) 

     # TODO: move this to a manager   
     query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order' 
    FROM reservations_locationtimeslot AS ts 
    INNER JOIN reservations_location AS l ON l.id = ts.location_id 
    WHERE l.city_id = %s  
    AND ts.available_reserves > 0 
    AND ts.datetime_from > datetime() """ 

    time_slots = LocationTimeSlot.objects.raw(query, [city_id]) 

    self.fields['location_time_slot'].queryset = time_slots 

Первая ошибка я получаю при попытке визуализации виджета: объект «RawQuerySet» не имеет атрибута «все»

я мог бы решить, что один благодаря одному из commets в enter link description here, поступая:

time_slots.all = time_slots.__iter__ # Dummy fix to allow default form rendering with raw SQL 

Но теперь я получаю что-то подобное, отправляя форму: объект «RawQuerySet» не имеет атрибута «получить»

Есть ли способ подготовить RawQuerySet для использования ModelChoiceField?

Спасибо!

ответ

1

Вы уверены, что вам действительно нужен необработанный запрос? Просто глядя на этот запрос, я не вижу причин, по которым вы не можете просто сделать это с помощью filter(location__city=city_id, available_reserves__gte=0, datetime_from__gt=datetime.datetime.now()).

В наборах необработанных запросов отсутствует ряд методов, которые определены на обычных наборах запросов, поэтому просто отказаться от них не удастся, не создавая собственных определений для всех этих методов.

+0

Да, я отправил по упрощенному запросу. Один из них в производстве намного сложнее и ожидается, что он вырастет :-( Итак, в заключение вы говорите, что ModelChoiceField от Symfony не готов использовать RawQuerySets? – MAB

+1

«ModelChoiceField» не настроен на использование набора необработанных запросов, если вы не заполнили необходимые методы, нет. В зависимости от вашей ситуации было бы полезно объявить представление в вашей базе данных, а затем создать неуправляемую модель в Django для ее представления. Вам нужно будет выполнить дополнительную работу, чтобы преобразовать выбранную запись вида обратно в реальный экземпляр модели, но это не должно быть слишком сложно, так как вы можете держать ПК одинаковыми. –

0

Я временно исправил проблему с добавлением недостающих методов. Способ, которым я в настоящее время использую ModelChoiceField Мне нужно только добавить методы all() и get(), но в разных сценариях вам может понадобиться добавить и другие методы. Также это не идеальное решение, потому что: 1) Определяя метод get таким образом, migth производит неверные результаты. Я думаю, метод get() используется для проверки того, что выбранная опция находится в пределах параметров, возвращаемых функцией all(). Способ, которым я временно выполнял это, только подтверждает, что идентификатор существует в таблице. 2) Я предполагаю, что метод get менее эффективен, указанный таким образом.

Если кто-нибудь может подумать о лучшем решении, пожалуйста, дайте мне знать.

Так что мое временное решение:

class LocationTimeSlotManager(models.Manager): 
    def availableSlots(self, city_id): 
     query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order' 
      FROM reservations_locationtimeslot AS ts 
      ..... 
      ..... 
      MORE SQL """ 

     time_slots = LocationTimeSlot.objects.raw(query, [city_id]) 

     # Dummy fix to allow default form rendering with raw SQL 
     time_slots.all = time_slots.__iter__ 
     time_slots.get = LocationTimeSlot.objects.get 

     return time_slots