From d0d6139381743925efd67e42e8bec5644508a7b5 Mon Sep 17 00:00:00 2001 From: Mikhail Khromov Date: Wed, 21 Jun 2023 00:26:59 +0300 Subject: [PATCH 1/7] created DefaultProjectCover + migration model --- projects/models.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/projects/models.py b/projects/models.py index c32ad85b..0ac5be1e 100644 --- a/projects/models.py +++ b/projects/models.py @@ -234,3 +234,36 @@ class ProjectNews(models.Model): class Meta: verbose_name = "Новость проекта" verbose_name_plural = "Новости проекта" + + +class DefaultProjectCover(models.Model): + """ + Default cover model for projects, is chosen randomly at project creation + + Attributes: + image: A ForeignKey referencing the image of the cover. + datetime_created: A DateTimeField indicating date of creation. + datetime_updated: A DateTimeField indicating date of update. + """ + + image = models.ForeignKey( + UserFile, + on_delete=models.CASCADE, + related_name="default_covers", + ) + + datetime_created = models.DateTimeField( + verbose_name="Дата создания", + null=False, + auto_now_add=True, + ) + datetime_updated = models.DateTimeField( + verbose_name="Дата изменения", + null=False, + auto_now=True, + ) + + class Meta: + abstract = True + verbose_name = "Обложка проекта" + verbose_name_plural = "Обложки проектов" From 6164ff6df4a6c3428c2e699c9b8546f1511c3122 Mon Sep 17 00:00:00 2001 From: Mikhail Khromov Date: Wed, 21 Jun 2023 00:33:20 +0300 Subject: [PATCH 2/7] added cover field to project model & serializer --- projects/migrations/0017_project_cover.py | 26 ++++++++ projects/models.py | 81 ++++++++++++++--------- projects/serializers.py | 3 + 3 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 projects/migrations/0017_project_cover.py diff --git a/projects/migrations/0017_project_cover.py b/projects/migrations/0017_project_cover.py new file mode 100644 index 00000000..b1aaa713 --- /dev/null +++ b/projects/migrations/0017_project_cover.py @@ -0,0 +1,26 @@ +# Generated by Django 4.1.3 on 2023-06-20 21:33 + +from django.db import migrations, models +import django.db.models.deletion +import projects.models + + +class Migration(migrations.Migration): + + dependencies = [ + ("files", "0003_userfile_extension_userfile_name_userfile_size"), + ("projects", "0016_alter_projectnews_files"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="cover", + field=models.ForeignKey( + default=projects.models.DefaultProjectCover.get_random_file, + on_delete=django.db.models.deletion.SET_DEFAULT, + related_name="project_cover", + to="files.userfile", + ), + ), + ] diff --git a/projects/models.py b/projects/models.py index 0ac5be1e..985755e6 100644 --- a/projects/models.py +++ b/projects/models.py @@ -15,6 +15,44 @@ User = get_user_model() +class DefaultProjectCover(models.Model): + """ + Default cover model for projects, is chosen randomly at project creation + + Attributes: + image: A ForeignKey referencing the image of the cover. + datetime_created: A DateTimeField indicating date of creation. + datetime_updated: A DateTimeField indicating date of update. + """ + + image = models.ForeignKey( + UserFile, + on_delete=models.CASCADE, + related_name="default_covers", + ) + + datetime_created = models.DateTimeField( + verbose_name="Дата создания", + null=False, + auto_now_add=True, + ) + datetime_updated = models.DateTimeField( + verbose_name="Дата изменения", + null=False, + auto_now=True, + ) + + @classmethod + def get_random_file(cls): + # FIXME: this is not efficient, but for ~10 default covers it should be ok + return cls.objects.order_by("?").first().image + + class Meta: + abstract = True + verbose_name = "Обложка проекта" + verbose_name_plural = "Обложки проектов" + + class Project(models.Model): """ Project model @@ -30,6 +68,7 @@ class Project(models.Model): image_address: A URLField image URL address. leader: A ForeignKey referring to the User model. draft: A boolean indicating if Project is a draft. + cover: A ForeignKey referring to the UserFile model, which is the image cover of the project. datetime_created: A DateTimeField indicating date of creation. datetime_updated: A DateTimeField indicating date of update. """ @@ -57,6 +96,15 @@ class Project(models.Model): draft = models.BooleanField(blank=False, default=True) + cover = models.ForeignKey( + UserFile, + default=DefaultProjectCover.get_random_file, + on_delete=models.SET_DEFAULT, + null=False, + blank=False, + related_name="project_cover", + ) + datetime_created = models.DateTimeField( verbose_name="Дата создания", null=False, auto_now_add=True ) @@ -234,36 +282,3 @@ class ProjectNews(models.Model): class Meta: verbose_name = "Новость проекта" verbose_name_plural = "Новости проекта" - - -class DefaultProjectCover(models.Model): - """ - Default cover model for projects, is chosen randomly at project creation - - Attributes: - image: A ForeignKey referencing the image of the cover. - datetime_created: A DateTimeField indicating date of creation. - datetime_updated: A DateTimeField indicating date of update. - """ - - image = models.ForeignKey( - UserFile, - on_delete=models.CASCADE, - related_name="default_covers", - ) - - datetime_created = models.DateTimeField( - verbose_name="Дата создания", - null=False, - auto_now_add=True, - ) - datetime_updated = models.DateTimeField( - verbose_name="Дата изменения", - null=False, - auto_now=True, - ) - - class Meta: - abstract = True - verbose_name = "Обложка проекта" - verbose_name_plural = "Обложки проектов" diff --git a/projects/serializers.py b/projects/serializers.py index 497c2bdf..a01af1e5 100644 --- a/projects/serializers.py +++ b/projects/serializers.py @@ -3,6 +3,7 @@ from core.fields import CustomListField from core.services import get_views_count, get_likes_count, is_fan +from files.serializers import UserFileSerializer from industries.models import Industry from projects.models import Project, Achievement, Collaborator, ProjectNews from projects.validators import validate_project @@ -64,6 +65,7 @@ class Meta: class ProjectDetailSerializer(serializers.ModelSerializer): achievements = AchievementListSerializer(many=True, read_only=True) + cover = UserFileSerializer(required=False) collaborators = CollaboratorSerializer( source="collaborator_set", many=True, read_only=True ) @@ -116,6 +118,7 @@ class Meta: "datetime_updated", "views_count", "likes_count", + "cover", ] read_only_fields = [ "leader", From 4c50867c88262626d3da9e0a27230fd03359a971 Mon Sep 17 00:00:00 2001 From: Mikhail Khromov Date: Wed, 21 Jun 2023 00:36:14 +0300 Subject: [PATCH 3/7] fix accidental abstract=true --- projects/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/models.py b/projects/models.py index 985755e6..3772cce2 100644 --- a/projects/models.py +++ b/projects/models.py @@ -48,7 +48,6 @@ def get_random_file(cls): return cls.objects.order_by("?").first().image class Meta: - abstract = True verbose_name = "Обложка проекта" verbose_name_plural = "Обложки проектов" From cc4b10e2ea538c804c2315b322f13adc0f6c5b7a Mon Sep 17 00:00:00 2001 From: Mikhail Khromov Date: Wed, 21 Jun 2023 00:42:39 +0300 Subject: [PATCH 4/7] fixed migration bug, but now tests will fail unless they'll have a UserImage --- .../0017_project_cover_defaultprojectcover.py | 59 +++++++++++++++++++ ...t_cover.py => 0018_alter_project_cover.py} | 7 ++- projects/models.py | 2 +- 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 projects/migrations/0017_project_cover_defaultprojectcover.py rename projects/migrations/{0017_project_cover.py => 0018_alter_project_cover.py} (78%) diff --git a/projects/migrations/0017_project_cover_defaultprojectcover.py b/projects/migrations/0017_project_cover_defaultprojectcover.py new file mode 100644 index 00000000..45745bc6 --- /dev/null +++ b/projects/migrations/0017_project_cover_defaultprojectcover.py @@ -0,0 +1,59 @@ +# Generated by Django 4.1.3 on 2023-06-20 21:39 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("files", "0003_userfile_extension_userfile_name_userfile_size"), + ("projects", "0016_alter_projectnews_files"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="cover", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="project_cover", + to="files.userfile", + ), + ), + migrations.CreateModel( + name="DefaultProjectCover", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "datetime_created", + models.DateTimeField(auto_now_add=True, verbose_name="Дата создания"), + ), + ( + "datetime_updated", + models.DateTimeField(auto_now=True, verbose_name="Дата изменения"), + ), + ( + "image", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="default_covers", + to="files.userfile", + ), + ), + ], + options={ + "verbose_name": "Обложка проекта", + "verbose_name_plural": "Обложки проектов", + }, + ), + ] diff --git a/projects/migrations/0017_project_cover.py b/projects/migrations/0018_alter_project_cover.py similarity index 78% rename from projects/migrations/0017_project_cover.py rename to projects/migrations/0018_alter_project_cover.py index b1aaa713..4a1cb0b6 100644 --- a/projects/migrations/0017_project_cover.py +++ b/projects/migrations/0018_alter_project_cover.py @@ -1,4 +1,4 @@ -# Generated by Django 4.1.3 on 2023-06-20 21:33 +# Generated by Django 4.1.3 on 2023-06-20 21:39 from django.db import migrations, models import django.db.models.deletion @@ -9,15 +9,16 @@ class Migration(migrations.Migration): dependencies = [ ("files", "0003_userfile_extension_userfile_name_userfile_size"), - ("projects", "0016_alter_projectnews_files"), + ("projects", "0017_project_cover_defaultprojectcover"), ] operations = [ - migrations.AddField( + migrations.AlterField( model_name="project", name="cover", field=models.ForeignKey( default=projects.models.DefaultProjectCover.get_random_file, + null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name="project_cover", to="files.userfile", diff --git a/projects/models.py b/projects/models.py index 3772cce2..4ee32380 100644 --- a/projects/models.py +++ b/projects/models.py @@ -99,9 +99,9 @@ class Project(models.Model): UserFile, default=DefaultProjectCover.get_random_file, on_delete=models.SET_DEFAULT, + related_name="project_cover", null=False, blank=False, - related_name="project_cover", ) datetime_created = models.DateTimeField( From 58bea0a66bda6cd367450596669ca710f03d34e9 Mon Sep 17 00:00:00 2001 From: Mikhail Khromov Date: Tue, 27 Jun 2023 14:49:50 +0300 Subject: [PATCH 5/7] =?UTF-8?q?=D0=BA=D0=B0=D0=B6=D0=B5=D1=82=D1=81=D1=8F,?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=84=D0=B8=D0=BA=D1=81=D0=B8=D0=BB=20=D0=BC?= =?UTF-8?q?=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D1=81=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B0=D0=BC=D0=B8,=20=D0=B8=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20DefaultCover?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- procollab/settings.py | 3 ++ ...projectcover_image_alter_project_cover.py} | 14 ++++---- .../migrations/0019_auto_20230627_1446.py | 35 +++++++++++++++++++ projects/models.py | 6 ++-- 4 files changed, 49 insertions(+), 9 deletions(-) rename projects/migrations/{0018_alter_project_cover.py => 0018_alter_defaultprojectcover_image_alter_project_cover.py} (59%) create mode 100644 projects/migrations/0019_auto_20230627_1446.py diff --git a/procollab/settings.py b/procollab/settings.py index 508529e0..95d0658d 100644 --- a/procollab/settings.py +++ b/procollab/settings.py @@ -1,4 +1,5 @@ import mimetypes +import sys from datetime import timedelta from pathlib import Path @@ -20,6 +21,8 @@ AUTOPOSTING_ON = config("AUTOPOSTING_ON", default=False, cast=bool) +TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" + TELEGRAM_BOT_TOKEN = config("TELEGRAM_BOT_TOKEN", default="", cast=str) TELEGRAM_CHANNEL = config("TELEGRAM_CHANNEL", default="", cast=str) diff --git a/projects/migrations/0018_alter_project_cover.py b/projects/migrations/0018_alter_defaultprojectcover_image_alter_project_cover.py similarity index 59% rename from projects/migrations/0018_alter_project_cover.py rename to projects/migrations/0018_alter_defaultprojectcover_image_alter_project_cover.py index 4a1cb0b6..690401c1 100644 --- a/projects/migrations/0018_alter_project_cover.py +++ b/projects/migrations/0018_alter_defaultprojectcover_image_alter_project_cover.py @@ -1,8 +1,7 @@ -# Generated by Django 4.1.3 on 2023-06-20 21:39 +# Generated by Django 4.1.3 on 2023-06-27 11:42 from django.db import migrations, models import django.db.models.deletion -import projects.models class Migration(migrations.Migration): @@ -14,14 +13,15 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="project", - name="cover", + model_name="defaultprojectcover", + name="image", field=models.ForeignKey( - default=projects.models.DefaultProjectCover.get_random_file, + blank=True, null=True, - on_delete=django.db.models.deletion.SET_DEFAULT, - related_name="project_cover", + on_delete=django.db.models.deletion.CASCADE, + related_name="default_covers", to="files.userfile", ), ), + ] diff --git a/projects/migrations/0019_auto_20230627_1446.py b/projects/migrations/0019_auto_20230627_1446.py new file mode 100644 index 00000000..e356ca1b --- /dev/null +++ b/projects/migrations/0019_auto_20230627_1446.py @@ -0,0 +1,35 @@ +# Generated by Django 4.1.3 on 2023-06-27 11:46 +import django +from django.db import migrations, models +import projects.models + + +def create_default_project_cover(apps, schema_editor): + # create a random default cover using a random UserFile + DefaultProjectCover = apps.get_model("projects", "DefaultProjectCover") + default_cover = DefaultProjectCover.objects.create() + # project = apps.get_model("projects", "Project") + # project.objects.update(cover=default_cover.image) + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0018_alter_defaultprojectcover_image_alter_project_cover"), + ] + + operations = [ + migrations.RunPython(create_default_project_cover), + migrations.AlterField( + model_name="project", + name="cover", + field=models.ForeignKey( + default=projects.models.DefaultProjectCover.get_random_file, + on_delete=django.db.models.deletion.SET_DEFAULT, + related_name="project_cover", + to="files.userfile", + null=True, + blank=True + ), + ), + ] diff --git a/projects/models.py b/projects/models.py index 4ee32380..377979bd 100644 --- a/projects/models.py +++ b/projects/models.py @@ -29,6 +29,8 @@ class DefaultProjectCover(models.Model): UserFile, on_delete=models.CASCADE, related_name="default_covers", + null=True, + blank=True, ) datetime_created = models.DateTimeField( @@ -100,8 +102,8 @@ class Project(models.Model): default=DefaultProjectCover.get_random_file, on_delete=models.SET_DEFAULT, related_name="project_cover", - null=False, - blank=False, + null=True, + blank=True, ) datetime_created = models.DateTimeField( From c85fcd7cb7e36d7b00852b2225c80efa46d26f6c Mon Sep 17 00:00:00 2001 From: Mikhail Khromov Date: Sat, 8 Jul 2023 19:17:58 +0300 Subject: [PATCH 6/7] remove testing constant in settings.py --- procollab/settings.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/procollab/settings.py b/procollab/settings.py index 95d0658d..508529e0 100644 --- a/procollab/settings.py +++ b/procollab/settings.py @@ -1,5 +1,4 @@ import mimetypes -import sys from datetime import timedelta from pathlib import Path @@ -21,8 +20,6 @@ AUTOPOSTING_ON = config("AUTOPOSTING_ON", default=False, cast=bool) -TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" - TELEGRAM_BOT_TOKEN = config("TELEGRAM_BOT_TOKEN", default="", cast=str) TELEGRAM_CHANNEL = config("TELEGRAM_CHANNEL", default="", cast=str) From 434aeb41a2b280dbe51510508faa950fc4f6ed9a Mon Sep 17 00:00:00 2001 From: VeryBigSad Date: Thu, 7 Sep 2023 10:21:12 +0300 Subject: [PATCH 7/7] fix migrations? --- ...tprojectcover_image_alter_project_cover.py | 27 ---------- .../migrations/0019_auto_20230627_1446.py | 35 ------------- ...0020_project_cover_defaultprojectcover.py} | 51 ++++++++++++++++--- 3 files changed, 45 insertions(+), 68 deletions(-) delete mode 100644 projects/migrations/0018_alter_defaultprojectcover_image_alter_project_cover.py delete mode 100644 projects/migrations/0019_auto_20230627_1446.py rename projects/migrations/{0017_project_cover_defaultprojectcover.py => 0020_project_cover_defaultprojectcover.py} (52%) diff --git a/projects/migrations/0018_alter_defaultprojectcover_image_alter_project_cover.py b/projects/migrations/0018_alter_defaultprojectcover_image_alter_project_cover.py deleted file mode 100644 index 690401c1..00000000 --- a/projects/migrations/0018_alter_defaultprojectcover_image_alter_project_cover.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.1.3 on 2023-06-27 11:42 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("files", "0003_userfile_extension_userfile_name_userfile_size"), - ("projects", "0017_project_cover_defaultprojectcover"), - ] - - operations = [ - migrations.AlterField( - model_name="defaultprojectcover", - name="image", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="default_covers", - to="files.userfile", - ), - ), - - ] diff --git a/projects/migrations/0019_auto_20230627_1446.py b/projects/migrations/0019_auto_20230627_1446.py deleted file mode 100644 index e356ca1b..00000000 --- a/projects/migrations/0019_auto_20230627_1446.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 4.1.3 on 2023-06-27 11:46 -import django -from django.db import migrations, models -import projects.models - - -def create_default_project_cover(apps, schema_editor): - # create a random default cover using a random UserFile - DefaultProjectCover = apps.get_model("projects", "DefaultProjectCover") - default_cover = DefaultProjectCover.objects.create() - # project = apps.get_model("projects", "Project") - # project.objects.update(cover=default_cover.image) - - -class Migration(migrations.Migration): - - dependencies = [ - ("projects", "0018_alter_defaultprojectcover_image_alter_project_cover"), - ] - - operations = [ - migrations.RunPython(create_default_project_cover), - migrations.AlterField( - model_name="project", - name="cover", - field=models.ForeignKey( - default=projects.models.DefaultProjectCover.get_random_file, - on_delete=django.db.models.deletion.SET_DEFAULT, - related_name="project_cover", - to="files.userfile", - null=True, - blank=True - ), - ), - ] diff --git a/projects/migrations/0017_project_cover_defaultprojectcover.py b/projects/migrations/0020_project_cover_defaultprojectcover.py similarity index 52% rename from projects/migrations/0017_project_cover_defaultprojectcover.py rename to projects/migrations/0020_project_cover_defaultprojectcover.py index 45745bc6..f30827dc 100644 --- a/projects/migrations/0017_project_cover_defaultprojectcover.py +++ b/projects/migrations/0020_project_cover_defaultprojectcover.py @@ -1,27 +1,51 @@ -# Generated by Django 4.1.3 on 2023-06-20 21:39 +# Generated by Django 4.2.3 on 2023-09-07 07:13 from django.db import migrations, models import django.db.models.deletion +import projects.models + +# Generated by Django 4.1.3 on 2023-06-27 11:46 +import django +from django.db import migrations, models +import projects.models + + +def create_default_project_cover(apps, schema_editor): + # create a random default cover using a random UserFile + DefaultProjectCover = apps.get_model("projects", "DefaultProjectCover") + default_cover = DefaultProjectCover.objects.create() class Migration(migrations.Migration): dependencies = [ - ("files", "0003_userfile_extension_userfile_name_userfile_size"), - ("projects", "0016_alter_projectnews_files"), + ("projects", "0018_alter_defaultprojectcover_image_alter_project_cover"), ] operations = [ - migrations.AddField( + migrations.RunPython(create_default_project_cover), + migrations.AlterField( model_name="project", name="cover", field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, + default=projects.models.DefaultProjectCover.get_random_file, + on_delete=django.db.models.deletion.SET_DEFAULT, related_name="project_cover", to="files.userfile", + null=True, + blank=True ), ), + ] + +class Migration(migrations.Migration): + + dependencies = [ + ("files", "0005_alter_userfile_options"), + ("projects", "0019_alter_project_options_project_hidden_score"), + ] + + operations = [ migrations.CreateModel( name="DefaultProjectCover", fields=[ @@ -45,6 +69,8 @@ class Migration(migrations.Migration): ( "image", models.ForeignKey( + blank=True, + null=True, on_delete=django.db.models.deletion.CASCADE, related_name="default_covers", to="files.userfile", @@ -56,4 +82,17 @@ class Migration(migrations.Migration): "verbose_name_plural": "Обложки проектов", }, ), + migrations.RunPython(create_default_project_cover), + migrations.AddField( + model_name="project", + name="cover", + field=models.ForeignKey( + blank=True, + default=projects.models.DefaultProjectCover.get_random_file, + null=True, + on_delete=django.db.models.deletion.SET_DEFAULT, + related_name="project_cover", + to="files.userfile", + ), + ), ]