【问题标题】:Django Parler "The 'language_code' attribute cannot be changed directlyDjango Parler“不能直接更改'language_code'属性
【发布时间】:2020-07-30 16:52:06
【问题描述】:

我目前正在扩展一个插件以与 Django 翻译和语言配合使用。这是有问题的方法。在涉及翻译之前,它会根据需要工作。

我扩展了查询以从几个翻译表中提取数据。但是,我收到一个错误,我不确定如何处理。

    def get_authors_and_article_counts(self, authors):
        """method returning authors and their article counts"""

        # first, we collect ids of authors for which we need to get data
        author_ids = [author.id for author in self.authors.all()]
        author_ids_tuple_str = '(' +  str(author_ids).strip('[]') + ')'

        #limit subquery to published articles
        published_clause = """ AND
            is_published %s AND
            publishing_date <= %s
            """ % (SQL_IS_TRUE, SQL_NOW_FUNC, )

        query = """
                with article_count as (
                  select author_id, count(*) as article_count
                    from aldryn_newsblog_article
                   where app_config_id = 1
                    %s
                   group by author_id
                )

                select distinct prof.*, coalesce(ac.article_count, 0) as article_count, author_trans.*, aldryn_people_trans.slug
                from common_authorprofile prof

                left join article_count ac
                on ac.author_id = prof.profile_id

                left join common_authorprofile_translation author_trans
                on prof.id = author_trans.master_id

                left join aldryn_people_person_translation aldryn_people_trans
                on prof.profile_id = aldryn_people_trans.master_id
                WHERE
                        prof.id IN %s AND
                        author_trans.language_code = 'ru';

""" % (published_clause, author_ids_tuple_str)

        print(query)
        #print(author_ids)

        raw_authors = list(AuthorProfile.objects.raw(query))
        #print(raw_authors)
        authors = [author for author in raw_authors if author.article_count]

        print(authors)
        return sorted(authors, key=lambda x: x.article_count, reverse=True)

回溯:

Traceback (most recent call last):
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
core/handlers/exception.py", line 34, in inner                                          
    response = get_response(request)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
core/handlers/base.py", line 156, in _get_response                                      
    response = self.process_exception_by_middleware(e, request)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
