Search code examples
pythondjangodjango-formsdjango-viewsdjango-filter

Django-Filter FilterSet Show Only User Generated Objects


I'm using a django-filter form and it's filtering all objects for 'associated_portfolios' how can I make it so it only shows the user the objects they created?

Error message:

'StatsFilter' object has no attribute 'fields'

Filters.py

class StatsFilter(django_filters.FilterSet):
    associated_portfolios = django_filters.ModelMultipleChoiceFilter(queryset=associated_portfolios)

    class Meta:
        model = Trade
        fields = ['type', 'asset', 'symbol', 'broker', 'patterns', 'associated_portfolios']

    def __init__(self, request, *args, **kwargs):
        super(StatsFilter, self).__init__(*args, **kwargs)
        self.fields['associated_portfolios'].queryset = Trade.objects.filter(user=request.user)]

views.py

class StatsView(LoginRequiredMixin, FilterView):
    model = Trade
    template_name = 'dashboard/stats.html'
    filterset_class = StatsFilter

    def get_context_data(self, **kwargs):
        filter = StatsFilter(self.request.GET, queryset=self.get_queryset())
        context = super().get_context_data(**kwargs)
        context['filter'] = filter
        context['get_users_trades'] = Trade.objects.get_users_trades('tj3admin')
        context['get_largest_winning_trade'] = filter.qs.aggregate(max_value=Max('profit_loss_value_fees'))['max_value']
        return context

Solution

  • Ah, now I remember: set the queryset argument of ModelMultipleChoiceFilter to a callable that accepts request as it's only argument:

    
    def portfolio_filtered_queryset(request):
        return Trade.objects.filter(user=request.user)
    
    class StatsFilter(django_filters.FilterSet):
        associated_portfolios = django_filters.ModelMultipleChoiceFilter(queryset=porfolio_filtered_queryset)
    
    The view:
    class StatsView(LoginRequiredMixin, FilterView):
        model = Trade
        template_name = 'dashboard/stats.html'
        filterset_class = StatsFilter
    
        def get_context_data(self, **kwargs):
            # Must pass in request!
            filter = StatsFilter(self.request.GET, queryset=self.get_queryset(), request=self.request)
            context = super().get_context_data(**kwargs)
            context['filter'] = filter
            context['get_users_trades'] = Trade.objects.get_users_trades('tj3admin')
            context['get_largest_winning_trade'] = filter.qs.aggregate(max_value=Max('profit_loss_value_fees'))['max_value']
            return context
    

    In django_filters.filters.QuerySetRequestMixin.get_request() the request instance is obtained from the parent. But I see no logic in django_filters.filterset.BaseFilterSet or concretes that tries to obtain the request through other means. So you must pass the request to the StatsFilter if you wish to make use of QuerySetRequestMixin.