3

Taking a classic foo bar example:

In models.py:

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

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

In my form, I tried to limit the choices of my foreignkey to Foo to a subset of Foo using a raw query.

In forms.py:

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.fields['foo'].queryset = Bar.objects.raw("""
select f.id as id, f.name as name from bar_lookup(%s)""", [search_str])

    class Meta:
        model = Bar
        exclude = ('foo',)

bar_lookup(%s) is a DB procedure returning a table. It searches multiple relations and handles the filtering and sorting of the results in an optimized way. It works and I would rather not have to code it again in Django code.

I get the following error: "'RawQuerySet' object has no attribute 'all'". The form works if I use a normal Bar.objects.filter() instead.

How should I transform my RawQuerySet into a normal QuerySet? Should I use the self.fields['line_stop'].choice option?

Sicco
  • 6,167
  • 5
  • 45
  • 61

1 Answers1

1

I had a similar problem and come with that tricky solution:

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("Some error!")
        return foo

    class Meta:
        model = Bar

An I know it is not perfect, and subclassing ModelChoiceField would be better.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
jasisz
  • 1,288
  • 8
  • 9