Django 模板标签将当前请求的 GET 参数添加到 Python3+Django2 中的 url

Django template tag to add GET parameters from current request to url in Python3+Django2

我正在尝试将我的项目从 Python 2.7/Django 1.11 迁移到 Python 3.7/Django 2.1。

在我的项目中,我使用了来自以下 Django 片段的 'add_get_parameter' 模板标签: https://djangosnippets.org/snippets/2428/

add_get_parameter.py

class AddGetParameter(Node):
    def __init__(self, values):
        self.values = values

    def render(self, context):
        #req = resolve_variable('request',context) #deprecated in modern Django
        req = template.Variable('request').resolve(context)
        params = req.GET.copy()
        for key, value in self.values.items():
            params[key] = Variable(value).resolve(context)
        return '?%s' %  params.urlencode()


@register.tag
def add_get_parameter(parser, token):
    from re import split
    contents = split(r'\s+', token.contents, 2)[1]
    pairs = split(r',', contents)

    values = {}

    for pair in pairs:
        s = split(r'=', pair, 2)
        values[s[0]] = s[1]

    return AddGetParameter(values)

在模板中,我用它来制作这样的分页网址:

{% load add_get_parameter %}
<div class="pagination">
    <span class="step-links">
        {% if device_tests.has_previous %}
            <a href="{% add_get_parameter page=device_tests.previous_page_number %}">Previous</a>
        {% endif %}

        {% for num in device_tests.paginator.page_range %}
            {% if num == device_tests.number %}
                <span class="current"><b>{{ num }}</b></span>
            {% else %}
                <a href="{% add_get_parameter page=num %}"> {{ num }}</a>
            {% endif %} 
        {% endfor %}

        {% if device_tests.has_next %}
            <a href="{% add_get_parameter page=device_tests.next_page_number %}">Next</a>
        {% endif %}
    </span>
</div>

它在 Python 2.7/Django 1.11 中都有效,但在 Python 3.7/Django 2.1 中无效。

Django 抱怨:

Exception Type: AttributeError
Exception Value: 'int' object has no attribute 'encode'

标记错误字符串在'add_get_parameter.py':

return '?%s' %  params.urlencode()

如何解决这个问题?

完整追溯:

Error during template rendering
In template E:\routemaps_python3\trunk\predator\templates\layout.html, error at line 0

'int' object has no attribute 'encode'
1   {% load static from staticfiles %}
2   
3   <!doctype html>
4   <html>
5       <head>
6           <meta charset="utf=8">
7           <meta http-equiv="X-UA-Compatible" content="IE=edge">
8           <meta name="viewport" content="width=device-width, initial-scale=1">
9   
10          <title>{% block title %}{% endblock %}</title>
Traceback Switch to copy-and-paste view
C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\core\handlers\exception.py in inner
            response = get_response(request) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\core\handlers\base.py in _get_response
                response = self.process_exception_by_middleware(e, request) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\core\handlers\base.py in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs) ...

E:\routemaps_python3\trunk\predator\predator\views_errors_feed.py in device_test_errors_feed
    return render(request, 'device_test_errors_feed.html', {'device_tests': device_tests}) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\shortcuts.py in render
    content = loader.render_to_string(template_name, context, request, using=using) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\loader.py in render_to_string
    return template.render(context, request) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\backends\django.py in render
            return self.template.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render
                    return self._render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in _render
        return self.nodelist.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render
                bit = node.render_annotated(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render_annotated
            return self.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\loader_tags.py in render
            return compiled_parent._render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in _render
        return self.nodelist.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render
                bit = node.render_annotated(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render_annotated
            return self.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\defaulttags.py in render
                return nodelist.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render
                bit = node.render_annotated(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render_annotated
            return self.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\templatetags\tz.py in render
            output = self.nodelist.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render
                bit = node.render_annotated(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render_annotated
            return self.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\loader_tags.py in render
                result = block.nodelist.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render
                bit = node.render_annotated(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render_annotated
            return self.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\defaulttags.py in render
                    nodelist.append(node.render_annotated(context)) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render_annotated
            return self.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\defaulttags.py in render
                return nodelist.render(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render
                bit = node.render_annotated(context) ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\template\base.py in render_annotated
            return self.render(context) ...

E:\routemaps_python3\trunk\predator\device_tests\templatetags\add_get_parameter.py in render
        return '?%s' %  params.urlencode() ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\http\request.py in urlencode
                for v in list_ ...

C:\Users\kostr\AppData\Local\Continuum\Anaconda\envs\routemaps3\lib\site-packages\django\http\request.py in <genexpr>
                for v in list_ ...

解决方法很简单。感谢@BearBrown

Variable(value).resolve(context) 参数应转换为字符串

class AddGetParameter(Node):
    def __init__(self, values):
        self.values = values

    def render(self, context):
        #req = resolve_variable('request',context) #deprecated in modern Django
        req = template.Variable('request').resolve(context)
        params = req.GET.copy()
        for key, value in self.values.items():
            params[key] = str(Variable(value).resolve(context))
        return '?%s' %  params.urlencode()