applegrew / django-select2

This is a Django integration for Select2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to filter ModelSelect2Widget queryset with a request data?

kabrachups opened this issue · comments

I use django_tables2 with django_filter according to django_tables2 tutorial:

#views.py
from django_filters.views import FilterView
from django_tables2.views import SingleTableMixin
        
class FilteredCarListView(SingleTableMixin, FilterView):
    table_class = CarTable
    model = Car
    template_name = 'template.html'    
    filterset_class = CarFilter

def get_queryset(self):
	return self.model.objects.filter(owner_id=request.user.id)

And now I want to have a filter's field and its ModelSelect2Widget with the same filter as in get_queryset() above. Something like this:
queryset = Car.objects.filter(owner_id=request.user.id).

For filter's field I've found this decision (I guess it is not DRY):

# filters.py
from .models import Car
from django_select2.forms import ModelSelect2Widget
def get_cars(request):	
	return Car.objects.filter(owner_id=request.user.id)
	
class CarFilter(django_filters.FilterSet):
	car = django_filters.ModelChoiceFilter(
		queryset = get_cars,
		field_name='car',
		widget = ModelSelect2Widget(
		model = Car,
		queryset = Car.objects.filter(owner_id=request.user.id)
		search_fields=['car__icontains'])

But how to limit choises in ModelSelect2Widget to display current user's cars only?

Hi @kabrachups

Thanks for reaching out. You are already on a good track. I haven't used django_tables2 before, but I believe the following code should work:

import django_filters
from django_select2 import forms as select2

from . import models


class CarWidget(select2.ModelSelect2Widget):
    queryset = models.Car.objects.all()

    def filter_queryset(self, request, **kwargs):
        """
        Limit results to Car's owned by the current user.

        If the current user is not authenticated, return empty queryset.
        """
        if not request.user.is_authenticated:
            return super().filter_queryset(request, **kwargs).filter(
                owner_id=request.user.id
            )
        return self.queryset.none()


class CarField(django_filters.ModelChoiceFilter):
    widget = CarWidget

    def get_queryset(self, request):
        """
        Limit results to Car's owned by the current user.

        If the current user is not authenticated, return empty queryset.
        """
        if request.user.is_authenticated:
            return models.Car.objects.filter(owner_id=request.user.id)
        return models.Car.objects.none()


class CarFilter(django_filters.FilterSet):
    car = django_filters.ModelChoiceFilter(
        widget=CarWidget,
    )

Let me know if that works for you and if you have any further questions.

Best
-Joe

It does work! )))

Just one simple correction:

.filter_queryset(request, **kwargs)
to
.filter_queryset(request, term, queryset, **kwargs)

Thank you a LOT!

Perfect, happy it worked :)

Sorry to reopen this, but I'm trying to set-up full text search using a TrigramSimilarity class. Here's how I'd do it from the command line:

from django.contrib.postgres.search import TrigramSimilarity
term = 'John Smith'
Author.objects.annotate(
    similarity=TrigramSimilarity("name", term), # `name` is the model field name, `term` is the search term.
).filter(
    similarity__gt=0.3,
).order_by("-similarity")

I tried following the pattern above, but it required asearch_fields parameter in the s2forms.ModelSelect2Widget Class, which overrode everything else.

I'm afraid I'm not too good at Class inheritance; I'm trying to cargo-cult what you've got here and it simply isn't working... :-)