core/handlers/base.py", line 154, in _get_response                                      
    response = response.render()
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/response.py", line 106, in render                                              
    self.content = self.rendered_content
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/response.py", line 83, in rendered_content                                     
    content = template.render(context, self._request)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/backends/django.py", line 61, in render                                        
    return self.template.render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 171, in render                                                  
    return self._render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 163, in _render                                                 
    return self.nodelist.render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 937, in render                                                  
    bit = node.render_annotated(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 904, in render_annotated                                        
    return self.render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/classyt
ags/core.py", line 153, in render                                                       
    return self.render_tag(context, **kwargs)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/sekizai
/templatetags/sekizai_tags.py", line 93, in render_tag                                  
    rendered_contents = nodelist.render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 937, in render                                                  
    bit = node.render_annotated(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 904, in render_annotated                                        
    return self.render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/classyt
ags/core.py", line 153, in render                                                       
    return self.render_tag(context, **kwargs)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/cms/tem
platetags/cms_tags.py", line 447, in render_tag                                         
    return toolbar.render_with_structure(context, nodelist)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/cms/too
lbar/toolbar.py", line 477, in render_with_structure                                    
    rendered_contents = nodelist.render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 937, in render                                                  
    bit = node.render_annotated(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
template/base.py", line 904, in render_annotated                                        
    return self.render(context)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/classyt
ags/core.py", line 153, in render                                                       
    return self.render_tag(context, **kwargs)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/cms/tem
platetags/cms_tags.py", line 313, in render_tag                                         
    nodelist=nodelist,
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/cms/plu
gin_rendering.py", line 343, in render_page_placeholder                                 
    nodelist=None,
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/cms/plu
gin_rendering.py", line 259, in render_placeholder                                      
    placeholder_content = ''.join(plugin_content)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/cms/plu
gin_rendering.py", line 456, in render_plugins                                          
    yield self.render_plugin(plugin, context, placeholder, editable)
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/cms/plu
gin_rendering.py", line 429, in render_plugin                                           
    context = plugin.render(context, instance, placeholder.slot)
  File "/home/user/sites/app-web/app/apps/plugins/cms_plugins.py", line 1
8, in render                                                                            
    authors_list = instance.get_authors_and_article_counts(request)
  File "/home/user/sites/app-web/app/apps/plugins/models.py", line 88, in
 get_authors_and_article_counts                                                         
    raw_authors = list(AuthorProfile.objects.raw(query))
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
db/models/query.py", line 1339, in __iter__                                             
    self._fetch_all()
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
db/models/query.py", line 1326, in _fetch_all                                           
    self._result_cache = list(self.iterator())
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/
db/models/query.py", line 1368, in iterator                                             
    setattr(instance, column, values[pos])
  File "/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/parler/
fields.py", line 161, in __set__                                                        
    raise AttributeError("The 'language_code' attribute cannot be changed directly! Use t
he set_current_language() method instead.")                                             
AttributeError: The 'language_code' attribute cannot be changed directly! Use the set_cur
rent_language() method instead.       

我做错了什么?问题出在raw_authors = list(AuthorProfile.objects.raw(query)) 吗?我是否应该做类似MyModel.objects.language('en'). ... 的事情,在更改查询以丢弃处理翻译的部分后通过 Parler 运行查询?正确的方法是什么?

【问题讨论】:

  • 你在使用django-translated-fields吗?为什么要标记django-translated-fields
  • @SpeedyMatch,我不知道那是什么。似乎它在这里是相关的,因为这个问题似乎与 Django 翻译字段有关。

标签: django translation django-cms django-parler django-translated-fields


【解决方案1】:

在我们继续解决之前,让我们讨论一下为什么会发生此错误。

我们可以使用 Model.objects.raw()直接执行自定义原始查询两种方式执行 django 原始查询。 当我们说:

  1. Model.objects.raw() ⇾ 它基本上执行原始查询并返回模型实例。
  2. 直接自定义原始查询 ⇾ 在这种情况下,您始终可以直接访问数据库,完全绕过模型层。

对于您的情况list(AuthorProfile.objects.raw(query)),在此期间它成功获取结果,但是当它尝试使model instance....时发生错误。

从您的回溯中:文件“/home/user/miniconda3/envs/app-web/lib/python3.7/site-packages/django/ db/models/query.py",第 1368 行,在迭代器中
setattr(instance, column, values[pos])

...因为这个实例不允许设置属性。 见下文codebase django-parler

class LanguageCodeDescriptor(object):
    ..... some code ....
    def __set__(self, instance, value):
        raise AttributeError("The 'language_code' attribute cannot be changed directly! Use the set_current_language() method instead.")
    ..... some code ....

回到你的答案。您可以采用多种方式。

  1. 只需从LanguageCodeDescriptor 方法__set__ 中删除异常即可。像这样在 django-parler 中进行更改当然不建议这样做。

  2. 我想考虑您的建议MyModel.objects.language('en')。您的查询似乎有点复杂,如果可能,请尝试使用ORM,如果不可能,请遵循第 3 点。

  3. 使用上面讨论的方法 2 执行原始查询,即直接自定义原始查询,

    from django.db import connection
    with connection.cursor() as cursor:
       cursor.execute(query, [published_clause, author_ids_tuple_str])
       rows = cursor.fetchall()    
    

注意:如果您使用方法 3,则无法像 author.article_count 这样访问 model_instance,因为此方法不返回模型实例。

更多详情可点击以下链接:

performing raw sql

django-parler codebase

【讨论】:

  • 谢谢。那么,看来选项3真的是我唯一的选择吗?如果不进行如此低级的抽象,就没有办法完成这项工作吗?
  • 我不太了解 django-parler 的详细信息,可能有一些方法可以有效地覆盖类方法(目前会引发 AttributeError)。您应该尝试选项 2 我认为原始查询可以转换为 ORM。查询中是否有不属于 ORM 的表?
  • 我认为所有使用的表格都直接与我拥有的特定模型或它们的翻译有关。查询中没有其他类型的表。我一直在试图弄清楚如何通过 ORM 进行查询:/
猜你喜欢
  • 2016-09-18
  • 1970-01-01
  • 2011-11-12
  • 2011-04-23
  • 2020-10-19
  • 2017-03-17
  • 2020-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多