From ffa5c0efaaab138d04f6a704cae767ab2a5f22d8 Mon Sep 17 00:00:00 2001 From: Mara Karagianni Date: Tue, 7 Nov 2023 17:41:27 +0200 Subject: [PATCH 1/9] deps: remove django-background-tasks --- changelog/7805.md | 3 +++ requirements/base.txt | 1 - tests/project/settings.py | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelog/7805.md diff --git a/changelog/7805.md b/changelog/7805.md new file mode 100644 index 000000000..d6ecaa383 --- /dev/null +++ b/changelog/7805.md @@ -0,0 +1,3 @@ +### Removed + +- django-background-tasks from settings and requirements diff --git a/requirements/base.txt b/requirements/base.txt index 970e7aa17..1deb755ba 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -3,7 +3,6 @@ bleach[css]==6.0.0 Django==3.2.20 django-allauth==0.54.0 git+https://github.com/liqd/django-autoslug.git@liqd2212#egg=django-autoslug -django-background-tasks==1.2.5 https://github.com/liqd/django-ckeditor-5/releases/download/v0.2.11-liqd/django_ckeditor_5-0.2.11-py3-none-any.whl django-ckeditor==6.6.1 django-enumfield==3.1 diff --git a/tests/project/settings.py b/tests/project/settings.py index 7a149fb7c..cf96edcce 100644 --- a/tests/project/settings.py +++ b/tests/project/settings.py @@ -60,7 +60,6 @@ # mandatory third party apps "easy_thumbnails", "rules.apps.AutodiscoverRulesConfig", - "background_task", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", From 289ac0ca93534cbd429827794b4dd98b7a428e55 Mon Sep 17 00:00:00 2001 From: Mara Karagianni Date: Tue, 7 Nov 2023 18:33:54 +0200 Subject: [PATCH 2/9] deps: django upgrade to 4.0 --- .../0003_alter_areasettings_module.py | 23 +++++++++++++++ .../0008_alter_module_blueprint_type.py | 20 +++++++++++++ .../migrations/0042_alter_project_topics.py | 28 +++++++++++++++++++ changelog/7776.md | 4 +++ requirements/base.txt | 2 +- .../migrations/0007_alter_idea_labels.py | 20 +++++++++++++ tests/project/urls.py | 4 +-- 7 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 adhocracy4/maps/migrations/0003_alter_areasettings_module.py create mode 100644 adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py create mode 100644 adhocracy4/projects/migrations/0042_alter_project_topics.py create mode 100644 changelog/7776.md create mode 100644 tests/apps/ideas/migrations/0007_alter_idea_labels.py diff --git a/adhocracy4/maps/migrations/0003_alter_areasettings_module.py b/adhocracy4/maps/migrations/0003_alter_areasettings_module.py new file mode 100644 index 000000000..bef9c6116 --- /dev/null +++ b/adhocracy4/maps/migrations/0003_alter_areasettings_module.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0 on 2023-11-07 15:26 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("a4modules", "0008_alter_module_blueprint_type"), + ("a4maps", "0002_change_help_text"), + ] + + operations = [ + migrations.AlterField( + model_name="areasettings", + name="module", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(class)s_settings", + to="a4modules.module", + ), + ), + ] diff --git a/adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py b/adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py new file mode 100644 index 000000000..ad2f49fe8 --- /dev/null +++ b/adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0 on 2023-11-07 15:26 + +import adhocracy4.modules.fields +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("a4modules", "0007_verbose_name_created_modified"), + ] + + operations = [ + migrations.AlterField( + model_name="module", + name="blueprint_type", + field=adhocracy4.modules.fields.BlueprintTypeField( + blank=True, choices=[], max_length=255 + ), + ), + ] diff --git a/adhocracy4/projects/migrations/0042_alter_project_topics.py b/adhocracy4/projects/migrations/0042_alter_project_topics.py new file mode 100644 index 000000000..fc24e64b3 --- /dev/null +++ b/adhocracy4/projects/migrations/0042_alter_project_topics.py @@ -0,0 +1,28 @@ +# Generated by Django 4.0 on 2023-11-07 15:26 + +import adhocracy4.projects.fields +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("a4projects", "0041_ckeditor5_iframes"), + ] + + operations = [ + migrations.AlterField( + model_name="project", + name="topics", + field=adhocracy4.projects.fields.TopicField( + choices=[ + ("ANT", "Anti-discrimination"), + ("WOR", "Work & economy"), + ("BUI", "Building & living"), + ], + default="", + help_text="Add topics to your project.", + max_length=254, + verbose_name="Project topics", + ), + ), + ] diff --git a/changelog/7776.md b/changelog/7776.md new file mode 100644 index 000000000..d1023b3c9 --- /dev/null +++ b/changelog/7776.md @@ -0,0 +1,4 @@ +### Upgraded + +- Django from 3.2.20 to 4.0 + - added migrations for max_length diff --git a/requirements/base.txt b/requirements/base.txt index 1deb755ba..bfcad0f68 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,6 +1,6 @@ beautifulsoup4==4.12.2 bleach[css]==6.0.0 -Django==3.2.20 +Django==4.0 django-allauth==0.54.0 git+https://github.com/liqd/django-autoslug.git@liqd2212#egg=django-autoslug https://github.com/liqd/django-ckeditor-5/releases/download/v0.2.11-liqd/django_ckeditor_5-0.2.11-py3-none-any.whl diff --git a/tests/apps/ideas/migrations/0007_alter_idea_labels.py b/tests/apps/ideas/migrations/0007_alter_idea_labels.py new file mode 100644 index 000000000..f422753fd --- /dev/null +++ b/tests/apps/ideas/migrations/0007_alter_idea_labels.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0 on 2023-11-07 15:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("a4labels", "0003_labelalias"), + ("a4test_ideas", "0006_alter_idea_description"), + ] + + operations = [ + migrations.AlterField( + model_name="idea", + name="labels", + field=models.ManyToManyField( + related_name="%(app_label)s_%(class)s_label", to="a4labels.Label" + ), + ), + ] diff --git a/tests/project/urls.py b/tests/project/urls.py index f91cde19a..189862938 100644 --- a/tests/project/urls.py +++ b/tests/project/urls.py @@ -1,5 +1,5 @@ from django.contrib import admin -from django.contrib.auth import views +from django.contrib.auth.views import LoginView from django.urls import include from django.urls import path from rest_framework import routers @@ -31,6 +31,6 @@ path("admin/", admin.site.urls), path("projects/", include(prj_urls)), path("modules/", include(mod_urls)), - path("accounts/login", views.LoginView, name="account_login"), + path("accounts/login", LoginView.as_view(), name="account_login"), path("dashboard/", include(dashboard_urls)), ] From 98fce3cad5b7466131b0ce8b280e37f5d0c62d83 Mon Sep 17 00:00:00 2001 From: Mara Karagianni Date: Wed, 8 Nov 2023 14:36:08 +0200 Subject: [PATCH 3/9] deps: django-allauth upgrade to 0.55.0 --- changelog/7776.md | 4 ++++ requirements/base.txt | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/changelog/7776.md b/changelog/7776.md index d1023b3c9..7cacf7e69 100644 --- a/changelog/7776.md +++ b/changelog/7776.md @@ -2,3 +2,7 @@ - Django from 3.2.20 to 4.0 - added migrations for max_length + +- Django-allauth from 0.54.0 to 0.55.0 to be compatible with django 4.2 + unique email is now only a constrain if it is already verified. + This takes place if ACCOUNT_UNIQUE_EMAIL is enabled in the settings diff --git a/requirements/base.txt b/requirements/base.txt index bfcad0f68..8b0e989be 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,7 +1,7 @@ beautifulsoup4==4.12.2 bleach[css]==6.0.0 Django==4.0 -django-allauth==0.54.0 +django-allauth==0.55.0 git+https://github.com/liqd/django-autoslug.git@liqd2212#egg=django-autoslug https://github.com/liqd/django-ckeditor-5/releases/download/v0.2.11-liqd/django_ckeditor_5-0.2.11-py3-none-any.whl django-ckeditor==6.6.1 From 738623d0f17e2a71ec9c279ad958c65a4fadb231 Mon Sep 17 00:00:00 2001 From: Mara Karagianni Date: Wed, 8 Nov 2023 17:41:03 +0200 Subject: [PATCH 4/9] deps: django upgrade to 4.1 --- adhocracy4/polls/models.py | 4 ++-- changelog/7776.md | 3 +++ requirements/base.txt | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/adhocracy4/polls/models.py b/adhocracy4/polls/models.py index 60e148d7b..7528d8fd2 100644 --- a/adhocracy4/polls/models.py +++ b/adhocracy4/polls/models.py @@ -70,7 +70,7 @@ def clean(self, *args, **kwargs): ) } ) - elif self.choices.count() > 0: + elif Choice.objects.filter(question=self.pk).count() > 0: raise ValidationError( { "is_open": _( @@ -227,7 +227,7 @@ def save(self, *args, **kwargs): return super().save(*args, **kwargs) def validate_unique(self, exclude=None): - super(Vote, self).validate_unique(exclude) + super().validate_unique(exclude) validators.single_vote_per_user(self.creator, self.choice, self.pk) @property diff --git a/changelog/7776.md b/changelog/7776.md index 7cacf7e69..a302b4ff0 100644 --- a/changelog/7776.md +++ b/changelog/7776.md @@ -6,3 +6,6 @@ - Django-allauth from 0.54.0 to 0.55.0 to be compatible with django 4.2 unique email is now only a constrain if it is already verified. This takes place if ACCOUNT_UNIQUE_EMAIL is enabled in the settings + +- Django from 4.0 to 4.1 + Reverse relations need to be saved before being called from the object they relate diff --git a/requirements/base.txt b/requirements/base.txt index 8b0e989be..d2ade7635 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,6 +1,6 @@ beautifulsoup4==4.12.2 bleach[css]==6.0.0 -Django==4.0 +Django==4.1 django-allauth==0.55.0 git+https://github.com/liqd/django-autoslug.git@liqd2212#egg=django-autoslug https://github.com/liqd/django-ckeditor-5/releases/download/v0.2.11-liqd/django_ckeditor_5-0.2.11-py3-none-any.whl From 3434eecae3423dd7e3672527f9bdfcbf4249ac73 Mon Sep 17 00:00:00 2001 From: Mara Karagianni Date: Wed, 8 Nov 2023 18:04:03 +0200 Subject: [PATCH 5/9] deps, models, views: django upgrade to 4.2 --- ..._object_id_a4actions_a_obj_con_ee317e_idx.py | 17 +++++++++++++++++ adhocracy4/actions/models.py | 2 +- ..._object_pk_a4comments__content_ff606b_idx.py | 17 +++++++++++++++++ adhocracy4/comments/models.py | 13 ++++++++++--- adhocracy4/dashboard/views.py | 2 +- adhocracy4/models/base.py | 6 ++++-- adhocracy4/projects/models.py | 10 ++++++++-- ..._object_pk_a4ratings_r_content_8fb00e_idx.py | 17 +++++++++++++++++ adhocracy4/ratings/models.py | 4 +--- ..._object_pk_a4reports_r_content_75c7cc_idx.py | 17 +++++++++++++++++ adhocracy4/reports/models.py | 3 +-- changelog/7776.md | 4 ++++ requirements/base.txt | 2 +- tests/project/settings.py | 2 -- 14 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 adhocracy4/actions/migrations/0009_rename_action_obj_content_type_obj_object_id_a4actions_a_obj_con_ee317e_idx.py create mode 100644 adhocracy4/comments/migrations/0014_rename_comment_content_type_object_pk_a4comments__content_ff606b_idx.py create mode 100644 adhocracy4/ratings/migrations/0005_rename_rating_content_type_object_pk_a4ratings_r_content_8fb00e_idx.py create mode 100644 adhocracy4/reports/migrations/0004_rename_report_content_type_object_pk_a4reports_r_content_75c7cc_idx.py diff --git a/adhocracy4/actions/migrations/0009_rename_action_obj_content_type_obj_object_id_a4actions_a_obj_con_ee317e_idx.py b/adhocracy4/actions/migrations/0009_rename_action_obj_content_type_obj_object_id_a4actions_a_obj_con_ee317e_idx.py new file mode 100644 index 000000000..e125e70f3 --- /dev/null +++ b/adhocracy4/actions/migrations/0009_rename_action_obj_content_type_obj_object_id_a4actions_a_obj_con_ee317e_idx.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-11-27 12:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("a4actions", "0008_set_action_obj_comment_creator"), + ] + + operations = [ + migrations.RenameIndex( + model_name="action", + new_name="a4actions_a_obj_con_ee317e_idx", + old_fields=("obj_content_type", "obj_object_id"), + ), + ] diff --git a/adhocracy4/actions/models.py b/adhocracy4/actions/models.py index cba0a3774..c8b9f7517 100644 --- a/adhocracy4/actions/models.py +++ b/adhocracy4/actions/models.py @@ -99,7 +99,7 @@ class Action(models.Model): class Meta: ordering = ("-timestamp",) - index_together = [("obj_content_type", "obj_object_id")] + indexes = [models.Index(fields=["obj_content_type", "obj_object_id"])] def __str__(self): ctx = { diff --git a/adhocracy4/comments/migrations/0014_rename_comment_content_type_object_pk_a4comments__content_ff606b_idx.py b/adhocracy4/comments/migrations/0014_rename_comment_content_type_object_pk_a4comments__content_ff606b_idx.py new file mode 100644 index 000000000..69cd7deaa --- /dev/null +++ b/adhocracy4/comments/migrations/0014_rename_comment_content_type_object_pk_a4comments__content_ff606b_idx.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-11-27 12:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("a4comments", "0013_set_project"), + ] + + operations = [ + migrations.RenameIndex( + model_name="comment", + new_name="a4comments__content_ff606b_idx", + old_fields=("content_type", "object_pk"), + ), + ] diff --git a/adhocracy4/comments/models.py b/adhocracy4/comments/models.py index 0db6c39dd..507a85023 100644 --- a/adhocracy4/comments/models.py +++ b/adhocracy4/comments/models.py @@ -47,7 +47,7 @@ class Meta: verbose_name = pgettext_lazy("noun", "Comment") verbose_name_plural = _("Comments") ordering = ("created",) - index_together = [("content_type", "object_pk")] + indexes = [models.Index(fields=["content_type", "object_pk"])] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -60,17 +60,24 @@ def __str__(self): else: return "{}".format(self.comment) - def save(self, *args, **kwargs): + def save(self, update_fields=None, *args, **kwargs): """Change comment.comment if comment was marked removed or censored.""" self.comment = transforms.clean_html_all(self.comment) + update_project = False if not self.project: self.project = self.content_object.module.project + update_project = True if self.is_removed or self.is_censored: self.comment = self._former_comment = "" self.comment_categories = "" - super(Comment, self).save(*args, **kwargs) + if update_fields: + update_fields = {"comment"}.union(update_fields) + if update_project: + update_fields = {"project"}.union(update_fields) + + super().save(update_fields=update_fields, *args, **kwargs) def get_absolute_url(self): if hasattr(self.content_object, "get_absolute_url"): diff --git a/adhocracy4/dashboard/views.py b/adhocracy4/dashboard/views.py index a3b5bfd1c..8b1d2b524 100644 --- a/adhocracy4/dashboard/views.py +++ b/adhocracy4/dashboard/views.py @@ -168,7 +168,7 @@ def post(self, request, *args, **kwargs): def get_next(self): if "referrer" in self.request.POST: return self.request.POST["referrer"] - elif "HTTP_REFERER" in self.request.META: + elif "referer" in self.request.headers: return self.request.headers["Referer"] return reverse( diff --git a/adhocracy4/models/base.py b/adhocracy4/models/base.py index f376aa1b4..3c166f5bc 100644 --- a/adhocracy4/models/base.py +++ b/adhocracy4/models/base.py @@ -20,10 +20,12 @@ class TimeStampedModel(models.Model): class Meta: abstract = True - def save(self, ignore_modified=False, *args, **kwargs): + def save(self, ignore_modified=False, update_fields=None, *args, **kwargs): if self.pk is not None and not ignore_modified: self.modified = timezone.now() - super(TimeStampedModel, self).save(*args, **kwargs) + if update_fields: + update_fields = {"modified"}.union(update_fields) + super().save(update_fields=update_fields, *args, **kwargs) class UserGeneratedContentModel(TimeStampedModel): diff --git a/adhocracy4/projects/models.py b/adhocracy4/projects/models.py index 6fbf92c11..f227c447c 100644 --- a/adhocracy4/projects/models.py +++ b/adhocracy4/projects/models.py @@ -279,7 +279,7 @@ def __str__(self): def get_absolute_url(self): return reverse("project-detail", kwargs=dict(slug=self.slug)) - def save(self, *args, **kwargs): + def save(self, update_fields=None, *args, **kwargs): self.information = html_transforms.clean_html_field( self.information, "collapsible-image-editor" ) @@ -289,7 +289,13 @@ def save(self, *args, **kwargs): if self.pk is None: project_type = "{}.{}".format(self._meta.app_label, self.__class__.__name__) self.project_type = project_type - super(Project, self).save(*args, **kwargs) + + if update_fields: + update_fields = {"information", "result"}.union(update_fields) + if self.pk is None: + update_fields = {"project_type"}.union(update_fields) + + super().save(update_fields=update_fields, *args, **kwargs) # functions needed to determine permissions def has_member(self, user): diff --git a/adhocracy4/ratings/migrations/0005_rename_rating_content_type_object_pk_a4ratings_r_content_8fb00e_idx.py b/adhocracy4/ratings/migrations/0005_rename_rating_content_type_object_pk_a4ratings_r_content_8fb00e_idx.py new file mode 100644 index 000000000..0e2aa7aa8 --- /dev/null +++ b/adhocracy4/ratings/migrations/0005_rename_rating_content_type_object_pk_a4ratings_r_content_8fb00e_idx.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-11-27 12:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("a4ratings", "0004_verbose_name_created_modified"), + ] + + operations = [ + migrations.RenameIndex( + model_name="rating", + new_name="a4ratings_r_content_8fb00e_idx", + old_fields=("content_type", "object_pk"), + ), + ] diff --git a/adhocracy4/ratings/models.py b/adhocracy4/ratings/models.py index d711cb624..e9a16d3f6 100644 --- a/adhocracy4/ratings/models.py +++ b/adhocracy4/ratings/models.py @@ -7,7 +7,6 @@ class Rating(UserGeneratedContentModel): - POSITIVE = 1 NEGATIVE = -1 @@ -18,7 +17,7 @@ class Rating(UserGeneratedContentModel): class Meta: unique_together = ("content_type", "object_pk", "creator") - index_together = [("content_type", "object_pk")] + indexes = [models.Index(fields=["content_type", "object_pk"])] def __str__(self): return str(self.value) @@ -46,7 +45,6 @@ def _get_value(self, number): return number def get_meta_info(self, user): - ratings = Rating.objects.filter( content_type=self.content_type, object_pk=self.object_pk ) diff --git a/adhocracy4/reports/migrations/0004_rename_report_content_type_object_pk_a4reports_r_content_75c7cc_idx.py b/adhocracy4/reports/migrations/0004_rename_report_content_type_object_pk_a4reports_r_content_75c7cc_idx.py new file mode 100644 index 000000000..40728eab1 --- /dev/null +++ b/adhocracy4/reports/migrations/0004_rename_report_content_type_object_pk_a4reports_r_content_75c7cc_idx.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-11-27 12:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("a4reports", "0003_verbose_name_created_modified"), + ] + + operations = [ + migrations.RenameIndex( + model_name="report", + new_name="a4reports_r_content_75c7cc_idx", + old_fields=("content_type", "object_pk"), + ), + ] diff --git a/adhocracy4/reports/models.py b/adhocracy4/reports/models.py index c1c6aed4b..0376e086c 100644 --- a/adhocracy4/reports/models.py +++ b/adhocracy4/reports/models.py @@ -6,7 +6,6 @@ class Report(base.UserGeneratedContentModel): - content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_pk = models.PositiveIntegerField() content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk") @@ -16,7 +15,7 @@ def __str__(self): return "{}_{}".format(str(self.content_type), str(self.object_pk)) class Meta: - index_together = [("content_type", "object_pk")] + indexes = [models.Index(fields=["content_type", "object_pk"])] @property def project(self): diff --git a/changelog/7776.md b/changelog/7776.md index a302b4ff0..9be8f93ea 100644 --- a/changelog/7776.md +++ b/changelog/7776.md @@ -9,3 +9,7 @@ - Django from 4.0 to 4.1 Reverse relations need to be saved before being called from the object they relate + +- Django from 4.1 to 4.2 + any fields modified in the custom save() methods should be added to the update_fields keyword argument before calling super() + retrieve referer in requests from headers instead of META diff --git a/requirements/base.txt b/requirements/base.txt index d2ade7635..0a240e100 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,6 +1,6 @@ beautifulsoup4==4.12.2 bleach[css]==6.0.0 -Django==4.1 +Django==4.2 django-allauth==0.55.0 git+https://github.com/liqd/django-autoslug.git@liqd2212#egg=django-autoslug https://github.com/liqd/django-ckeditor-5/releases/download/v0.2.11-liqd/django_ckeditor_5-0.2.11-py3-none-any.whl diff --git a/tests/project/settings.py b/tests/project/settings.py index cf96edcce..ccd3dbe02 100644 --- a/tests/project/settings.py +++ b/tests/project/settings.py @@ -134,8 +134,6 @@ USE_I18N = True -USE_L10N = True - USE_TZ = True From af1392c7d248032c8f50f84e76e7d450162c02d6 Mon Sep 17 00:00:00 2001 From: Mara Karagianni Date: Wed, 8 Nov 2023 18:07:03 +0200 Subject: [PATCH 6/9] deps: upgrade psycopg to 3.1.12 --- changelog/0003.md | 3 +++ requirements/dev.txt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changelog/0003.md diff --git a/changelog/0003.md b/changelog/0003.md new file mode 100644 index 000000000..8c2823971 --- /dev/null +++ b/changelog/0003.md @@ -0,0 +1,3 @@ +### Upgraded + +- psycopg to 3.1.12 diff --git a/requirements/dev.txt b/requirements/dev.txt index ed70f751c..4068ac538 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -5,7 +5,7 @@ Faker==19.1.0 flake8==6.0.0 freezegun==1.2.2 isort==5.12.0 -psycopg2-binary==2.9.6 +psycopg[binary]==3.1.12 pytest==7.4.0 pytest-cov==4.1.0 pytest-django==4.5.2 From dfd5391180d0255522d0f914b190ead8e795edc9 Mon Sep 17 00:00:00 2001 From: Julian Dehm Date: Tue, 28 Nov 2023 14:54:23 +0100 Subject: [PATCH 7/9] apps/modules: change module blueprint_type to char --- Makefile | 4 --- .../0003_alter_areasettings_module.py | 2 +- adhocracy4/modules/admin.py | 1 + .../0008_alter_module_blueprint_type.py | 9 ++---- adhocracy4/modules/models.py | 4 +-- .../migrations/0042_alter_project_topics.py | 28 ------------------- changelog/0005.md | 3 ++ 7 files changed, 9 insertions(+), 42 deletions(-) delete mode 100644 adhocracy4/projects/migrations/0042_alter_project_topics.py create mode 100644 changelog/0005.md diff --git a/Makefile b/Makefile index 1738dc9d6..795d61e94 100644 --- a/Makefile +++ b/Makefile @@ -45,15 +45,11 @@ lint: $(VIRTUAL_ENV)/bin/isort --diff -c $(SOURCE_DIRS) || EXIT_STATUS=$$?; \ $(VIRTUAL_ENV)/bin/flake8 $(SOURCE_DIRS) --exclude migrations,settings || EXIT_STATUS=$$?; \ npm run lint || EXIT_STATUS=$$?; \ - $(VIRTUAL_ENV)/bin/python manage.py makemigrations --dry-run --check --noinput || EXIT_STATUS=$$?; \ - exit $${EXIT_STATUS} .PHONY: lint-quick lint-quick: EXIT_STATUS=0; \ npm run lint-staged || EXIT_STATUS=$$?; \ - $(VIRTUAL_ENV)/bin/python manage.py makemigrations --dry-run --check --noinput || EXIT_STATUS=$$?; \ - exit $${EXIT_STATUS} .PHONY: lint-python-files lint-python-files: diff --git a/adhocracy4/maps/migrations/0003_alter_areasettings_module.py b/adhocracy4/maps/migrations/0003_alter_areasettings_module.py index bef9c6116..c11a987d8 100644 --- a/adhocracy4/maps/migrations/0003_alter_areasettings_module.py +++ b/adhocracy4/maps/migrations/0003_alter_areasettings_module.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0 on 2023-11-07 15:26 +# Generated by Django 4.2 on 2023-11-29 12:49 from django.db import migrations, models import django.db.models.deletion diff --git a/adhocracy4/modules/admin.py b/adhocracy4/modules/admin.py index df5af5e79..107d29cd8 100644 --- a/adhocracy4/modules/admin.py +++ b/adhocracy4/modules/admin.py @@ -24,6 +24,7 @@ class ItemAdmin(admin.ModelAdmin): class ModuleAdmin(admin.ModelAdmin): inlines = [phase_admin.PhaseInline] + search_fields = ["name"] list_filter = ("project__organisation", "project") list_display = ("__str__", "name") if hasattr(settings, "A4_BLUEPRINT_TYPES"): diff --git a/adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py b/adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py index ad2f49fe8..5806a7588 100644 --- a/adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py +++ b/adhocracy4/modules/migrations/0008_alter_module_blueprint_type.py @@ -1,7 +1,6 @@ -# Generated by Django 4.0 on 2023-11-07 15:26 +# Generated by Django 4.2 on 2023-11-29 12:49 -import adhocracy4.modules.fields -from django.db import migrations +from django.db import migrations, models class Migration(migrations.Migration): @@ -13,8 +12,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="module", name="blueprint_type", - field=adhocracy4.modules.fields.BlueprintTypeField( - blank=True, choices=[], max_length=255 - ), + field=models.CharField(blank=True, max_length=255), ), ] diff --git a/adhocracy4/modules/models.py b/adhocracy4/modules/models.py index cd93ce601..c5d559bb0 100644 --- a/adhocracy4/modules/models.py +++ b/adhocracy4/modules/models.py @@ -11,8 +11,6 @@ from adhocracy4.models import base from adhocracy4.projects import models as project_models -from .fields import BlueprintTypeField - class ModulesQuerySet(models.QuerySet): def annotate_module_start(self): @@ -95,7 +93,7 @@ class Module(models.Model): objects = ModulesQuerySet.as_manager() - blueprint_type = BlueprintTypeField( + blueprint_type = models.CharField( max_length=255, blank=True, ) diff --git a/adhocracy4/projects/migrations/0042_alter_project_topics.py b/adhocracy4/projects/migrations/0042_alter_project_topics.py deleted file mode 100644 index fc24e64b3..000000000 --- a/adhocracy4/projects/migrations/0042_alter_project_topics.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 4.0 on 2023-11-07 15:26 - -import adhocracy4.projects.fields -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("a4projects", "0041_ckeditor5_iframes"), - ] - - operations = [ - migrations.AlterField( - model_name="project", - name="topics", - field=adhocracy4.projects.fields.TopicField( - choices=[ - ("ANT", "Anti-discrimination"), - ("WOR", "Work & economy"), - ("BUI", "Building & living"), - ], - default="", - help_text="Add topics to your project.", - max_length=254, - verbose_name="Project topics", - ), - ), - ] diff --git a/changelog/0005.md b/changelog/0005.md new file mode 100644 index 000000000..a6e5dd221 --- /dev/null +++ b/changelog/0005.md @@ -0,0 +1,3 @@ +### Changed + +- apps/modules: change blueprint_type to char field (was creating migrations in forked projects after django upgrade to 4.x) From 8bb42e30735eaec2dd04dc6296d0238c18200bd3 Mon Sep 17 00:00:00 2001 From: Julian Dehm Date: Wed, 29 Nov 2023 10:49:58 +0100 Subject: [PATCH 8/9] apps/categories: change category choice field --- adhocracy4/categories/fields.py | 6 ---- adhocracy4/categories/form_fields.py | 42 ++++------------------------ adhocracy4/categories/forms.py | 2 ++ adhocracy4/categories/models.py | 10 ------- changelog/0006.md | 4 +++ 5 files changed, 12 insertions(+), 52 deletions(-) create mode 100644 changelog/0006.md diff --git a/adhocracy4/categories/fields.py b/adhocracy4/categories/fields.py index ead5b081f..16d4de246 100644 --- a/adhocracy4/categories/fields.py +++ b/adhocracy4/categories/fields.py @@ -1,7 +1,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from adhocracy4.categories.form_fields import CategoryChoiceField from adhocracy4.categories.models import Category @@ -17,8 +16,3 @@ def __init__(self, *args, **kwargs): } defaults.update(kwargs) super().__init__(**defaults) - - def formfield(self, **kwargs): - form_class = kwargs.get("form_class", CategoryChoiceField) - kwargs["form_class"] = form_class - return super().formfield(**kwargs) diff --git a/adhocracy4/categories/form_fields.py b/adhocracy4/categories/form_fields.py index 05251c66a..08c53a587 100644 --- a/adhocracy4/categories/form_fields.py +++ b/adhocracy4/categories/form_fields.py @@ -1,34 +1,10 @@ -from collections import abc - from django import forms +from django.conf import settings from django.forms import widgets -from django.utils.functional import cached_property from adhocracy4.categories import get_category_icon_url -class CategoryIconDict(abc.Mapping): - def __init__(self, field): - self.field = field - self.queryset = field.queryset - - @cached_property - def _icons(self): - return { - self.field.prepare_value(obj): getattr(obj, "icon", None) - for obj in self.queryset.all() - } - - def __getitem__(self, key): - return self._icons.__getitem__(key) - - def __iter__(self): - return self._icons.__iter__() - - def __len__(self): - return self._icons.__len__() - - class CategorySelectWidget(widgets.Select): def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) @@ -40,30 +16,24 @@ def get_context(self, name, value, attrs): def create_option(self, name, value, label, selected, index, **kwargs): option = super().create_option(name, value, label, selected, index, **kwargs) - if hasattr(value, "value") and value.value in self.icons: - icon_url = get_category_icon_url(self.icons[value.value]) + if value in self.icons: + icon_url = get_category_icon_url(value) option["attrs"]["data-icon-src"] = icon_url return option -class CategoryChoiceField(forms.ModelChoiceField): +class CategoryChoiceField(forms.ChoiceField): widget = CategorySelectWidget def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.widget.icons = self.icons + self.choices = getattr(settings, "A4_CATEGORY_ICONS", []) @property def icons(self): - return CategoryIconDict(self) - - # Update the icons if the queryset is updated - def _set_queryset(self, queryset): - super()._set_queryset(queryset) - self.widget.icons = self.icons - - queryset = property(forms.ModelChoiceField._get_queryset, _set_queryset) + return dict(self.choices) class IconSelectWidget(widgets.Select): diff --git a/adhocracy4/categories/forms.py b/adhocracy4/categories/forms.py index 55ba172db..513e0a042 100644 --- a/adhocracy4/categories/forms.py +++ b/adhocracy4/categories/forms.py @@ -7,6 +7,7 @@ from adhocracy4.modules import models as module_models from . import has_icons +from .form_fields import CategoryChoiceField class CategorizableFieldMixin: @@ -50,6 +51,7 @@ def __init__(self, module, *args, **kwargs): del self.fields["icon"] name = forms.CharField(widget=forms.TextInput(attrs={"placeholder": _("Category")})) + icon = CategoryChoiceField() class Media: js = ("category_formset.js",) diff --git a/adhocracy4/categories/models.py b/adhocracy4/categories/models.py index 38d0e165e..391971bd9 100644 --- a/adhocracy4/categories/models.py +++ b/adhocracy4/categories/models.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.db import models from django.utils.translation import gettext_lazy as _ @@ -13,15 +12,6 @@ def __init__(self, *args, **kwargs): kwargs["blank"] = True super().__init__(*args, **kwargs) - def contribute_to_class(self, cls, name, **kwargs): - """Initialize icon choices from the settings if they exist.""" - - if hasattr(settings, "A4_CATEGORY_ICONS"): - self.choices = settings.A4_CATEGORY_ICONS - - # Call the super method at last so that choices are already initialized - super().contribute_to_class(cls, name, **kwargs) - def formfield(self, **kwargs): form_class = kwargs.get("choices_form_class", IconChoiceField) kwargs["choices_form_class"] = form_class diff --git a/changelog/0006.md b/changelog/0006.md new file mode 100644 index 000000000..77414e4ef --- /dev/null +++ b/changelog/0006.md @@ -0,0 +1,4 @@ +### Changed + +- apps/categories: change CategoryChoiceField for icons from moded field to simple field + (was creating migrations in forked projects) From ec5c807fa6e8e9644aa23d0a8e7c7a2df2fd5c60 Mon Sep 17 00:00:00 2001 From: Julian Dehm Date: Wed, 29 Nov 2023 12:32:58 +0100 Subject: [PATCH 9/9] apps/projects: add topics as m2m relation --- Makefile | 4 ++ ..._alter_project_topics_project_m2mtopics.py | 34 +++++++++++++++++ .../0043_migrate_topics_to_m2m_topics.py | 38 +++++++++++++++++++ .../0044_remove_project_field_topics.py | 16 ++++++++ .../0045_rename_field_m2mtopics_to_topics.py | 15 ++++++++ adhocracy4/projects/models.py | 17 +++++++-- changelog/0007.md | 6 +++ 7 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 adhocracy4/projects/migrations/0042_topic_alter_project_topics_project_m2mtopics.py create mode 100644 adhocracy4/projects/migrations/0043_migrate_topics_to_m2m_topics.py create mode 100644 adhocracy4/projects/migrations/0044_remove_project_field_topics.py create mode 100644 adhocracy4/projects/migrations/0045_rename_field_m2mtopics_to_topics.py create mode 100644 changelog/0007.md diff --git a/Makefile b/Makefile index 795d61e94..1738dc9d6 100644 --- a/Makefile +++ b/Makefile @@ -45,11 +45,15 @@ lint: $(VIRTUAL_ENV)/bin/isort --diff -c $(SOURCE_DIRS) || EXIT_STATUS=$$?; \ $(VIRTUAL_ENV)/bin/flake8 $(SOURCE_DIRS) --exclude migrations,settings || EXIT_STATUS=$$?; \ npm run lint || EXIT_STATUS=$$?; \ + $(VIRTUAL_ENV)/bin/python manage.py makemigrations --dry-run --check --noinput || EXIT_STATUS=$$?; \ + exit $${EXIT_STATUS} .PHONY: lint-quick lint-quick: EXIT_STATUS=0; \ npm run lint-staged || EXIT_STATUS=$$?; \ + $(VIRTUAL_ENV)/bin/python manage.py makemigrations --dry-run --check --noinput || EXIT_STATUS=$$?; \ + exit $${EXIT_STATUS} .PHONY: lint-python-files lint-python-files: diff --git a/adhocracy4/projects/migrations/0042_topic_alter_project_topics_project_m2mtopics.py b/adhocracy4/projects/migrations/0042_topic_alter_project_topics_project_m2mtopics.py new file mode 100644 index 000000000..106ca3bdd --- /dev/null +++ b/adhocracy4/projects/migrations/0042_topic_alter_project_topics_project_m2mtopics.py @@ -0,0 +1,34 @@ +# Generated by Django 4.2 on 2023-11-29 13:18 + +import adhocracy4.projects.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("a4projects", "0041_ckeditor5_iframes"), + ] + + operations = [ + migrations.CreateModel( + name="Topic", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("code", models.CharField(blank=True, max_length=10)), + ("name", models.CharField(max_length=120, verbose_name="Topic")), + ], + ), + migrations.AddField( + model_name="project", + name="m2mtopics", + field=models.ManyToManyField(to="a4projects.topic"), + ), + ] diff --git a/adhocracy4/projects/migrations/0043_migrate_topics_to_m2m_topics.py b/adhocracy4/projects/migrations/0043_migrate_topics_to_m2m_topics.py new file mode 100644 index 000000000..dce03f053 --- /dev/null +++ b/adhocracy4/projects/migrations/0043_migrate_topics_to_m2m_topics.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2 on 2023-11-29 13:20 + +from django.db import migrations +from django.conf import settings + + +def add_topics_to_m2m_table(apps, schema_editor): + if hasattr(settings, "A4_PROJECT_TOPICS"): + topicsenum = settings.A4_PROJECT_TOPICS + project = apps.get_model("a4projects", "Project") + for project in project.objects.all(): + for topic_code in project.topics: + project.m2mtopics.create( + code=topic_code, + name=[item[1] for item in topicsenum if item[0] == topic_code][0], + ) + else: + pass + + +def reverse_func(apps, schema_editor): + if hasattr(settings, "A4_PROJECT_TOPICS"): + project = apps.get_model("a4projects", "Project") + for project in project.objects.all(): + for topic in project.m2mtopics.all(): + project.m2mtopics.remove(topic) + else: + pass + + +class Migration(migrations.Migration): + dependencies = [ + ("a4projects", "0042_topic_alter_project_topics_project_m2mtopics"), + ] + + operations = [ + migrations.RunPython(add_topics_to_m2m_table, reverse_func), + ] diff --git a/adhocracy4/projects/migrations/0044_remove_project_field_topics.py b/adhocracy4/projects/migrations/0044_remove_project_field_topics.py new file mode 100644 index 000000000..c183a2d36 --- /dev/null +++ b/adhocracy4/projects/migrations/0044_remove_project_field_topics.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2 on 2023-11-29 15:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("a4projects", "0043_migrate_topics_to_m2m_topics"), + ] + + operations = [ + migrations.RemoveField( + model_name="project", + name="topics", + ), + ] diff --git a/adhocracy4/projects/migrations/0045_rename_field_m2mtopics_to_topics.py b/adhocracy4/projects/migrations/0045_rename_field_m2mtopics_to_topics.py new file mode 100644 index 000000000..1ba59921b --- /dev/null +++ b/adhocracy4/projects/migrations/0045_rename_field_m2mtopics_to_topics.py @@ -0,0 +1,15 @@ +# Generated by Django 4.2 on 2023-11-29 15:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("a4projects", "0044_remove_project_field_topics"), + ] + + operations = [ + migrations.RenameField( + model_name="project", old_name="m2mtopics", new_name="topics" + ), + ] diff --git a/adhocracy4/projects/models.py b/adhocracy4/projects/models.py index f227c447c..b8e1261db 100644 --- a/adhocracy4/projects/models.py +++ b/adhocracy4/projects/models.py @@ -19,11 +19,21 @@ from adhocracy4.models import base from .enums import Access -from .fields import TopicField from .utils import get_module_clusters from .utils import get_module_clusters_dict +class Topic(models.Model): + code = models.CharField(blank=True, max_length=10) + name = models.CharField( + max_length=120, + verbose_name=_("Topic"), + ) + + def __str__(self): + return self.name + + class ProjectManager(models.Manager): def get_by_natural_key(self, name): return self.get(name=name) @@ -259,9 +269,8 @@ class Project( "dashboard." ), ) - topics = TopicField( - verbose_name=_("Project topics"), help_text=_("Add topics to your project.") - ) + topics = models.ManyToManyField(Topic) + project_type = models.CharField( blank=True, max_length=256, default="a4projects.Project" ) diff --git a/changelog/0007.md b/changelog/0007.md new file mode 100644 index 000000000..ebd389319 --- /dev/null +++ b/changelog/0007.md @@ -0,0 +1,6 @@ +# Changed + +- apps/projects: + add topics model/table + make topics a m2m relation to projects + stop making use of django-multiselectfield as it's not maintained