I am currently extending a plugin to play well with Django translations and languages. Here is the method in question. Prior to getting translations involved, it worked as needed.
I extended the query to pull data from a couple of translation tables. However, I am getting an error, which I am unsure how to deal with.
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)
The traceback:
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.
What am I doing wrong? Is the problem here raw_authors = list(AuthorProfile.objects.raw(query))
? Should I be doing something like MyModel.objects.language('en'). ...
, run the query via Parler after changing the query to discard the parts dealing with translations? What is the proper way?
Before we moving on to solution let's discuss why this error happened.
We can perform django raw query in 2 ways either using
Model.objects.raw()
or execute custom raw query directly. When we say:Model.objects.raw()
⇾ it basically perform raw queries and return model instances.For your case
list(AuthorProfile.objects.raw(query))
during this it fetch result successfully but the error happens when it tries to makemodel instance
....From your traceback: 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])
...because this instance doesn't allow to set the attribute. see below codebase of django-parler
Coming back to your answer. There are couple of ways you can follow.
Just remove the exception from
LanguageCodeDescriptor
method__set__
. changes in django-parler like this of course this is not recommended.I would like to consider your suggestion
MyModel.objects.language('en')
. your query seems little bit more complex try to useORM
if possible, if not possible just follow points 3.Execute raw query using method 2 from discussed above i.e directly custom raw query,
NOTE: if you use method 3 then you can not access model_instance like this
author.article_count
since this method doesn't return model instance.The following links can be followed for more details:
performing raw sql
django-parler codebase