3 Stimmen

Django: Verwendung einer Rohabfrage, um die Auswahlmöglichkeiten eines Fremdschlüssel-ChoiceField in einem ModelForm zu begrenzen

Eine klassische Foo-Bar-Beispiel:

In models.py:

Klasse Foo(models.Model):
    name = models.CharField(max_length= 200)

Klasse Bar(models.Model):
    name = models.CharField(max_length= 200)
    foo = models.ForeignKey('Foo')

In meinem Formular habe ich versucht, die Auswahl meiner fremdtaste auf eine Teilmenge von Foo mittels einer Rohabfrage zu begrenzen.

In forms.py:

Klasse BarForm(ModelForm):
    Suchfeld = CharField(max_length=100, erforderlich=False)

    def __init__(self,*args,**kwargs):
        Such_str = kwargs.pop('Such_str', None)
        super(BarForm,self ).__init__(*args,**kwargs)
        self.fields['Suchfeld'].initial = Such_str
        self.fields['foo'].queryset = Bar.objects.raw("""
select f.id as id, f.name as name from bar_lookup(%s)""", [Such_str])

    Klasse Meta:
        modell = Bar
        ausschließen = ('foo',)

bar_lookup(%s) ist ein DB-Verfahren, das eine Tabelle zurückgibt. Es sucht nach mehreren Beziehungen und behandelt die Filterung und Sortierung der Ergebnisse auf optimierte Weise. Es funktioniert und ich würde es lieber nicht wieder im Django-Code schreiben müssen.

Ich erhalte den folgenden Fehler: "'RawQuerySet' object has no attribute 'all'". Das Formular funktioniert, wenn ich stattdessen ein normales Bar.objects.filter() verwende.

Wie sollte ich mein RawQuerySet in ein normales QuerySet umwandeln? Sollte ich die Option self.fields['line_stop'].choice verwenden?

1voto

jasisz Punkte 1288

Ich hatte ein ähnliches Problem und kam auf diese knifflige Lösung:

class BarForm(ModelForm):
    search_field = CharField(max_length=100, required=False)

    def __init__(self,*args,**kwargs):
        search_str = kwargs.pop('search_str', None)
        super(BarForm,self ).__init__(*args,**kwargs)
        self.fields['search_field'].initial = search_str
        self.foo_choices = Bar.objects.raw("""
              select f.id as id, f.name as name from bar_lookup(%s)""", [search_str])
        self.fields['foo'].choices = [(x.id, x) for x in self.foo_choices]

    def clean_foo(self):
        foo = self.cleaned_data['foo']
        if foo not in self.foo_choices:
             raise forms.ValidationError("Ein Fehler ist aufgetreten!")
        return foo

    class Meta:
        model = Bar

Und ich weiß, dass es nicht perfekt ist und es besser wäre, ModelChoiceField zu unterklassen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X