'django.template.context_processors.request

2019-07-13 12:43发布

问题:

I'm having an issue when trying to render a PDF through xhtml2pdf in Django(1.10.4) when using django-admin-tools(0.8.0) & django-tables2(1.5) together. I've done enough reading to understand the basis of what's going on but have not idea how to fix it. I think it's got something to do with the django-admin-tools custom loaders.

Link to the exception I'm getting from django-tables.

This SO question led me to asking a question.

The gist of what I'm trying to do is create a custom Admin 'action' through the drop-down box of my AdminModel in the django-admin interface that turns the queryset given into a PDF document.

According to the django-tables2 docs the render() function takes 3 arguments (request, 'template_name.html', {'people': Person.objects.all()}). So I added a queryset to my context_dict and tried using it in a for loop in the template below but no dice. The template renders the html to pdf just fine without django-tables2 but if I try to convert the tables to PDF I get the following...

Traceback

Environment:


Request Method: POST
Request URL: http://127.0.0.1:9999/admin/research/labsample/

Django Version: 1.10.4
Python Version: 3.5.2
Installed Applications:
('admin_tools',
 'admin_tools.theming',
 'admin_tools.menu',
 'admin_tools.dashboard',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django_tables2',
 'import_export',
 'chemicals',
 'suppliers',
 'customers',
 'recipes',
 'research')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware')


Template error:
In template /home/dan/Projects/research/lib/python3.5/site-packages/django_tables2/templates/django_tables2/table.html, error at line 13
   Tag {% querystring %} requires django.template.context_processors.request to be in the template configuration in settings.TEMPLATES[]OPTIONS.context_processors) in order for the included template tags to function correctly.   3 : 
   4 : <div class="table-container">
   5 : {% block table %}
   6 : <table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
   7 :     {% block table.thead %}
   8 :     {% if table.show_header %}
   9 :     <thead>
   10 :         <tr>
   11 :         {% for column in table.columns %}
   12 :             {% if column.orderable %}
   13 :             <th {{ column.attrs.th.as_html }}><a href=" {% querystring table.prefixed_order_by_field=column.order_by_alias.next %} ">{{ column.header }}</a></th>
   14 :             {% else %}
   15 :             <th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
   16 :             {% endif %}
   17 :         {% endfor %}
   18 :         </tr>
   19 :     </thead>
   20 :     {% endif %}
   21 :     {% endblock table.thead %}
   22 :     {% block table.tbody %}
   23 :     <tbody>


Traceback:

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/core/handlers/exception.py" in inner
  39.             response = get_response(request)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/contrib/admin/options.py" in wrapper
  544.                 return self.admin_site.admin_view(view)(*args, **kwargs)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/utils/decorators.py" in _wrapped_view
  149.                     response = view_func(request, *args, **kwargs)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  57.         response = view_func(request, *args, **kwargs)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/contrib/admin/sites.py" in inner
  211.             return view(request, *args, **kwargs)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/utils/decorators.py" in _wrapper
  67.             return bound_func(*args, **kwargs)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/utils/decorators.py" in _wrapped_view
  149.                     response = view_func(request, *args, **kwargs)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/utils/decorators.py" in bound_func
  63.                 return func.__get__(self, type(self))(*args2, **kwargs2)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/contrib/admin/options.py" in changelist_view
  1569.                 response = self.response_action(request, queryset=cl.get_queryset(request))

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/contrib/admin/options.py" in response_action
  1305.             response = func(self, request, queryset)

File "/home/dan/Projects/research/mysite/research/admin.py" in GeneratePdf
  27.   pdf = render_to_pdf('pdf/quote_recipe.html', content)

File "/home/dan/Projects/research/mysite/research/utils.py" in render_to_pdf
  40.   html = template.render(context_dict)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/backends/django.py" in render
  66.             return self.template.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  208.                     return self._render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in _render
  199.         return self.nodelist.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  994.                 bit = node.render_annotated(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/defaulttags.py" in render
  209.                     nodelist.append(node.render_annotated(context))

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django_tables2/templatetags/django_tables2.py" in render
  154.             return template.render(context.flatten())

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/backends/django.py" in render
  66.             return self.template.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  208.                     return self._render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in _render
  199.         return self.nodelist.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  994.                 bit = node.render_annotated(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/loader_tags.py" in render
  61.                 result = self.nodelist.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  994.                 bit = node.render_annotated(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/loader_tags.py" in render
  61.                 result = self.nodelist.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  994.                 bit = node.render_annotated(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/defaulttags.py" in render
  315.                 return nodelist.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  994.                 bit = node.render_annotated(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/defaulttags.py" in render
  209.                     nodelist.append(node.render_annotated(context))

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/defaulttags.py" in render
  315.                 return nodelist.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render
  994.                 bit = node.render_annotated(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django/template/base.py" in render_annotated
  961.             return self.render(context)

File "/home/dan/Projects/research/lib/python3.5/site-packages/django_tables2/templatetags/django_tables2.py" in render
  59.             raise ImproperlyConfigured(context_processor_error_msg % 'querystring')

Exception Type: ImproperlyConfigured at /admin/research/labsample/
Exception Value: Tag {% querystring %} requires django.template.context_processors.request to be in the template configuration in settings.TEMPLATES[]OPTIONS.context_processors) in order for the included template tags to function correctly.

Custom Admin function

def GeneratePdf(self, request, queryset):
    data = queryset.values()
    content = {}
    rec = RecipeIngredients.objects.filter(recipe_id=data.values()[0]['lab_recipe_id'])
    content.update({'recipe':{rec.values()}})
    content.update(data[0])
    pdf = render_to_pdf('pdf/quote_recipe.html', content)
    return HttpResponse(pdf, content_type='application/pdf')

My utils.py

def render_to_pdf(template_src, context_dict={}):
    template = get_template(template_src)
    html = template.render(context_dict)
    result = BytesIO()
    pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result, link_callback=link_callback)
    if not pdf.err:
        return HttpResponse(result.getvalue(), content_type='application/pdf')
    return None

My settings.py template config

TEMPLATES = [
  {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS':[BASE_DIR+'/templates/',],
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.template.context_processors.i18n',
                'django.template.context_processors.media',
                'django.template.context_processors.static',
                'django.template.context_processors.tz',
                'django.template.context_processors.debug',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
            'loaders':[
                'admin_tools.template_loaders.Loader',
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
            ]
        },
    },
]

Template for PDF

{% load render_table from django_tables2 %}
{% load static %}
<!doctype html>
<html>
    <body>
        {% for r in recipe %}
           {% render_table r %}
        {% endfor %}
    </body>
</html>

回答1:

To use the template context processors, you must pass the request object when rendering the template:

def render_to_pdf(template_src, context_dict={}):
    template = get_template(template_src)
    html = template.render(context_dict, request=request)
    ...

You can simplify the code slightly by using render_to_string.

from django.template.loader import render_to_string

def render_to_pdf(template_src, context_dict=None):
    if context_dict is None:
        context_dict = {}
    html = render_to_string(template_src, context_dict, request=request)
    ...

As an aside, you shouldn't use mutable values as defaults when defining functions. In the second example above, I have shown how you can avoid issues by using None as the default.