Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to make a model search form?

I have this model:

class Aircraft(models.Model):
    model       =   models.CharField(max_length=64, blank=True)
    type        =   models.CharField(max_length=32)
    extra       =   models.CharField(max_length=32, blank=True)
    manufacturer    =   models.CharField(max_length=32)
    engine_type =   models.IntegerField("Engine Type", choices=ENGINE_TYPE, default=0)
    cat_class   =   models.IntegerField("Category/Class", choices=CAT_CLASSES, default=1)

And I have a "find aircraft" page where the user is presented with a form where they can enter data that will be used to find all aircraft that fits their criteria. For instance the user can enter "boeing" into a textbox and "jet" into the engine_type box, and it will display all boeing jets in the database. The way I'm doing this now is by this form:

class AircraftSearch(ModelForm):
    search = forms.CharField(max_length=100, required=False)
    class Meta:
        model = Aircraft
        fields = ('engine_type', 'cat_class', )

And then a (needlessly complex) view which converts the data from this form into a set of filter()'s which get added to Aircraft.objects.all(). (Instead of having 4 seperate search fields for each CharField, I have combined them all into one search field.)

This all works, but with one problem. If the user wants to exclude engine type from their search criteria, then they're screwed because "Any" is not a valid choice for the engine type field. I'm going to have to create a new field/widget for engine type and category/class to include "Any", which kind of defeats the purpose of using a model view in the first place

I'm curious. Is there a better way? This seems like a very common task which has to have been tackled by someone else already, but a google search brings up nothing.

like image 560
priestc Avatar asked Jul 10 '09 03:07

priestc


People also ask

What is a model form?

Model Forms are forms that are connected directly to models, allowing them to populate the form with data. It allows you to create a form from a pre-existing model. You add an inline class called Meta, which provides information connecting the model to the form. An inline class is a class within another class.

How do you make a model field required in Django?

Let's try to use required via Django Web application we created, visit http://localhost:8000/ and try to input the value based on option or validation applied on the Field. Hit submit. Hence Field is accepting the form even without any data in the geeks_field. This makes required=False implemented successfully.

What is ModelForm in Django?

Django Model Form It is a class which is used to create an HTML form by using the Model. It is an efficient way to create a form without writing HTML code. Django automatically does it for us to reduce the application development time.


2 Answers

Functionally, "any" would be achieved by just not including that particular search vector in the filtering.

Generally, ModelForms are for creating and editing models; in this case, I'm not sure it's helping you much more than just doing a regular form:

class AircraftSearch(forms.Form):
    search = forms.CharField(max_length=100, required=False)
    engine_type = forms.ChoiceField(choices=ENGINE_TYPE)
    cat_class = forms.ChoiceField(choices=CAT_CLASS)

To do the search, you then just filter when fields are non-empty:

def search(request):
    if request.method == 'POST':
        results = Aircraft.objects.all()

        search = request.POST.get('search', None)
        if search:
            results = results.filter(Q(model=search)|Q(type=search)|Q(extra=search)|Q(manufacturer=search))

        engine_type = request.POST.get('engine_type', None)
        if engine_type:
            results = results.filter(engine_type=engine_type)

        cat_class = request.POST.get('cat_class', None)
        if cat_class:
            results = results.filter(cat_class=cat_class)

        return render_to_response('aircraft.html', {'form': AircraftSearch(request.POST), 'aircraft': results})

    return render_to_response('aircraft.html', {'form': AircraftSearch()})
like image 158
tghw Avatar answered Nov 15 '22 05:11

tghw


I think you should not use a ModelForm.
Typical ModelForm usescase is data manipulation, and not its search.

Instead, make a completely new form, based on the fields you need and with checkboxes that user will (de-)select to disable searching a particular field.
Of course, you still should use the choices defined in the model, by simply importing the file and using that list.

like image 20
rob Avatar answered Nov 15 '22 04:11

rob