Django form for querying database. Is form.py needed and how to leave fields empty for query?

296 views Asked by At

I would like to have an input form where a user inputs either an incident_id or a equipment_id or both. The problem I have now is for example, if I fill in incident_id and leave equipment_id blank, the query will return no hits even when incident_id finds a match, because my query uses blank equipment_id in the search. How can I set it up so that when I leave a field blank, it doesn't use it in the query? Do I need to validate this data? I'm not inserting any of it into the db.

I know Django forms uses POST, but in this instance I feel that GET is more appropriate, which means I don't have to use Django forms, but does that mean I also don't have to validate the data? Or should I just use POST anyway and validate that data with Django forms? I'm sorry this is so conceptual. I'm not finding many good answers online.

model.py

from django.db import models

class Incident(models.Model):
incident_id = models.CharField(max_length=1000, blank=True)
equipment_id = models.ForeignKey(Equipment, blank=True)

class Equipment(models.Model):
        equipment_id = models.CharField(primary_key=True, max_length=100)
        manufacturer = models.ForeignKey(Manufacturer)
        equipment_category = models.ForeignKey(Equipment_Category)
        validated= models.BooleanField(default=True)
        in_service_date = models.DateTimeField('in service date', default=timezone.now)

view.py

@login_required
def search_incidents_query(request):

            if request.method == 'GET':

                            incident_id_query = request.GET.get('incident_id')
                            equipment_id_query = request.GET.get('equipment_id')

                            try:
                                            incident_id = str(incident_id_query)
                            except ValueError:
                                            incident_id = None
                            try:
                                            equipment_id = str(equipment_id_query)
                            except ValueError:
                                            username = None

                            list = [incident_id,equipment_id]

                            if all(x is None for x in list): #check if `list` contains only None
                                            incident_list = None #this in case the query comes back empty
                            else: #perform query

                                            incident_list = Incident.objects.filter(incident_id=incident_id, equipment_id=equipment_id)
                                                                                                                            )                              
                            return render(request, 'search_incidents_query.html', { 
                                            'incident_list' : incident_list
                            })

search_incidents_query.html

{% extends "base.html" %}
{% load widget_tweaks %}

{% block content %}
<br>

<div class="container-fluid">

    <!-----INPUT FORM------------------->
    <form method='GET' action='/search_incidents/'>
        <div class="row">   
            <div class="form-group col-md-3">
                <label>Incident ID</label>
                <input type="text" name="incident_id" value="{{ incident_id_query }}" class="form-control"/>
            </div>              
            <div class="form-group col-md-3">               
                <label>Equipment ID</label>
                <input type="text" name="equipment" value="{{ equipment_id_query }}" class="form-control"/>
            </div>
        </div>
    </form>
</div>
{% endblock %}
1

There are 1 answers

3
Anas On BEST ANSWER

The query

You should use a Q object for similar queries.

from django.db.models import Q 

Incident.objects.filter(
     Q(incident_id=incident_id) | Q(equipment_id=equipment_id)
)

More on Q objects.

Also, IMO this code needs to live in some Form class. If it was me, I would have put this code in some

The form

class IncidentSearchForm(forms.Form):
    incident = forms.CharField(required=False)
    # ModelChoiceField because we want django to do the validation for us
    # TextInput because the default widget is a select tag
    equipment = forms.ModelChoiceField(Equipment.objects.all(), required=False, widget=forms.TextInput)  # TextInput because

    def clean(self):
         # I'd use the clean method to force the user to provide either an incident or equipment value

    def search(self):
        return Incident.objects.filter(
              Q(incident_id=self.cleaned_data['incident']) | 
              Q(equipment_id=self.cleaned_data['equipment'])
        )

The view

  • Why aren't you using Class Based Views already?
  • username = None. Wat?

You should use a form because never trust user input.

@login_required
def search_incidents_query(request):
    form = IncidentSearchForm(request.GET or None)
    incident_list = None     
    if 'equipment' in request.GET or 'incident' in request.GET:
         incident_list = None  # Or maybe Incident.objects.none()  
         if form.is_valid():
            incident_list = form.search()

    return render(request, 'search_incidents_query.html', {'form' : form})

The template

<form method='GET' action='/search_incidents/'>
    <div class="row">   
        <div class="form-group col-md-3">
            {{ form.incident }}
        </div>              
        <div class="form-group col-md-3">               
            {{ form.equipment }}
        </div>
    </div>
    <input type="submit" />
</form>

You can use a widget on the form to add form-control class to the fields.