Django Rest + Jinja2:ValueError:字典更新序列元素#0的长度为0; 2是必需的

时间:2023-01-25 02:27:37

I am currently developing a Django website using the Jinja2 template engine using the django-jinja package. As the website will need a JSON api I thought of using the Django Rest Framework (DRF).

我目前正在使用django-jinja软件包使用Jinja2模板引擎开发Django网站。由于网站需要JSON api,我想到使用Django Rest Framework(DRF)。

Everything worked nicely before using DRF, using class based views that inherited from django's class based views (TemplateView, ListView, ...).

在使用DRF之前,一切都运行得很好,使用继承自django基于类的视图(TemplateView,ListView,...)的基于类的视图。

Django Rest Framework Part

Django Rest框架部分

So I started including DRF to the website by creating Serializers and Routers. My settings for DRF are the following:

所以我开始通过创建Serializers和Routers将DRF包含在网站中。我对DRF的设置如下:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.TemplateHTMLRenderer',
        'rest_framework.renderers.JSONRenderer',
    )
}

My serializers are the following

我的序列化器如下

class ItemCategorySerializer(serializers.ModelSerializer):

    class Meta:
        model = ItemCategory
        fields = ('id', 'name', 'slug')

class ItemImageSerializer(serializers.ModelSerializer):

    class Meta:
        model = ItemImage
        fields = ('id', 'file',)

class ItemSerializer(serializers.ModelSerializer):

    owner = UserSerializer(read_only=True)
    categories = ItemCategorySerializer(many=True, read_only=True)
    photos = ItemImageSerializer(many=True, read_only=True)

    class Meta:
        model = Item
        fields = (
            'id', 'owner', 'name', 'categories', 'photos', 'price', 'quantity',
            'urgent', 'available', 'condition', 'boxing', 'description',
            'start_date', 'end_date', 'created_at', 'modified_at'
        )

And my urls.py are the following:

我的urls.py如下:

router = routers.SimpleRouter()
router.register(r'', ItemViewSet)

urlpatters = router.urls

I created one view to test the system:

我创建了一个视图来测试系统:

class ItemViewSet(viewsets.ModelViewSet):

    queryset = Item.objects.all().select_related('owner').prefetch_related('categories', 'photos')
    serializer_class = ItemSerializer
    permission_classes = (
        permissions.IsAuthenticatedOrReadOnly,
        IsOwnerOrReadOnly,
    )

    def list(self, request):
        self.template_name = 'item/list.jinja'
        return super(ItemViewSet, self).list(request)

django-jinja Part

My template settings are such as:

我的模板设置如下:

TEMPLATES = [

    {
        'BACKEND': 'django_jinja.backend.Jinja2',
        'APP_DIRS': False,
        'DIRS': [
            os.path.join(BASE_DIR, 'templates'),
        ],
        'OPTIONS': {
            #'match_regex': "*\.jinja$",
            'match_extension': '.jinja',
            'newstyle_gettext': True,
            'autoescape': True,
            'auto_reload': DEBUG,
            'constants': {
                'STATIC_URL': STATIC_URL,
                'timezone': timezone, # timezone is django.utils.timezone
            },
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'django.template.context_processors.tz',
                'django.template.context_processors.media',
            ],
            'extensions': [
                'jinja2.ext.do',
                'jinja2.ext.loopcontrols',
                'jinja2.ext.with_',
                'jinja2.ext.i18n',
                'jinja2.ext.autoescape',
                'django_jinja.builtins.extensions.CsrfExtension',
                'django_jinja.builtins.extensions.CacheExtension',
                'django_jinja.builtins.extensions.TimezoneExtension',
                'django_jinja.builtins.extensions.UrlsExtension',
                'django_jinja.builtins.extensions.StaticFilesExtension',
                'django_jinja.builtins.extensions.DjangoFiltersExtension',

                'jdj_tags.extensions.DjangoStatic',
                'jdj_tags.extensions.DjangoI18n',
                'jdj_tags.extensions.DjangoStatic',
                'jdj_tags.extensions.DjangoUrl',
            ],
        }
    },

    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'templates'),
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Settings Part

In my settings.py, the INSTALLED_APPS and MIDDLEWARE_CLASSES look like that:

在我的settings.py中,INSTALLED_APPS和MIDDLEWARE_CLASSES看起来像这样:

INSTALLED_APPS = (
    'grappelli',

    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'pytz',
    'django_extensions',
    'easy_thumbnails',
    'django_jinja',
    'django_jinja.contrib._humanize',
    'django_jinja.contrib._easy_thumbnails',

    'rest_framework',

    'mysite.item',
)

MIDDLEWARE_CLASSES = (
    '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',

)

Now that you can see the whole system the problem I have is that when I load the page at /items/ which calls the .list(request) method of the ItemViewSet, I get the following error:

现在您可以看到整个系统我遇到的问题是,当我在/ items /中调用ItemViewSet的.list(request)方法加载页面时,我收到以下错误:

