I'm trying to create a search capability in my Django project that will filter multiple models (currently 3) and return a value from the surveys model. It works for a single model and an additional model tied by a foreign key. But, when I added a dropdown menu for the third model not containing a direct reference to the initial model, I got an error saying they keyword was unavailable (because it wasn't looking in the model):
Cannot resolve keyword 'rooms' into field. Choices are: DateBegin, FAN, IS, Location, PI, holdings, id
Models:
#models.py
class rooms(models.Model):
ContainerLocation = models.CharField(max_length=100, blank=True, null=True)
Database = models.CharField(max_length=100, blank=True, null=True)
Name = models.CharField(max_length=100, blank=True, null=True)
Datatype = models.CharField(max_length=100, blank=True, null=True)
class holdings(models.Model):
Contents = models.CharField(max_length=700, blank=True, null=True, default='No description')
FAN = models.ForeignKey('surveys', on_delete=models.SET_NULL, blank=True, null=True)
Database = models.ForeignKey('rooms', on_delete=models.SET_NULL, blank=True, null=True)
...(more fields)...
class surveys(models.Model):
FAN = models.SlugField(max_length=100, blank=True, null=True)
PI = models.CharField(max_length=100, blank=True, null=True)
IS = models.CharField(max_length=100, blank=True, null=True)
DateBegin = models.DateField(blank=True, null=True)
Location = models.CharField(max_length=200, blank=True, null=True)
Filter:
#filters.py
from django import forms
from datalibrary.models import surveys, rooms, holdings
import django_filters
class MultiFilter(django_filters.FilterSet):
FAN = django_filters.CharFilter(lookup_expr='icontains', distinct=True)
PI = django_filters.CharFilter(lookup_expr='icontains', distinct=True)
Location = django_filters.CharFilter(lookup_expr='icontains', distinct=True)
Contents = django_filters.CharFilter(field_name='holdings__Contents', lookup_expr='icontains', label='Contents', distinct=True)
Room = django_filters.ModelChoiceFilter(queryset=rooms.objects.all(), label='Room', distinct=True)
class Meta:
model = surveys
fields = ['FAN', 'PI', 'Location', 'Contents', 'Room']
Views:
#views.py
def search(request):
multifilter = MultiFilter(request.GET, queryset=surveys.objects.all())
return render(request, 'search_results.html', {'filter': multifilter})
Is it possible to build a filter with django-filters that searches multiple models? Can I create a merged queryset or something like that? I tried adding a list to the filters Meta
(e.g. model = [surveys, rooms, holdings]
) but that obviously doesn't work.
If django-filters can't do it, are there other options for searching multiple models in Django?
I figured out how this should work. Another model can be specified using modelname__field
(that's two underscores)in the fields
variable under Meta
. So it would look like this:
#filters.py
from django import forms
from datalibrary.models import surveys, rooms, holdings
import django_filters
class MultiFilter(django_filters.FilterSet):
FAN = django_filters.CharFilter(lookup_expr='icontains', distinct=True)
PI = django_filters.CharFilter(lookup_expr='icontains', distinct=True)
Location = django_filters.CharFilter(lookup_expr='icontains', distinct=True)
Contents = django_filters.CharFilter(field_name='holdings__Contents', lookup_expr='icontains', label='Contents', distinct=True)
Room = django_filters.ModelChoiceFilter(lookup_expr='icontains', label='Room', distinct=True)
class Meta:
model = surveys
fields = ['FAN', 'PI', 'Location', 'Contents', 'rooms__name']
rooms__name
here is referring to the field name
in the model rooms
.
Note that I changed Room
to rooms_name
in the fields
list.