Django ListView customising queryset

前端 未结 2 676
无人共我
无人共我 2020-12-17 14:31

Hopefully this should be a simple one to help me with.

I have a page with a dropdown menu containing three items:

&l
相关标签:
2条回答
  • 2020-12-17 15:03

    To solve this problem I just modified the pagination HTML, to accommodate both the get request from the form and the page number in the url string, like so:

    <div class="pagination">
        <span class="page-links">
            {% if page_obj.has_previous %}
                <a href="/browse/?browse={{ input }}&page={{ page_obj.previous_page_number }}">previous</a>
            {% endif %}
            <span class="page-current">
                Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
            </span>
            {% if page_obj.has_next %}
                <a href="/browse/?browse={{ input }}&page={{ page_obj.next_page_number }}">next</a>
            {% endif %}
        </span>
    </div>
    

    The {{ input }} here is a string containing the option submitted via the form, e.g. 'Cats' or 'Worms'.

    To be able to pass this into the template, I modified the get_context_data method of the class based view as such:

    class Browse(generic.ListView):
        template_name = 'app/browse.html'
        paginate_by = 25
    
        # Modifying the get_context_data method
    
        def get_context_data(self, **kwargs):
            context = super(Browse, self).get_context_data(**kwargs)
            q = self.request.GET.get("browse")
            context['input'] = q
            return context
    
        def get_queryset(self):
            queryset = Cats.objects.all()
            if self.request.GET.get("browse"):
                selection = self.request.GET.get("browse")
                if selection == "Cats":
                    queryset = Cats.objects.all()
                elif selection == "Dogs":
                    queryset = Dogs.objects.all()
                elif selection == "Worms":
                    queryset = Worms.objects.all()
                else:
                    queryset = Cats.objects.all()
            return queryset
    

    That was it, the url string now reads something like:

    /browse/?browse=Cats&page=3
    

    So there it is, pagination now works alongside the get method of the form.

    0 讨论(0)
  • 2020-12-17 15:07

    I put together a template tag to help using queries based on Sirrah's answer. Example:

    <a href="{% url view_url %}?{% query query_params page=num %}">{{ num }}</a>
    

    If query params is a dictionary {'foo': 'bar'} passed in the context, it will be rendered to something like this:

    <a href="myview/?foo=bar&page=2">2</a>
    

    Syntax:

    {% query var_name param=value 'name_only_param' other_param=value|default:'x' another_var %}
    

    Variables can be lists, dicts, strings or None (None is skipped).

    Code:

    from django import template
    from django.utils.encoding import force_text
    from django.template.base import Node, TemplateSyntaxError, kwarg_re, FilterExpression
    
    register = template.Library()
    
    @register.tag
    def query(parser, token):
        bits = token.split_contents()
        args = []
        asvar = None
        bits = bits[1:]
        if len(bits) >= 2 and bits[-2] == 'as':
            asvar = bits[-1]
            bits = bits[:-2]
    
        if len(bits):
            for bit in bits:
                match = kwarg_re.match(bit)
                if not match:
                    raise TemplateSyntaxError("Malformed arguments to url tag")
                name, value = match.groups()
                if name:
                    args.append({name: parser.compile_filter(value)})
                else:
                    args.append(parser.compile_filter(value))
    
        return QueryNode(args, asvar)
    
    
    class QueryNode(Node):
        def __init__(self, args, asvar):
            self.args = args
            self.asvar = asvar
    
        def render(self, context):
            def join(thing, lst):
                if isinstance(thing, dict):
                    for k, v in thing.items():
                        if isinstance(v, FilterExpression):
                            v = force_text(v.resolve(context))
                        if v is None:
                            continue
                        lst.append('{}={}'.format(k, v))
                elif isinstance(thing, list):
                    for it in thing:
                        if isinstance(it, FilterExpression):
                            it = it.resolve(context)
                        join(it, lst)
                elif isinstance(thing, str):
                    lst.append(thing + '=')
                elif thing is None:
                    pass
                else:
                    raise TypeError('Cannot join: %r' % thing)
    
            query_lst = []
            join(self.args, query_lst)
            query = '&'.join(query_lst)
    
            if self.asvar:
                context[self.asvar] = query
                return ''
            else:
                return query
    
    0 讨论(0)
提交回复
热议问题