2

一起使用 django-admin-tools(0.8.0) 和 django-tables2(1.5) 时尝试在 Django(1.10.4) 中通过 xhtml2pdf 呈现 PDF 时遇到问题。我已经做了足够的阅读以了解发生了什么的基础,但不知道如何解决它。我认为这与 django-admin-tools 自定义加载器有关。

链接到我从 django-tables 获得的异常。

这个SO question让我问了一个问题。

我正在尝试做的事情的要点是通过 django-admin 界面中我的 AdminModel 的下拉框创建一个自定义管理员“操作”,将给定的查询集转换为 PDF 文档。

根据 django-tables2文档,render() 函数接受 3 个参数(请求、'template_name.html'、{'people': Person.objects.all()})。所以我在我的 context_dict 中添加了一个查询集,并尝试在下面模板的 for 循环中使用它,但没有骰子。该模板在没有 django-tables2 的情况下将 html 呈现为 pdf,但如果我尝试将表格转换为 PDF,我会得到以下内容......

追溯

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.

自定义管理功能

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')

我的 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

我的 settings.py 模板配置

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',
            ]
        },
    },
]

PDF 模板

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

1 回答 1

4

要使用模板上下文处理器,您必须request在渲染模板时传递对象:

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

您可以使用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)
    ...

顺便说一句,在定义函数时,您不应该使用可变值作为默认值。在上面的第二个示例中,我展示了如何通过使用None默认设置来避免问题。

于 2017-04-24T16:27:49.063 回答