Django Parler "Атрибут 'language_code' нельзя изменить напрямую
В настоящее время я расширяю плагин, чтобы он хорошо работал с переводами и языками 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 после изменения запроса, чтобы отбросить части, связанные с переводами? Каков правильный путь?
1 ответ
Прежде чем перейти к решению, давайте обсудим, почему произошла эта ошибка.
Мы можем выполнить необработанный запрос django двумя способами: Model.objects.raw()
или выполнить пользовательский необработанный запрос напрямую. Когда мы говорим:
Model.objects.raw()
⇾ он в основном выполняет необработанные запросы и возвращает экземпляры модели.- непосредственно настраиваемый необработанный запрос ⇾ В этом случае вы всегда можете получить прямой доступ к базе данных, полностью обходя слой модели.
Для вашего случая 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])
... потому что этот экземпляр не позволяет установить атрибут. см. ниже кодовую базу 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 ....
Возвращаясь к вашему ответу. Есть несколько способов, которым вы можете следовать.
Просто удалите исключение из
LanguageCodeDescriptor
метод__set__
. такие изменения в django-parler, конечно, не рекомендуются.Я хотел бы рассмотреть ваше предложение
MyModel.objects.language('en')
. ваш запрос кажется немного сложнее, попробуйте использоватьORM
если возможно, если невозможно, просто следуйте пунктам 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, вы не можете получить доступ к model_instance, как этоauthor.article_count
поскольку этот метод не возвращает экземпляр модели.
Для получения более подробной информации перейдите по следующим ссылкам: