Django ListView - Form to filter and sort

前端 未结 4 925
醉梦人生
醉梦人生 2020-12-12 22:58

My Goal

  • A site that list all my Updates (model) in a table
  • Dont display all models at once (pagination - maybe 10 per page)
相关标签:
4条回答
  • 2020-12-12 23:19

    This is how we do it, that way you get validation/type conversion as well:

    class UnitList(PermissionRequiredMixin, ListView):
        """ Class based view to show a list of all buildings for a specific user """
    
        model = Unit
        ordering = ['building', 'unit']
        paginate_by = 100
    
        # Access
        permission_required = ['core.manager_perm']
        raise_exception = True  # If true, give access denied message rather than redirecting to login
    
        def get_queryset(self):
            try:
                units = self.model.objects.filter(building__company=self.request.user.profile.company)
            except Profile.DoesNotExist:
                units = self.model.objects.none()
    
            form = UnitSearchForm(self.request.GET)
    
            if form.is_valid():
                filters = {}
    
                address = form.cleaned_data['address']
                neighborhood = form.cleaned_data['neighborhood']
                beds = form.cleaned_data['beds']
                amenity = form.cleaned_data['amenity']
    
                if address:
                    filters['building__street_index__istartswith'] = compute_street_address_index(address)
    
                if neighborhood:
                    filters['building__neighborhood__icontains'] = neighborhood
    
                if beds:
                    filters['beds'] = beds
    
                if amenity:
                    filters['unit_amenities__name__iexact'] = amenity
        
                units = units.filter(**filters)
    
            return units.select_related('building').order_by(*self.ordering)
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['form'] = UnitSearchForm(self.request.GET)
    
            return context
    
    0 讨论(0)
  • 2020-12-12 23:34

    I am wondering why nobody mentioned here this cool library: django-filter https://github.com/carltongibson/django-filter

    you can define your logic for filtering very clean and get fast working forms etc.

    demo here: https://stackoverflow.com/a/46492378/953553

    0 讨论(0)
  • 2020-12-12 23:35

    I posted this elsewhere but I think this adds to the selected answer.

    I think you would be better off doing this via get_context_data. Manually create your HTML form and use GET to retrieve this data. An example from something I wrote is below. When you submit the form, you can use the get data to pass back via the context data. This example isn't tailored to your request, but it should help other users.

    def get_context_data(self, **kwargs):
        context = super(Search, self).get_context_data(**kwargs)
        filter_set = Gauges.objects.all()
        if self.request.GET.get('gauge_id'):
            gauge_id = self.request.GET.get('gauge_id')
            filter_set = filter_set.filter(gauge_id=gauge_id)
    
        if self.request.GET.get('type'):
            type = self.request.GET.get('type')
            filter_set = filter_set.filter(type=type)
    
        if self.request.GET.get('location'):
            location = self.request.GET.get('location')
            filter_set = filter_set.filter(location=location)
    
        if self.request.GET.get('calibrator'):
            calibrator = self.request.GET.get('calibrator')
            filter_set = filter_set.filter(calibrator=calibrator)
    
        if self.request.GET.get('next_cal_date'):
            next_cal_date = self.request.GET.get('next_cal_date')
            filter_set = filter_set.filter(next_cal_date__lte=next_cal_date)
    
        context['gauges'] = filter_set
        context['title'] = "Gauges "
        context['types'] = Gauge_Types.objects.all()
        context['locations'] = Locations.objects.all()
        context['calibrators'] = Calibrator.objects.all()
        # And so on for more models
        return context
    
    0 讨论(0)
  • 2020-12-12 23:39

    You don't need post. Pass the filter value and order_by in the url for example:

    .../update/list/?filter=filter-val&orderby=order-val

    and get the filter and orderby in the get_queryset like:

    class MyView(ListView):
        model = Update
        template_name = "updates/update.html"
        paginate_by = 10
    
        def get_queryset(self):
            filter_val = self.request.GET.get('filter', 'give-default-value')
            order = self.request.GET.get('orderby', 'give-default-value')
            new_context = Update.objects.filter(
                state=filter_val,
            ).order_by(order)
            return new_context
    
        def get_context_data(self, **kwargs):
            context = super(MyView, self).get_context_data(**kwargs)
            context['filter'] = self.request.GET.get('filter', 'give-default-value')
            context['orderby'] = self.request.GET.get('orderby', 'give-default-value')
            return context
    

    Make sure you give proper default value to filter and orderby

    Example form (you can modify this to your need):

    <form method="get" action="{% url 'update-list' %}">
        <p>Filter: <input type="text" value={{filter}} name="filter"/></p>
        <p>order_by: <input type="text" value={{orderby}} name="orderby"/></p>
        <p><input type="submit" name="submit" value="submit"/></p>
    </form>
    
    0 讨论(0)
提交回复
热议问题