diff --git a/projects/migrations/0020_project_cover_defaultprojectcover.py b/projects/migrations/0020_project_cover_defaultprojectcover.py new file mode 100644 index 00000000..f30827dc --- /dev/null +++ b/projects/migrations/0020_project_cover_defaultprojectcover.py @@ -0,0 +1,98 @@ +# 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 = [ + ("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 + ), + ), + ] + +class Migration(migrations.Migration): + + dependencies = [ + ("files", "0005_alter_userfile_options"), + ("projects", "0019_alter_project_options_project_hidden_score"), + ] + + operations = [ + 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( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="default_covers", + to="files.userfile", + ), + ), + ], + options={ + "verbose_name": "Обложка проекта", + "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", + ), + ), + ] diff --git a/projects/models.py b/projects/models.py index bc81024f..e8031e23 100644 --- a/projects/models.py +++ b/projects/models.py @@ -15,6 +15,45 @@ 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", + null=True, + blank=True, + ) + + 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: + verbose_name = "Обложка проекта" + verbose_name_plural = "Обложки проектов" + + class Project(models.Model): """ Project model @@ -30,6 +69,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. """ @@ -58,6 +98,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, + related_name="project_cover", + null=True, + blank=True, + ) + datetime_created = models.DateTimeField( verbose_name="Дата создания", null=False, auto_now_add=True ) diff --git a/projects/serializers.py b/projects/serializers.py index cfa0b606..111eae88 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 @@ -63,6 +64,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 ) @@ -127,7 +129,8 @@ class Meta: "datetime_updated", "views_count", "likes_count", - "partner_programs_tags", + "cover", + "partner_programs_tags" ] read_only_fields = [ "leader",