8000 [BUG] Editing translations of pages using the language tabs inside PageContent creates an inconsistent state · Issue #8044 · django-cms/django-cms · GitHub
[go: up one dir, main page]

Skip to content
[BUG] Editing translations of pages using the language tabs inside PageContent creates an inconsistent state  #8044
Closed
@filipweidemann

Description

@filipweidemann

Description

Consider the following scenario: we got a multi-language site using the languages English (en) and German (de).

We currently got a page which only exists in the German (de) version. Therefore, we only have a published PageContent object for this page in German.

If we change the language switch inside the PageContent admin list view (the one on top, just beside the "Main Navigation" label) to English (en), we can see the title of the German Page with a "(de)" behind it. We can then click on the grey circle to create the english version of the page. This all works flawlessly.

However, suppose we have a page which is published in both versions. We now click on the page content settings on the German version and then use the language tab on top of the form to switch the language to English.
This results in an empty form without title, slug or anything that the already existing english version of this page provides. If we continue to fill out the form and save it, we can create an inconsistent state inside the DB because the PageUrl objects now return 2 results for the english page version.

If we look at the get_urls() method of this page, we can see that the English version now has 2 PageUrl objects:

<QuerySet [<PageUrl: english-testpage (en)>, <PageUrl: deutsche-testseite-translated (de)>, <PageUrl: adskjfhgdskjfhdsakjh (en)>]>

If we then select the language with 2 PageUrl objects in the PageContent list view and try to edit it, we get an error:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/contrib/admin/options.py", line 688, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/utils/decorators.py", line 134, in _wrapper_view
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/views/decorators/cache.py", line 62, in _wrapper_view_func
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/contrib/admin/sites.py", line 242, in inner
    return view(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/cms/admin/pageadmin.py", line 981, in change_view
    return super().change_view(request, object_id, form_url=form_url, extra_context=context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/contrib/admin/options.py", line 1889, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/utils/decorators.py", line 46, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/utils/decorators.py", line 134, in _wrapper_view
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/contrib/admin/options.py", line 1747, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/contrib/admin/options.py", line 1819, in _changeform_view
    form = ModelForm(instance=obj)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/cms/admin/forms.py", line 578, in __init__
    self.url_obj = self.instance.page.get_url(self._language)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/cms/models/pagemodel.py", line 782, in get_url
    return self.get_urls().get(language=language)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/django/db/models/query.py", line 640, in get
    raise self.model.MultipleObjectsReturned(
    ^

Exception Type: MultipleObjectsReturned at /de/admin/cms/pagecontent/362/change/
Exception Value: get() returned more than one PageUrl -- it returned 2!

This is really unexpected because we get an explicit option to edit page contents in more than one way and depending on which way you choose you may end up destroying the integrity of your pages.

Steps to reproduce

Follow the steps above.

Expected behaviour

Page Content always get correctly fetched and edited without destroying the consistency of the DB

Actual behaviour

See above.

Screenshots

Not really applicable, the reproduction is too complex to convey through screenshots.

Additional information (CMS/Python/Django versions)

Python 3.11
Django 4.2
djangoCMS 4.1.3

Do you want to help fix this issue?

Imo, this can only be resolved in two ways:

  1. fix the edit view of page content objects so that using the tab select correctly fetches existing page information and edits it as expected (just the way it did in djangoCMS 3) or
  2. completely disable the tab selectors inside the page content edit view so that you NEED to use the languag 5CB2 e select inside the list view.

I know this may seem hard to fathom and especially hard to reproduce, so if anyone needs clarification or a short demo I am always available to hop on a quick Discord call.

So yes, I'd like to help but I can't really dig through djangoCMS internals right now and create a PR. Always happy to review them by testing however :)

  • Yes, I want to help fix this issue and I will join the channel #pr-reviews on the Discord Server to confirm with the community that a PR is welcome.
  • No, I only want to report the issue.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0