Environment:


Request Method: GET
Request URL: http://localhost:8000/items/

Django Version: 1.8.1
Python Version: 2.7.8
Installed Applications:
('grappelli',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'pytz',
 'django_extensions',
 'easy_thumbnails',
 'django_jinja',
 'django_jinja.contrib._humanize',
 'django_jinja.contrib._easy_thumbnails',
 'rest_framework',
 'mysite.item',
 'mysite.person')
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')


Traceback:
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  164.                 response = response.render()
File "/usr/local/lib/python2.7/site-packages/django/template/response.py" in render
  158.             self.content = self.rendered_content
File "/usr/local/lib/python2.7/site-packages/rest_framework/response.py" in rendered_content
  59.         ret = renderer.render(self.data, media_type, context)
File "/usr/local/lib/python2.7/site-packages/rest_framework/renderers.py" in render
  169.         return template.render(context)
File "/usr/local/lib/python2.7/site-packages/django_jinja/backend.py" in render
  66.         return self.template.render(context)
File "/usr/local/lib/python2.7/site-packages/jinja2/environment.py" in render
  972.         vars = dict(*args, **kwargs)

Exception Type: ValueError at /items/
Exception Value: dictionary update sequence element #0 has length 0; 2 is required

So I edited the file at /usr/local/lib/python2.7/site-packages/jinja2/environment.py and printed args and kwargs in order to better understand what was going on:

所以我编辑了/usr/local/lib/python2.7/site-packages/jinja2/environment.py中的文件并打印了args和kwargs以便更好地了解发生了什么:

when printing args using print:

使用print打印args时:

([{
        'False': False,
        'None': None,
        'True': True
    },
    [OrderedDict(  ... here were all serialized objects returned  )], {}
], )

and when printing kwargs it simply returned {}

当打印kwargs时,它只是返回{}

So yeah basically if anyone has any idea of what is happening or what I could do to solve this issue.

所以,基本上,如果有人知道发生了什么或我能做些什么来解决这个问题。

Thank you in advance, Thomas

托马斯,先谢谢你了

EDIT 1

The first major finding is that when doing a normal request, args is a tuple containing a flat dict, whereas in the request using DRF, args is a tuple containing a RequestContext object.

第一个主要发现是,在执行正常请求时,args是包含平面字典的元组,而在使用DRF的请求中,args是包含RequestContext对象的元组。

So obviously I try to call args.flatten() to get a normal dict object. Now this method throws a similar error: ValueError: dictionary update sequence element #0 has length 16; 2 is required.

所以很明显我试着调用args.flatten()来获得一个普通的dict对象。现在这个方法抛出了一个类似的错误:ValueError:字典更新序列元素#0的长度为16; 2是必需的。

This error occurs in the code inside django.template.context.RequestContext.flatten() which is

在django.template.context.RequestContext.flatten()里面的代码中发生了这个错误,这是

def flatten(self):
        """
        Returns self.dicts as one dictionary
        """
        flat = {}
        for d in self.dicts:
            flat.update(d)  # <-- Exception occurs at this point
        return flat

I'll try to gather more information in order to solve this issue

我将尝试收集更多信息以解决此问题

EDIT 2

I realised the REST framework instantiates the RequestContext inside the render method of the TemplateHTMLRenderer, so obviously that breaks the system because Jinja2 expects a dict and not a RequestContext. Trying to write a fix now

我意识到REST框架在TemplateHTMLRenderer的render方法中实例化了RequestContext,所以很明显会破坏系统,因为Jinja2需要一个dict而不是RequestContext。现在尝试编写修复程序

EDIT 3: FIXED

编辑3:固定

Okay so the only way I could see in order to fix this was to write my own REST Renderer and so I wrote a JinjaTemplateRenderer that I will post on github and try to merge with the project. I will post here soon

好吧,所以我能看到解决这个问题的唯一方法是编写自己的REST渲染器,所以我写了一个JinjaTemplateRenderer,我将在github上发布并尝试与项目合并。我很快就会在这里发布

1 个解决方案

#1


I was able to fix the problem by writing my own renderer, here a JinjaTemplateRenderer

我能够通过编写自己的渲染器来解决这个问题,这里是一个JinjaTemplateRenderer

Although this is not really working in the end, many problems with it, I will just go back to using normal class based views instead of the REST framework as it does not satisfy my needs.

虽然这最终没有真正起作用,但很多问题,我将回到使用基于普通类的视图而不是REST框架,因为它不能满足我的需求。

#1


I was able to fix the problem by writing my own renderer, here a JinjaTemplateRenderer

我能够通过编写自己的渲染器来解决这个问题,这里是一个JinjaTemplateRenderer

Although this is not really working in the end, many problems with it, I will just go back to using normal class based views instead of the REST framework as it does not satisfy my needs.

虽然这最终没有真正起作用,但很多问题,我将回到使用基于普通类的视图而不是REST框架,因为它不能满足我的需求。