django-cms / djangocms-frontend

django CMS frontend is a plugin bundle for django CMS providing several components for the frontend, currently implemented with the popular Bootstrap 5 framework.
Other
50 stars 21 forks source link

a plugin with this name ('LinkPlugin') is already registered #38

Closed jpVm5jYYRE1VIKL closed 2 years ago

jpVm5jYYRE1VIKL commented 2 years ago

Describe the bug Attempt to migrate from bs4 to frontend

  File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/usr/local/lib/python3.9/site-packages/djangocms_frontend/contrib/carousel/cms_plugins.py", line 10, in <module>
    from ..link.cms_plugins import LinkPluginMixin
  File "/usr/local/lib/python3.9/site-packages/djangocms_frontend/contrib/link/cms_plugins.py", line 89, in <module>
    class LinkPlugin(
  File "/usr/local/lib/python3.9/site-packages/cms/plugin_pool.py", line 117, in register_plugin
    raise PluginAlreadyRegistered(
cms.exceptions.PluginAlreadyRegistered: Cannot register <class 'djangocms_frontend.contrib.link.cms_plugins.LinkPlugin'>, a plugin with this name ('LinkPlugin') is already registered.

commenting in settings.py djangocms_link result :

  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/usr/local/lib/python3.9/site-packages/djangocms_bootstrap4/contrib/bootstrap4_carousel/models.py", line 9, in <module>
    from djangocms_link.models import AbstractLink
  File "/usr/local/lib/python3.9/site-packages/djangocms_link/models.py", line 268, in <module>
    class Link(AbstractLink):
  File "/usr/local/lib/python3.9/site-packages/cms/models/pluginmodel.py", line 78, in __new__
    new_class = super_new(cls, name, bases, attrs)
  File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 113, in __new__
    raise RuntimeError(
RuntimeError: Model class djangocms_link.models.Link doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

To Reproduce Steps to reproduce the behavior:

  1. install all needed modules
  2. Add djangocms_frontend .... modules to settings.py
  3. Keep bootstrap in settings.py like recommended in migration docs.

Expected behavior At least have to work

Additional context

beside this frontend also block execution of command python manage.py collectstatic --noinput So it is not possible anymore to build image with :

FROM python:3.9
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
RUN python manage.py collectstatic --noinput
CMD uwsgi --http=0.0.0.0:80 --module=backend.wsgi
fsbraun commented 2 years ago

@jpVm5jYYRE1VIKL Thanks for reporting this!

Indeed the documentation is not clear enough on it: The djangocms_frontend packages need to go after the djangocms_bootstrap4 packages. Djangocms_bootstrap4 depends on djangocms_link (which has to be before the djangocms_bootstrap4 packages). Hence, for you the order in settings.py should be

INSTALLED_APPS = [
    ...,
    "djangocms_link",
    "djangocms_bootstrap4",
    "djangocms_bootstrap4.contrib.bootstrap4_utilities",
    "djangocms_bootstrap4.contrib.bootstrap4_tabs",
    "djangocms_bootstrap4.contrib.bootstrap4_grid",
    "djangocms_bootstrap4.contrib.bootstrap4_alerts",
    "djangocms_bootstrap4.contrib.bootstrap4_card",
    "djangocms_bootstrap4.contrib.bootstrap4_listgroup",
    "djangocms_bootstrap4.contrib.bootstrap4_badge",
    "djangocms_bootstrap4.contrib.bootstrap4_link",
    "djangocms_bootstrap4.contrib.bootstrap4_collapse",
    "djangocms_bootstrap4.contrib.bootstrap4_content",
    "djangocms_bootstrap4.contrib.bootstrap4_media",
    "djangocms_bootstrap4.contrib.bootstrap4_jumbotron",
    "djangocms_bootstrap4.contrib.bootstrap4_picture",
    "djangocms_bootstrap4.contrib.bootstrap4_carousel",
    "djangocms_frontend",
    "djangocms_frontend.contrib.utilities",
    "djangocms_frontend.contrib.tabs",
    "djangocms_frontend.contrib.grid",
    "djangocms_frontend.contrib.alert",
    "djangocms_frontend.contrib.card",
    "djangocms_frontend.contrib.listgroup",
    "djangocms_frontend.contrib.badge",
    "djangocms_frontend.contrib.link",
    "djangocms_frontend.contrib.collapse",
    "djangocms_frontend.contrib.content",
    "djangocms_frontend.contrib.media",
    "djangocms_frontend.contrib.jumbotron",
    "djangocms_frontend.contrib.image",
    "djangocms_frontend.contrib.carousel",
    "djangocms_frontend.contrib.accordion",
    "djangocms_frontend.contrib.frontend_forms",
    ...,
]

After migrating, both the djangocms_link and the djangocms_bootstrap4 entries can go.

Let me know if reordering helped. I will update the docs.

jpVm5jYYRE1VIKL commented 2 years ago

Hi. Yes change of order helped a lot and image generated and passed. But most probably migration procedire have to be adjusted. My project widely use card decks due to it get :

Migrating plugins
=================
* Detected bootstrap v4 card-deck which is not part of bootstrap5
  Replaced it with Card Layout, grid cards
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "djangocms_frontend_frontenduiitem" does not exist
LINE 1: UPDATE "djangocms_frontend_frontenduiitem" SET "ui_item" = '...

may be advice how better to migrate. may be something semi automatic. I have more than hundred card decks. but i seen attempt to migrate but it failed . Most probably need to create another bug report about migration of card decks. It feels like migration try to make conversion and write data before table djangocms_frontend_frontenduiitem created.

fsbraun commented 2 years ago

Card decks have no 1:1 correspondence in Bootstrap 5 and need a special treatment. Sorry, no way around it.

From the bug it seems, however, that the frontend tables were not generated. Did you run ./manage.py migrate before ./manage frontend migrate? The first command creates the tables in the database.

fsbraun commented 2 years ago

Again, this is a good hint: ./manage.py frontend migrate might check if the database migrations have been run!

jpVm5jYYRE1VIKL commented 2 years ago

Yes you right . Also i presume have to be adjusted in docs . because in current moment only this steps :

./manage.py cms delete-orphaned-plugins
./manage.py frontend migrate

i presume need to be :

./manage.py cms delete-orphaned-plugins
./manage.py migrate
./manage.py frontend migrate

:) But still not passed

Now got after ./manage.py frontend migrate:

  File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 98, in execute
    return super().execute(sql, params)
  File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.9/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 82, in _execute
    return self.cursor.execute(sql)
django.db.utils.ProgrammingError: syntax error at or near "`"
LINE 1: DELETE FROM `bootstrap4_card_bootstrap4card` WHERE cmsplugin...

As i understand card-deck is just a "<div>" with class . I am i right that it have to just ignore card-deck class and exchange to simple div ?

fsbraun commented 2 years ago

What database are you using? This sql delete statement removes the migrated plugin from the database.

The migration process will create rows and columns that hold the cards. You will find a CardLayoutPlugin which you can change if you want.

jpVm5jYYRE1VIKL commented 2 years ago

I using postgres:9.6-alpine . I think that problem with opening and closing quote somewhere . This is statement pgre got : STATEMENT: DELETE FROM `bootstrap4_card_bootstrap4card` WHERE cmsplugin_ptr_id=5188; used ` but i think (i am not sure ) have to be " or '

fsbraun commented 2 years ago

OK, that's a bug I will need to fix. Postgresql does not accept backticks as quotes (like mysql, or sqlite). I have the following work around for you until I can fix the bug (your feedback would be valued). This involves patch a file called management/commands/subcommands/migrate.py, lines 97-98, specifically:

                cursor.execute(
                    f"DELETE FROM `{obj._meta.db_table}` WHERE cmsplugin_ptr_id={obj.id};"
                )

probably needs to become for postgresql:

                cursor.execute(
                    f'DELETE FROM "{obj._meta.db_table}" WHERE cmsplugin_ptr_id={obj.id};'
                )
fsbraun commented 2 years ago

Alternatively, you can try the hot fix by installing pip install git+https://github.com/fsbraun/djangocms-frontend@fix/migration#egg=djangocms-frontend .

jpVm5jYYRE1VIKL commented 2 years ago

I made it to work with this :


                with connection.cursor() as cursor:
                    cursor.execute(
                        f'DELETE FROM "{obj._meta.db_table}" WHERE cmsplugin_ptr_id={obj.id};'
                    )

changed general statement to singlequote and inside set doublequote.

fsbraun commented 2 years ago

Great! I will prepare a PR to fix this (depending on the database used). Did it run through now?

jpVm5jYYRE1VIKL commented 2 years ago

yes with code i showed it passed . Thanks for your help.

fsbraun commented 2 years ago

Pleasure! Thanks for pointing out these issues!

jpVm5jYYRE1VIKL commented 2 years ago

I looked on PR and I think that usage only " in statement will break something. I have feeling that python will generate syntax error because will detect it as two separate strings "DELETE FROM " and " WHERE cmsplugin_ptr_id={obj.id};'"

fsbraun commented 2 years ago

Of course, if you can, it'll be great if you could test it!

My expectation is that the f-string will be evaluated and a mysql-like command generated and stored as string. If a non-sql and non-sqlite database is present (presumably ansi compliant) the backticks are replaced by double quotes.

jpVm5jYYRE1VIKL commented 2 years ago

Yes i presume i was right :

  File "/app/djangocms_frontend/management/commands/frontend.py", line 5, in <module>
    from .subcommands.migrate import Migrate
  File "/app/djangocms_frontend/management/commands/subcommands/migrate.py", line 97
    f"DELETE FROM "{obj._meta.db_table}" WHERE cmsplugin_ptr_id={obj.id};"
                   ^
SyntaxError: invalid syntax

i tried to escape and it passed :

                with connection.cursor() as cursor:
                    cursor.execute(
                        f"DELETE FROM \"{obj._meta.db_table}\" WHERE cmsplugin_ptr_id={obj.id};"
                    )
                cnt += 1
fsbraun commented 2 years ago

Hold on, the PR should look like this: https://github.com/django-cms/djangocms-frontend/blob/07160bf04549395f3db9b56c4566f8e62af9e45d/djangocms_frontend/management/commands/subcommands/migrate.py#L95-L100 🤔

mysql needs the backtick (at least if it is not running in ansi mode which is not the standard).

jpVm5jYYRE1VIKL commented 2 years ago

Yes you right. Sorry.

fsbraun commented 2 years ago

It's always good to have at least two more eyes looking at the code! Thank you for your time!