From b7c1d6a48d3a55e3498b32c5af3e6890975ccf52 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 30 Aug 2019 10:48:44 +0300 Subject: [PATCH 01/24] added application review --- apps/review/__init__.py | 0 apps/review/admin.py | 7 ++++++ apps/review/apps.py | 7 ++++++ apps/review/migrations/__init__.py | 0 apps/review/models.py | 34 +++++++++++++++++++++++++++++ apps/review/serializers/__init__.py | 0 apps/review/serializers/common.py | 0 apps/review/serializers/mobile.py | 0 apps/review/serializers/web.py | 0 apps/review/tests.py | 3 +++ apps/review/urls/__init__.py | 0 apps/review/urls/common.py | 0 apps/review/urls/mobile.py | 0 apps/review/urls/web.py | 0 apps/review/views/__init__.py | 0 apps/review/views/common.py | 0 apps/review/views/mobile.py | 0 apps/review/views/web.py | 0 project/settings/base.py | 1 + 19 files changed, 52 insertions(+) create mode 100644 apps/review/__init__.py create mode 100644 apps/review/admin.py create mode 100644 apps/review/apps.py create mode 100644 apps/review/migrations/__init__.py create mode 100644 apps/review/models.py create mode 100644 apps/review/serializers/__init__.py create mode 100644 apps/review/serializers/common.py create mode 100644 apps/review/serializers/mobile.py create mode 100644 apps/review/serializers/web.py create mode 100644 apps/review/tests.py create mode 100644 apps/review/urls/__init__.py create mode 100644 apps/review/urls/common.py create mode 100644 apps/review/urls/mobile.py create mode 100644 apps/review/urls/web.py create mode 100644 apps/review/views/__init__.py create mode 100644 apps/review/views/common.py create mode 100644 apps/review/views/mobile.py create mode 100644 apps/review/views/web.py diff --git a/apps/review/__init__.py b/apps/review/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/admin.py b/apps/review/admin.py new file mode 100644 index 00000000..f3aeca39 --- /dev/null +++ b/apps/review/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin +from review import models + + +@admin.register(models.Review) +class ReviewAdminModel(admin.ModelAdmin): + """Admin model for model Review.""" diff --git a/apps/review/apps.py b/apps/review/apps.py new file mode 100644 index 00000000..6440958c --- /dev/null +++ b/apps/review/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class ReviewConfig(AppConfig): + name = 'review' + verbose_name = _('reviews') diff --git a/apps/review/migrations/__init__.py b/apps/review/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/models.py b/apps/review/models.py new file mode 100644 index 00000000..d7f7082e --- /dev/null +++ b/apps/review/models.py @@ -0,0 +1,34 @@ +from django.contrib.contenttypes import fields as generic +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from utils.models import BaseAttributes + + +class ReviewQuerySet(models.QuerySet): + """QuerySets for model Review""" + + def by_reviewer(self, user): + """Return reviews by user""" + return self.filter(reviewer=user) + + +class Review(BaseAttributes): + """Review model""" + reviewer = models.ForeignKey('account.User', + related_name='review', + on_delete=models.CASCADE, + verbose_name=_('reviewer'),) + content_object = generic.GenericForeignKey('content_type', 'object_id') + language = models.ForeignKey('translation.Language', + on_delete=models.CASCADE, + related_name='review', + verbose_name=_('Review language')) + text = models.TextField(verbose_name=_('Text')) + + objects = ReviewQuerySet.as_manager() + + class Meta: + """Meta class.""" + verbose_name = _('Review') + verbose_name_plural = _('Reviews') diff --git a/apps/review/serializers/__init__.py b/apps/review/serializers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/serializers/common.py b/apps/review/serializers/common.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/serializers/mobile.py b/apps/review/serializers/mobile.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/serializers/web.py b/apps/review/serializers/web.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/tests.py b/apps/review/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/review/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/review/urls/__init__.py b/apps/review/urls/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/urls/common.py b/apps/review/urls/common.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/urls/mobile.py b/apps/review/urls/mobile.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/urls/web.py b/apps/review/urls/web.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/views/__init__.py b/apps/review/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/views/common.py b/apps/review/views/common.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/views/mobile.py b/apps/review/views/mobile.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/review/views/web.py b/apps/review/views/web.py new file mode 100644 index 00000000..e69de29b diff --git a/project/settings/base.py b/project/settings/base.py index ef721f80..e6332237 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -65,6 +65,7 @@ PROJECT_APPS = [ 'translation.apps.TranslationConfig', 'configuration.apps.ConfigurationConfig', 'timetable.apps.TimetableConfig', + 'review.apps.ReviewConfig', ] EXTERNAL_APPS = [ From 8fccd069ece6ba4bcceb4690d4bd2593c1411199 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 30 Aug 2019 15:30:41 +0300 Subject: [PATCH 02/24] added additional fields to review model --- apps/review/models.py | 32 +++++++++++++++++++++++++++++--- apps/utils/models.py | 3 --- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/review/models.py b/apps/review/models.py index d7f7082e..fe33bfed 100644 --- a/apps/review/models.py +++ b/apps/review/models.py @@ -1,6 +1,7 @@ from django.contrib.contenttypes import fields as generic from django.db import models from django.utils.translation import gettext_lazy as _ +from django.core.validators import MinValueValidator, MaxValueValidator from utils.models import BaseAttributes @@ -12,19 +13,44 @@ class ReviewQuerySet(models.QuerySet): """Return reviews by user""" return self.filter(reviewer=user) + def by_vintage(self, year: int): + """Return reviews by year""" + return self.filter(vintage=year) + class Review(BaseAttributes): """Review model""" + TO_INVESTIGATE = 0 + TO_REVIEW = 1 + READY = 2 + REVIEW_STATUSES = ( + (TO_INVESTIGATE, _('To investigate')), + (TO_REVIEW, _('To review')), + (READY, _('Ready')), + ) + reviewer = models.ForeignKey('account.User', - related_name='review', + related_name='reviews', on_delete=models.CASCADE, - verbose_name=_('reviewer'),) + verbose_name=_('Reviewer')) + content_type = models.ForeignKey(generic.ContentType, on_delete=models.CASCADE) + object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') language = models.ForeignKey('translation.Language', on_delete=models.CASCADE, - related_name='review', + related_name='reviews', verbose_name=_('Review language')) text = models.TextField(verbose_name=_('Text')) + status = models.PositiveSmallIntegerField(choices=REVIEW_STATUSES, default=TO_INVESTIGATE) + child = models.ForeignKey('self', + on_delete=models.CASCADE, + verbose_name=_('Child review')) + published_at = models.DateTimeField(verbose_name=_('Publish datetime'), + blank=True, default=None, null=True, + help_text=_('Review published datetime')) + vintage = models.IntegerField(verbose_name=_('Year of review'), + validators=[MinValueValidator(1900), + MaxValueValidator(2100)]) objects = ReviewQuerySet.as_manager() diff --git a/apps/utils/models.py b/apps/utils/models.py index 0e7fdd7f..d9c4564c 100644 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -74,9 +74,6 @@ class OAuthProjectMixin: return NotImplemented -basemixin_fields = ['created', 'modified'] - - class BaseAttributes(ProjectBaseMixin): created_by = models.ForeignKey( 'account.User', on_delete=models.SET_NULL, verbose_name=_('created by'), From ba317f77b8470685b0752f6957fc0284bd53ffbf Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 11:50:52 +0300 Subject: [PATCH 03/24] finish review model --- apps/review/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/review/models.py b/apps/review/models.py index fe33bfed..ff0308e5 100644 --- a/apps/review/models.py +++ b/apps/review/models.py @@ -1,7 +1,7 @@ from django.contrib.contenttypes import fields as generic +from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models from django.utils.translation import gettext_lazy as _ -from django.core.validators import MinValueValidator, MaxValueValidator from utils.models import BaseAttributes @@ -43,6 +43,7 @@ class Review(BaseAttributes): text = models.TextField(verbose_name=_('Text')) status = models.PositiveSmallIntegerField(choices=REVIEW_STATUSES, default=TO_INVESTIGATE) child = models.ForeignKey('self', + blank=True, default=None, null=True, on_delete=models.CASCADE, verbose_name=_('Child review')) published_at = models.DateTimeField(verbose_name=_('Publish datetime'), From 0d4f08085015cef48f19499ee88e9808f5244f55 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 12:30:00 +0300 Subject: [PATCH 04/24] added new model - Comment --- apps/account/admin.py | 4 +- apps/establishment/admin.py | 8 +++- apps/establishment/migrations/0006_comment.py | 32 ++++++++++++++++ apps/establishment/models.py | 38 ++++++++++++++++++- apps/establishment/serializers.py | 20 ++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 apps/establishment/migrations/0006_comment.py diff --git a/apps/account/admin.py b/apps/account/admin.py index 9cbe52eb..e9c853bb 100644 --- a/apps/account/admin.py +++ b/apps/account/admin.py @@ -18,7 +18,7 @@ class UserAdmin(BaseUserAdmin): fieldsets = ( (None, {'fields': ('email', 'password',)}), (_('Personal info'), { - 'fields': ('username', 'first_name', 'last_name', )}), + 'fields': ('username', 'first_name', 'last_name', 'image')}), (_('Subscription'), { 'fields': ( 'newsletter', @@ -27,7 +27,7 @@ class UserAdmin(BaseUserAdmin): (_('Important dates'), {'fields': ('last_login', 'date_joined')}), (_('Permissions'), { 'fields': ( - 'is_active', 'is_staff', 'is_superuser', 'email_confirmed' + 'is_active', 'is_staff', 'is_superuser', 'email_confirmed', 'groups', 'user_permissions'), 'classes': ('collapse', ) }), diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index d40950b1..638f6564 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -1,7 +1,8 @@ """Establishment admin conf.""" from django.contrib import admin -from establishment import models from django.contrib.contenttypes.admin import GenericTabularInline + +from establishment import models from main.models import Award, MetaDataContent @@ -34,3 +35,8 @@ class EstablishmentAdmin(admin.ModelAdmin): @admin.register(models.EstablishmentSchedule) class EstablishmentSchedule(admin.ModelAdmin): """Establishment schedule""" + + +@admin.register(models.Comment) +class EstablishmentComment(admin.ModelAdmin): + """Establishment comments.""" diff --git a/apps/establishment/migrations/0006_comment.py b/apps/establishment/migrations/0006_comment.py new file mode 100644 index 00000000..4ae22034 --- /dev/null +++ b/apps/establishment/migrations/0006_comment.py @@ -0,0 +1,32 @@ +# Generated by Django 2.2.4 on 2019-09-01 09:16 + +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('establishment', '0005_establishmentschedule'), + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('text', models.TextField(verbose_name='Comment text')), + ('mark', models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='Mark')), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to=settings.AUTH_USER_MODEL, verbose_name='Author')), + ('establishment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='establishment.Establishment', verbose_name='Establishment')), + ], + options={ + 'verbose_name': 'Comment', + 'verbose_name_plural': 'Comments', + }, + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 56cc531c..668d0d46 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,11 +1,12 @@ """Establishment models.""" +from django.contrib.contenttypes import fields as generic from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ + from location.models import Address from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, TraslatedFieldsMixin, BaseAttributes) -from django.contrib.contenttypes import fields as generic # todo: establishment type&subtypes check @@ -146,3 +147,38 @@ class EstablishmentSchedule(BaseAttributes): """Meta class""" verbose_name = _('Establishment schedule') verbose_name_plural = _('Establishment schedules') + + +class CommentQuerySet(models.QuerySet): + """QuerySets for Comment model.""" + + def by_author(self, author): + """Return comments by author""" + return self.filter(author=author) + + +class Comment(ProjectBaseMixin): + """Comment model.""" + text = models.TextField(verbose_name=_('Comment text')) + mark = models.PositiveIntegerField(blank=True, null=True, + default=None, + verbose_name=_('Mark')) + author = models.ForeignKey('account.User', + related_name='comments', + on_delete=models.CASCADE, + verbose_name=_('Author')) + establishment = models.ForeignKey(Establishment, + related_name='comments', + on_delete=models.CASCADE, + verbose_name=_('Establishment')) + + objects = CommentQuerySet.as_manager() + + class Meta: + """Meta class""" + verbose_name = _('Comment') + verbose_name_plural = _('Comments') + + def __str__(self): + """String representation""" + return str(self.author) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 49788db3..660f9709 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -1,5 +1,6 @@ """Establishment serializers.""" from rest_framework import serializers + from establishment import models from location.serializers import AddressSerializer from main.serializers import MetaDataContentSerializer, AwardSerializer @@ -46,6 +47,22 @@ class EstablishmentScheduleSerializer(serializers.ModelSerializer): ) +class CommentSerializer(serializers.ModelSerializer): + """Comment serializer""" + nickname = serializers.CharField(source='author.username') + image = serializers.ImageField(source='author.image') + + class Meta: + """Serializer for model Comment""" + model = models.Comment + fields = ( + 'text', + 'mark', + 'nickname', + 'image' + ) + + class EstablishmentSerializer(serializers.ModelSerializer): """Serializer for Establishment model.""" @@ -59,6 +76,8 @@ class EstablishmentSerializer(serializers.ModelSerializer): schedule = EstablishmentScheduleSerializer(source='schedule.schedule', many=True, allow_null=True) + comments = CommentSerializer(many=True, + allow_null=True) class Meta: """Meta class.""" @@ -79,4 +98,5 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', + 'comments', ) From fc4facbf83941108d47088cf2c0eb09e6ca35830 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Sun, 1 Sep 2019 12:35:09 +0300 Subject: [PATCH 05/24] add contacts for establishments --- apps/establishment/admin.py | 25 +++- .../migrations/0005_auto_20190901_0831.py | 77 +++++++++++ .../migrations/0006_merge_20190901_0846.py | 14 ++ apps/establishment/models.py | 122 ++++++++++++++++-- apps/establishment/serializers.py | 37 ++++++ .../migrations/0003_auto_20190821_1407.py | 2 +- .../migrations/0009_auto_20190901_0831.py | 19 +++ apps/location/models.py | 2 +- apps/main/models.py | 16 ++- apps/news/models.py | 6 +- apps/translation/models.py | 2 +- project/settings/base.py | 1 + requirements/base.txt | 1 + 13 files changed, 307 insertions(+), 17 deletions(-) create mode 100644 apps/establishment/migrations/0005_auto_20190901_0831.py create mode 100644 apps/establishment/migrations/0006_merge_20190901_0846.py create mode 100644 apps/location/migrations/0009_auto_20190901_0831.py diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index d40950b1..a5209c3d 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -25,10 +25,33 @@ class MetaDataContentInline(GenericTabularInline): extra = 0 +class ContactPhoneInline(admin.TabularInline): + """Contact phone inline admin.""" + model = models.ContactPhone + extra = 0 + + +class ContactEmailInline(admin.TabularInline): + """Contact email inline admin.""" + model = models.ContactEmail + extra = 0 + + +@admin.register(models.Contact) +class ContactAdmin(admin.ModelAdmin): + """Contact admin.""" + inlines = [ContactPhoneInline, ContactEmailInline, ] + + +class ContactsInline(admin.TabularInline): + model = models.Contact + extra = 0 + + @admin.register(models.Establishment) class EstablishmentAdmin(admin.ModelAdmin): """Establishment admin.""" - inlines = [AwardInline, MetaDataContentInline] + inlines = [AwardInline, MetaDataContentInline, ContactsInline, ] @admin.register(models.EstablishmentSchedule) diff --git a/apps/establishment/migrations/0005_auto_20190901_0831.py b/apps/establishment/migrations/0005_auto_20190901_0831.py new file mode 100644 index 00000000..ef99bf4d --- /dev/null +++ b/apps/establishment/migrations/0005_auto_20190901_0831.py @@ -0,0 +1,77 @@ +# Generated by Django 2.2.4 on 2019-09-01 08:31 + +from django.db import migrations, models +import django.db.models.deletion +import phonenumber_field.modelfields +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0009_auto_20190901_0831'), + ('establishment', '0004_auto_20190828_1156'), + ] + + operations = [ + migrations.CreateModel( + name='Contact', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='location.Address')), + ], + options={ + 'verbose_name': 'contact', + 'verbose_name_plural': 'contacts', + }, + ), + migrations.AlterField( + model_name='establishment', + name='description', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Description'), + ), + migrations.AlterField( + model_name='establishment', + name='name', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Name'), + ), + migrations.AlterField( + model_name='establishmentsubtype', + name='name', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Description'), + ), + migrations.AlterField( + model_name='establishmenttype', + name='name', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Description'), + ), + migrations.CreateModel( + name='ContactPhone', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('phone', phonenumber_field.modelfields.PhoneNumberField(max_length=128)), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='phones', to='establishment.Contact')), + ], + options={ + 'verbose_name': 'contact phone', + 'verbose_name_plural': 'contact phones', + }, + ), + migrations.CreateModel( + name='ContactEmail', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.EmailField(max_length=254)), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='emails', to='establishment.Contact')), + ], + options={ + 'verbose_name': 'contact email', + 'verbose_name_plural': 'contact emails', + }, + ), + migrations.AddField( + model_name='contact', + name='establishment', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contacts', to='establishment.Establishment'), + ), + ] diff --git a/apps/establishment/migrations/0006_merge_20190901_0846.py b/apps/establishment/migrations/0006_merge_20190901_0846.py new file mode 100644 index 00000000..e629f2b9 --- /dev/null +++ b/apps/establishment/migrations/0006_merge_20190901_0846.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.4 on 2019-09-01 08:46 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0005_auto_20190901_0831'), + ('establishment', '0005_establishmentschedule'), + ] + + operations = [ + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 68b8872e..0c73b722 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,12 +1,15 @@ """Establishment models.""" -from functools import reduce +from django.contrib.contenttypes import fields as generic from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ +from phonenumber_field.modelfields import PhoneNumberField + from location.models import Address -from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, - TraslatedFieldsMixin, BaseAttributes) -from django.contrib.contenttypes import fields as generic +from utils.models import ( + ProjectBaseMixin, ImageMixin, TJSONField, + TraslatedFieldsMixin, BaseAttributes +) # todo: establishment type&subtypes check @@ -14,7 +17,7 @@ class EstablishmentType(ProjectBaseMixin, TraslatedFieldsMixin): """Establishment type model.""" name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), - help_text='{"en":"some text"}') + help_text='{"en-GB":"some text"}') use_subtypes = models.BooleanField(_('Use subtypes'), default=True) class Meta: @@ -38,7 +41,7 @@ class EstablishmentSubType(ProjectBaseMixin, TraslatedFieldsMixin): """Establishment type model.""" name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), - help_text='{"en":"some text"}') + help_text='{"en-GB":"some text"}') establishment_type = models.ForeignKey(EstablishmentType, on_delete=models.CASCADE, verbose_name=_('Type')) @@ -75,10 +78,10 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): """Establishment model.""" name = TJSONField(blank=True, null=True, default=None, - verbose_name=_('Name'), help_text='{"en":"some text"}') + verbose_name=_('Name'), help_text='{"en-GB":"some text"}') description = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), - help_text='{"en":"some text"}') + help_text='{"en-GB":"some text"}') public_mark = models.PositiveIntegerField(blank=True, null=True, default=None, verbose_name=_('Public mark'),) @@ -160,3 +163,106 @@ class EstablishmentSchedule(BaseAttributes): """Meta class""" verbose_name = _('Establishment schedule') verbose_name_plural = _('Establishment schedules') + + +class Contact(models.Model): + """Contact model.""" + establishment = models.ForeignKey( + Establishment, related_name='contacts', on_delete=models.CASCADE) + address = models.ForeignKey('location.Address', on_delete=models.CASCADE) + + class Meta: + verbose_name = _('contact') + verbose_name_plural = _('contacts') + + +class ContactPhone(models.Model): + """Contact phone model.""" + contact = models.ForeignKey( + Contact, related_name='phones', on_delete=models.CASCADE) + phone = PhoneNumberField() + + class Meta: + verbose_name = _('contact phone') + verbose_name_plural = _('contact phones') + + def __str__(self): + return f'{self.phone.as_e164}' + + +class ContactEmail(models.Model): + """Contact email model.""" + contact = models.ForeignKey( + Contact, related_name='emails', on_delete=models.CASCADE) + email = models.EmailField() + + class Meta: + verbose_name = _('contact email') + verbose_name_plural = _('contact emails') + + def __str__(self): + return f'{self.email}' + +# +# class Wine(TraslatedFieldsMixin, models.Model): +# """Wine model.""" +# establishment = models.ForeignKey( +# 'establishment.Establishment', verbose_name=_('establishment'), +# on_delete=models.CASCADE) +# bottles = models.IntegerField(_('bottles')) +# price_min = models.DecimalField( +# _('price min'), max_digits=14, decimal_places=2) +# price_max = models.DecimalField( +# _('price max'), max_digits=14, decimal_places=2) +# by_glass = models.BooleanField(_('by glass')) +# price_glass_min = models.DecimalField( +# _('price min'), max_digits=14, decimal_places=2) +# price_glass_max = models.DecimalField( +# _('price max'), max_digits=14, decimal_places=2) +# +# +# class Plate(TraslatedFieldsMixin, models.Model): +# """Plate model.""" +# +# STARTER = 0 +# MAIN = 1 +# COURSE = 2 +# DESSERT = 3 +# +# PLATE_TYPE_CHOICES = ( +# (STARTER, _('starter')), +# (MAIN, _('main')), +# (COURSE, _('course')), +# (DESSERT, _('dessert')), +# ) +# name = models.CharField(_('name'), max_length=255) +# plate_type = models.PositiveSmallIntegerField(_('plate_type'), choices=PLATE_TYPE_CHOICES) +# description = TJSONField( +# blank=True, null=True, default=None, verbose_name=_('description'), +# help_text='{"en-GB":"some text"}') +# price = models.DecimalField( +# _('price'), max_digits=14, decimal_places=2) +# is_signature_plate = models.BooleanField(_('is signature plate')) +# currency = models.ForeignKey( +# 'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE) +# +# menu = models.ManyToManyField(to='Plate', verbose_name=_(''), through='establishment.Menu') +# +# class Meta: +# verbose_name = _('plate') +# verbose_name_plural = _('plates') +# +# def __str__(self): +# return f'plate_id:{self.id}' +# +# +# class Menu(TraslatedFieldsMixin, BaseAttributes): +# """Menu model.""" +# establishment = models.ForeignKey( +# 'establishment.Establishment', verbose_name=_('establishment'), +# on_delete=models.CASCADE) +# plate = models.ForeignKey(Plate, verbose_name=_('menu'), on_delete=models.CASCADE) +# +# class Meta: +# verbose_name = _('menu') +# verbose_name_plural = _('menu') \ No newline at end of file diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 49788db3..92c7bb1c 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -6,6 +6,39 @@ from main.serializers import MetaDataContentSerializer, AwardSerializer from timetable.models import Timetable +class ContactPhonesSerializer(serializers.ModelSerializer): + """Contact phone serializer""" + class Meta: + model = models.ContactPhone + fields = [ + 'phone' + ] + + +class ContactEmailsSerializer(serializers.ModelSerializer): + """Contact email serializer""" + class Meta: + model = models.ContactEmail + fields = [ + 'email' + ] + + +class ContactSerializer(serializers.ModelSerializer): + """Contact serializer.""" + address = AddressSerializer(read_only=True) + phones = ContactPhonesSerializer(read_only=True, many=True,) + emails = ContactEmailsSerializer(read_only=True, many=True,) + + class Meta: + model = models.Contact + fields = [ + 'address', + 'phones', + 'emails' + ] + + class EstablishmentTypeSerializer(serializers.ModelSerializer): """Serializer for EstablishmentType model.""" @@ -59,6 +92,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): schedule = EstablishmentScheduleSerializer(source='schedule.schedule', many=True, allow_null=True) + contacts = ContactSerializer(read_only=True, many=True, ) class Meta: """Meta class.""" @@ -79,4 +113,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', + 'contacts' ) + + diff --git a/apps/location/migrations/0003_auto_20190821_1407.py b/apps/location/migrations/0003_auto_20190821_1407.py index 548e2a70..c82ec597 100644 --- a/apps/location/migrations/0003_auto_20190821_1407.py +++ b/apps/location/migrations/0003_auto_20190821_1407.py @@ -30,6 +30,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='country', name='name', - field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en":"some text"}', null=True, verbose_name='Text'), + field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Text'), ), ] diff --git a/apps/location/migrations/0009_auto_20190901_0831.py b/apps/location/migrations/0009_auto_20190901_0831.py new file mode 100644 index 00000000..c4e21715 --- /dev/null +++ b/apps/location/migrations/0009_auto_20190901_0831.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-09-01 08:31 + +import django.contrib.postgres.fields.jsonb +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0008_auto_20190827_1302'), + ] + + operations = [ + migrations.AlterField( + model_name='country', + name='name', + field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Name'), + ), + ] diff --git a/apps/location/models.py b/apps/location/models.py index 56bd89f3..613cc013 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -17,7 +17,7 @@ class Country(SVGImageMixin, ProjectBaseMixin): """Country model.""" name = JSONField(null=True, blank=True, default=None, - verbose_name=_('Name'), help_text='{"en":"some text"}') + verbose_name=_('Name'), help_text='{"en-GB":"some text"}') code = models.CharField(max_length=255, unique=True, verbose_name=_('Code')) low_price = models.IntegerField(default=25, verbose_name=_('Low price')) high_price = models.IntegerField(default=50, verbose_name=_('High price')) diff --git a/apps/main/models.py b/apps/main/models.py index cb406d98..b58dc402 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -190,7 +190,7 @@ class Award(TraslatedFieldsMixin, models.Model): award_type = models.ForeignKey('main.AwardType', on_delete=models.CASCADE) title = TJSONField( _('title'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') vintage_year = models.CharField(_('vintage year'), max_length=255, default='') content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) @@ -228,7 +228,7 @@ class MetaData(TraslatedFieldsMixin, models.Model): """MetaData model.""" label = TJSONField( _('label'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') category = models.ForeignKey( MetaDataCategory, verbose_name=_('category'), on_delete=models.CASCADE) @@ -250,3 +250,15 @@ class MetaDataContent(models.Model): object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') metadata = models.ForeignKey(MetaData, on_delete=models.CASCADE) + + +class Currency(models.Model): + """Currency model.""" + name = models.CharField(_('name'), max_length=50) + + class Meta: + verbose_name = _('currency') + verbose_name_plural = _('currencies') + + def __str__(self): + return f'{self.name}' diff --git a/apps/news/models.py b/apps/news/models.py index e3eff57e..0abc7ab5 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -43,14 +43,14 @@ class News(BaseAttributes, TraslatedFieldsMixin): title = TJSONField( _('title'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') subtitle = TJSONField( _('subtitle'), null=True, blank=True, - default=None, help_text='{"en":"some text"}' + default=None, help_text='{"en-GB":"some text"}' ) description = TJSONField( _('description'), null=True, blank=True, - default=None, help_text='{"en":"some text"}' + default=None, help_text='{"en-GB":"some text"}' ) start = models.DateTimeField(_('start')) end = models.DateTimeField(_('end')) diff --git a/apps/translation/models.py b/apps/translation/models.py index f675b315..42530965 100644 --- a/apps/translation/models.py +++ b/apps/translation/models.py @@ -49,7 +49,7 @@ class SiteInterfaceDictionary(ProjectBaseMixin): verbose_name=_('Page')) keywords = models.CharField(max_length=255, verbose_name='Keywords') text = JSONField(_('Text'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') objects = SiteInterfaceDictionaryManager() diff --git a/project/settings/base.py b/project/settings/base.py index 588011d1..6a4a5836 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -82,6 +82,7 @@ EXTERNAL_APPS = [ 'django_extensions', 'rest_framework_simplejwt.token_blacklist', 'solo', + 'phonenumber_field', ] diff --git a/requirements/base.txt b/requirements/base.txt index 20a87346..3d7987c0 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -17,6 +17,7 @@ djangorestframework-xml celery amqp>=2.4.0 geoip2==2.9.0 +django-phonenumber-field[phonenumbers]==2.1.0 # auth socials djangorestframework-oauth From c1738478abb3471511d15f2952ea4f6570b8d0b3 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 13:24:37 +0300 Subject: [PATCH 06/24] added new model Review --- apps/establishment/admin.py | 11 +++++-- apps/establishment/models.py | 4 ++- apps/establishment/serializers.py | 15 +++++++++ apps/review/admin.py | 10 ++---- apps/review/migrations/0001_initial.py | 43 ++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 apps/review/migrations/0001_initial.py diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index d40950b1..d34141db 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -1,8 +1,10 @@ """Establishment admin conf.""" from django.contrib import admin -from establishment import models from django.contrib.contenttypes.admin import GenericTabularInline + +from establishment import models from main.models import Award, MetaDataContent +from review import models as review_models @admin.register(models.EstablishmentType) @@ -25,10 +27,15 @@ class MetaDataContentInline(GenericTabularInline): extra = 0 +class ReviewInline(GenericTabularInline): + model = review_models.Review + extra = 0 + + @admin.register(models.Establishment) class EstablishmentAdmin(admin.ModelAdmin): """Establishment admin.""" - inlines = [AwardInline, MetaDataContentInline] + inlines = [AwardInline, MetaDataContentInline, ReviewInline] @admin.register(models.EstablishmentSchedule) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 56cc531c..0a2a8831 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,11 +1,12 @@ """Establishment models.""" +from django.contrib.contenttypes import fields as generic from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ + from location.models import Address from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, TraslatedFieldsMixin, BaseAttributes) -from django.contrib.contenttypes import fields as generic # todo: establishment type&subtypes check @@ -88,6 +89,7 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): verbose_name=_('Price level')) awards = generic.GenericRelation(to='main.Award') tags = generic.GenericRelation(to='main.MetaDataContent') + reviews = generic.GenericRelation(to='review.Review') class Meta: """Meta class.""" diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 49788db3..fef87cb5 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -1,8 +1,10 @@ """Establishment serializers.""" from rest_framework import serializers + from establishment import models from location.serializers import AddressSerializer from main.serializers import MetaDataContentSerializer, AwardSerializer +from review import models as review_models from timetable.models import Timetable @@ -46,6 +48,16 @@ class EstablishmentScheduleSerializer(serializers.ModelSerializer): ) +class ReviewSerializer(serializers.ModelSerializer): + """Serializer for model Review.""" + class Meta: + """Meta class.""" + model = review_models.Review + fields = ( + 'text', + ) + + class EstablishmentSerializer(serializers.ModelSerializer): """Serializer for Establishment model.""" @@ -59,6 +71,8 @@ class EstablishmentSerializer(serializers.ModelSerializer): schedule = EstablishmentScheduleSerializer(source='schedule.schedule', many=True, allow_null=True) + reviews = ReviewSerializer(source='reviews.last', + allow_null=True) class Meta: """Meta class.""" @@ -79,4 +93,5 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', + 'reviews', ) diff --git a/apps/review/admin.py b/apps/review/admin.py index f3aeca39..cbd0bf94 100644 --- a/apps/review/admin.py +++ b/apps/review/admin.py @@ -1,7 +1,3 @@ -from django.contrib import admin -from review import models - - -@admin.register(models.Review) -class ReviewAdminModel(admin.ModelAdmin): - """Admin model for model Review.""" +# @admin.register(models.Review) +# class ReviewAdminModel(admin.ModelAdmin): +# """Admin model for model Review.""" diff --git a/apps/review/migrations/0001_initial.py b/apps/review/migrations/0001_initial.py new file mode 100644 index 00000000..3deac75e --- /dev/null +++ b/apps/review/migrations/0001_initial.py @@ -0,0 +1,43 @@ +# Generated by Django 2.2.4 on 2019-09-01 09:32 + +import django.core.validators +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('translation', '0002_siteinterfacedictionary'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Review', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('object_id', models.PositiveIntegerField()), + ('text', models.TextField(verbose_name='Text')), + ('status', models.PositiveSmallIntegerField(choices=[(0, 'To investigate'), (1, 'To review'), (2, 'Ready')], default=0)), + ('published_at', models.DateTimeField(blank=True, default=None, help_text='Review published datetime', null=True, verbose_name='Publish datetime')), + ('vintage', models.IntegerField(validators=[django.core.validators.MinValueValidator(1900), django.core.validators.MaxValueValidator(2100)], verbose_name='Year of review')), + ('child', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='review.Review', verbose_name='Child review')), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), + ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='review_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')), + ('language', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='translation.Language', verbose_name='Review language')), + ('modified_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='review_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by')), + ('reviewer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to=settings.AUTH_USER_MODEL, verbose_name='Reviewer')), + ], + options={ + 'verbose_name': 'Review', + 'verbose_name_plural': 'Reviews', + }, + ), + ] From 3f90ef6dab6353fee287a79c0ec526724cca8b49 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 13:29:17 +0300 Subject: [PATCH 07/24] fix merge --- apps/establishment/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 68b8872e..8f315fff 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,12 +1,14 @@ """Establishment models.""" from functools import reduce + +from django.contrib.contenttypes import fields as generic from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ + from location.models import Address from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, TraslatedFieldsMixin, BaseAttributes) -from django.contrib.contenttypes import fields as generic # todo: establishment type&subtypes check @@ -100,6 +102,7 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): verbose_name=_('Price level')) awards = generic.GenericRelation(to='main.Award') tags = generic.GenericRelation(to='main.MetaDataContent') + reviews = generic.GenericRelation(to='review.Review') objects = EstablishmentQuerySet.as_manager() From ef59216feb9592871f54ec8c3322f4c08cefad32 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Sun, 1 Sep 2019 13:39:01 +0300 Subject: [PATCH 08/24] change contacts for est. --- apps/establishment/admin.py | 15 ++----- .../migrations/0007_auto_20190901_1032.py | 30 ++++++++++++++ .../0008_contactemail_contactphone.py | 39 +++++++++++++++++++ apps/establishment/models.py | 19 ++------- apps/establishment/serializers.py | 21 ++-------- .../migrations/0013_auto_20190901_1032.py | 35 +++++++++++++++++ .../migrations/0009_auto_20190901_1032.py | 29 ++++++++++++++ .../migrations/0003_auto_20190901_1032.py | 19 +++++++++ 8 files changed, 163 insertions(+), 44 deletions(-) create mode 100644 apps/establishment/migrations/0007_auto_20190901_1032.py create mode 100644 apps/establishment/migrations/0008_contactemail_contactphone.py create mode 100644 apps/main/migrations/0013_auto_20190901_1032.py create mode 100644 apps/news/migrations/0009_auto_20190901_1032.py create mode 100644 apps/translation/migrations/0003_auto_20190901_1032.py diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index a5209c3d..37a2e8cb 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -37,21 +37,12 @@ class ContactEmailInline(admin.TabularInline): extra = 0 -@admin.register(models.Contact) -class ContactAdmin(admin.ModelAdmin): - """Contact admin.""" - inlines = [ContactPhoneInline, ContactEmailInline, ] - - -class ContactsInline(admin.TabularInline): - model = models.Contact - extra = 0 - - @admin.register(models.Establishment) class EstablishmentAdmin(admin.ModelAdmin): """Establishment admin.""" - inlines = [AwardInline, MetaDataContentInline, ContactsInline, ] + inlines = [ + AwardInline, MetaDataContentInline, + ContactPhoneInline, ContactEmailInline] @admin.register(models.EstablishmentSchedule) diff --git a/apps/establishment/migrations/0007_auto_20190901_1032.py b/apps/establishment/migrations/0007_auto_20190901_1032.py new file mode 100644 index 00000000..eb6c6a4a --- /dev/null +++ b/apps/establishment/migrations/0007_auto_20190901_1032.py @@ -0,0 +1,30 @@ +# Generated by Django 2.2.4 on 2019-09-01 10:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0006_merge_20190901_0846'), + ] + + operations = [ + migrations.RemoveField( + model_name='contactemail', + name='contact', + ), + migrations.RemoveField( + model_name='contactphone', + name='contact', + ), + migrations.DeleteModel( + name='Contact', + ), + migrations.DeleteModel( + name='ContactEmail', + ), + migrations.DeleteModel( + name='ContactPhone', + ), + ] diff --git a/apps/establishment/migrations/0008_contactemail_contactphone.py b/apps/establishment/migrations/0008_contactemail_contactphone.py new file mode 100644 index 00000000..bda629ed --- /dev/null +++ b/apps/establishment/migrations/0008_contactemail_contactphone.py @@ -0,0 +1,39 @@ +# Generated by Django 2.2.4 on 2019-09-01 10:36 + +from django.db import migrations, models +import django.db.models.deletion +import phonenumber_field.modelfields + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0007_auto_20190901_1032'), + ] + + operations = [ + migrations.CreateModel( + name='ContactPhone', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('phone', phonenumber_field.modelfields.PhoneNumberField(max_length=128)), + ('establishment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='phones', to='establishment.Establishment')), + ], + options={ + 'verbose_name': 'contact phone', + 'verbose_name_plural': 'contact phones', + }, + ), + migrations.CreateModel( + name='ContactEmail', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.EmailField(max_length=254)), + ('establishment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='emails', to='establishment.Establishment')), + ], + options={ + 'verbose_name': 'contact email', + 'verbose_name_plural': 'contact emails', + }, + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 0c73b722..8f346564 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -165,21 +165,10 @@ class EstablishmentSchedule(BaseAttributes): verbose_name_plural = _('Establishment schedules') -class Contact(models.Model): - """Contact model.""" - establishment = models.ForeignKey( - Establishment, related_name='contacts', on_delete=models.CASCADE) - address = models.ForeignKey('location.Address', on_delete=models.CASCADE) - - class Meta: - verbose_name = _('contact') - verbose_name_plural = _('contacts') - - class ContactPhone(models.Model): """Contact phone model.""" - contact = models.ForeignKey( - Contact, related_name='phones', on_delete=models.CASCADE) + establishment = models.ForeignKey( + Establishment, related_name='phones', on_delete=models.CASCADE) phone = PhoneNumberField() class Meta: @@ -192,8 +181,8 @@ class ContactPhone(models.Model): class ContactEmail(models.Model): """Contact email model.""" - contact = models.ForeignKey( - Contact, related_name='emails', on_delete=models.CASCADE) + establishment = models.ForeignKey( + Establishment, related_name='emails', on_delete=models.CASCADE) email = models.EmailField() class Meta: diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 92c7bb1c..7e3a8085 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -24,21 +24,6 @@ class ContactEmailsSerializer(serializers.ModelSerializer): ] -class ContactSerializer(serializers.ModelSerializer): - """Contact serializer.""" - address = AddressSerializer(read_only=True) - phones = ContactPhonesSerializer(read_only=True, many=True,) - emails = ContactEmailsSerializer(read_only=True, many=True,) - - class Meta: - model = models.Contact - fields = [ - 'address', - 'phones', - 'emails' - ] - - class EstablishmentTypeSerializer(serializers.ModelSerializer): """Serializer for EstablishmentType model.""" @@ -92,7 +77,8 @@ class EstablishmentSerializer(serializers.ModelSerializer): schedule = EstablishmentScheduleSerializer(source='schedule.schedule', many=True, allow_null=True) - contacts = ContactSerializer(read_only=True, many=True, ) + phones = ContactPhonesSerializer(read_only=True, many=True, ) + emails = ContactEmailsSerializer(read_only=True, many=True, ) class Meta: """Meta class.""" @@ -113,7 +99,8 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', - 'contacts' + 'phones', + 'emails' ) diff --git a/apps/main/migrations/0013_auto_20190901_1032.py b/apps/main/migrations/0013_auto_20190901_1032.py new file mode 100644 index 00000000..95c86883 --- /dev/null +++ b/apps/main/migrations/0013_auto_20190901_1032.py @@ -0,0 +1,35 @@ +# Generated by Django 2.2.4 on 2019-09-01 10:32 + +from django.db import migrations, models +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0012_auto_20190829_1155'), + ] + + operations = [ + migrations.CreateModel( + name='Currency', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, verbose_name='name')), + ], + options={ + 'verbose_name': 'currency', + 'verbose_name_plural': 'currencies', + }, + ), + migrations.AlterField( + model_name='award', + name='title', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='title'), + ), + migrations.AlterField( + model_name='metadata', + name='label', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='label'), + ), + ] diff --git a/apps/news/migrations/0009_auto_20190901_1032.py b/apps/news/migrations/0009_auto_20190901_1032.py new file mode 100644 index 00000000..5a083240 --- /dev/null +++ b/apps/news/migrations/0009_auto_20190901_1032.py @@ -0,0 +1,29 @@ +# Generated by Django 2.2.4 on 2019-09-01 10:32 + +from django.db import migrations +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0008_auto_20190828_1522'), + ] + + operations = [ + migrations.AlterField( + model_name='news', + name='description', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='description'), + ), + migrations.AlterField( + model_name='news', + name='subtitle', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='subtitle'), + ), + migrations.AlterField( + model_name='news', + name='title', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='title'), + ), + ] diff --git a/apps/translation/migrations/0003_auto_20190901_1032.py b/apps/translation/migrations/0003_auto_20190901_1032.py new file mode 100644 index 00000000..85bf63eb --- /dev/null +++ b/apps/translation/migrations/0003_auto_20190901_1032.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-09-01 10:32 + +import django.contrib.postgres.fields.jsonb +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('translation', '0002_siteinterfacedictionary'), + ] + + operations = [ + migrations.AlterField( + model_name='siteinterfacedictionary', + name='text', + field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Text'), + ), + ] From 1494bbbf36d7f449c1ca297a54161aec8088fb5d Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 14:09:37 +0300 Subject: [PATCH 09/24] Merge branch 'feature/reviews' into develop # Conflicts: # apps/establishment/admin.py # apps/establishment/models.py # apps/establishment/serializers.py --- apps/establishment/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index ea4af485..4cd5e348 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -1,5 +1,6 @@ """Establishment serializers.""" from rest_framework import serializers + from establishment import models from location.serializers import AddressSerializer from main.serializers import MetaDataContentSerializer, AwardSerializer @@ -113,6 +114,6 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'awards', 'schedule', 'phones', - 'emails' + 'emails', 'reviews', ) From 1b001f303abdd3afa191836daa5a700ba151ef3f Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Sun, 1 Sep 2019 14:17:03 +0300 Subject: [PATCH 10/24] extended establishment api enpoint by attribute of 'employees' --- apps/establishment/admin.py | 5 +++ apps/establishment/models.py | 71 ++++++++++++++++++++++++++++++- apps/establishment/serializers.py | 17 ++++++++ apps/establishment/views.py | 5 ++- 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index d40950b1..9c02459e 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -34,3 +34,8 @@ class EstablishmentAdmin(admin.ModelAdmin): @admin.register(models.EstablishmentSchedule) class EstablishmentSchedule(admin.ModelAdmin): """Establishment schedule""" + + +@admin.register(models.Position) +class PositionAdmin(admin.ModelAdmin): + """Position admin.""" diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 68b8872e..340b96bb 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,12 +1,13 @@ """Establishment models.""" from functools import reduce +from django.contrib.contenttypes import fields as generic from django.core.exceptions import ValidationError from django.db import models +from django.utils import timezone from django.utils.translation import gettext_lazy as _ from location.models import Address from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, TraslatedFieldsMixin, BaseAttributes) -from django.contrib.contenttypes import fields as generic # todo: establishment type&subtypes check @@ -70,6 +71,14 @@ class EstablishmentQuerySet(models.QuerySet): else: return self.none() + def prefetch_actual_employees(self): + """Prefetch actual employees.""" + return self.prefetch_related( + models.Prefetch('establishmentemployee_set', + queryset=EstablishmentEmployee.objects.actual().select_related( + 'position'), + to_attr='actual_establishment_employees')) + class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): """Establishment model.""" @@ -123,6 +132,7 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): country = self.address.city.country return country.low_price, country.high_price + # todo: make via prefetch @property def subtypes(self): return EstablishmentSubType.objects.filter( @@ -141,6 +151,65 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): self.establishment_subtypes.add(establishment_subtype) +class Position(BaseAttributes, TraslatedFieldsMixin): + """Position model.""" + + name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), + help_text='{"en":"some text"}') + + class Meta: + """Meta class.""" + + verbose_name = _('Position') + verbose_name_plural = _('Positions') + + +class EstablishmentEmployeeQuerySet(models.QuerySet): + """Extended queryset for EstablishmEntemployee model.""" + + def actual(self): + """Actual objects..""" + now = timezone.now() + return self.filter(models.Q(from_date__lte=now), + (models.Q(to_date__gte=now) | + models.Q(to_date__isnull=True))) + + +class EstablishmentEmployee(BaseAttributes): + """EstablishmentEmployee model.""" + + establishment = models.ForeignKey(Establishment, on_delete=models.PROTECT, + verbose_name=_('Establishment')) + employee = models.ForeignKey('establishment.Employee', on_delete=models.PROTECT, + verbose_name=_('Employee')) + from_date = models.DateTimeField(default=timezone.now, verbose_name=_('From date')) + to_date = models.DateTimeField(blank=True, null=True, default=None, + verbose_name=_('To date')) + position = models.ForeignKey(Position, on_delete=models.PROTECT, + verbose_name=_('Position')) + + objects = EstablishmentEmployeeQuerySet.as_manager() + + +class Employee(BaseAttributes): + """Employee model.""" + + user = models.OneToOneField('account.User', on_delete=models.PROTECT, + null=True, blank=True, default=None, + verbose_name=_('User')) + name = models.CharField(max_length=255, verbose_name=_('Last name')) + establishments = models.ManyToManyField(Establishment, related_name='employees', + through=EstablishmentEmployee) + awards = generic.GenericRelation(to='main.Award') + tags = generic.GenericRelation(to='main.MetaDataContent') + + class Meta: + """Meta class.""" + + verbose_name = _('Employee') + verbose_name_plural = _('Employees') + + class EstablishmentScheduleQuerySet(models.QuerySet): """QuerySet for model EstablishmentSchedule""" diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 49788db3..4da3f139 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -46,6 +46,20 @@ class EstablishmentScheduleSerializer(serializers.ModelSerializer): ) +class EstablishmentEmployeeSerializer(serializers.ModelSerializer): + """Serializer for actual employees.""" + + id = serializers.IntegerField(source='employee.id') + name = serializers.CharField(source='employee.name') + position_translated = serializers.CharField(source='position.name_translated') + + class Meta: + """Meta class.""" + + model = models.Employee + fields = ('id', 'name', 'position_translated') + + class EstablishmentSerializer(serializers.ModelSerializer): """Serializer for Establishment model.""" @@ -59,6 +73,8 @@ class EstablishmentSerializer(serializers.ModelSerializer): schedule = EstablishmentScheduleSerializer(source='schedule.schedule', many=True, allow_null=True) + employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees', + many=True) class Meta: """Meta class.""" @@ -79,4 +95,5 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', + 'employees', ) diff --git a/apps/establishment/views.py b/apps/establishment/views.py index 459aeeac..525118e2 100644 --- a/apps/establishment/views.py +++ b/apps/establishment/views.py @@ -10,9 +10,12 @@ class EstablishmentListView(JWTGenericViewMixin, generics.ListAPIView): permission_classes = (permissions.AllowAny,) serializer_class = serializers.EstablishmentSerializer - queryset = models.Establishment.objects.all() filter_class = filters.EstablishmentFilter + def get_queryset(self): + """Overrided method 'get_queryset'.""" + return models.Establishment.objects.all().prefetch_actual_employees() + class EstablishmentRetrieveView(JWTGenericViewMixin, generics.RetrieveAPIView): """Resource for getting a establishment.""" From 305da0e008886598788e89fdbd2462c9799bd7f7 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 14:31:42 +0300 Subject: [PATCH 11/24] merge migrations --- .../migrations/0009_merge_20190901_1131.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 apps/establishment/migrations/0009_merge_20190901_1131.py diff --git a/apps/establishment/migrations/0009_merge_20190901_1131.py b/apps/establishment/migrations/0009_merge_20190901_1131.py new file mode 100644 index 00000000..e5a59f4d --- /dev/null +++ b/apps/establishment/migrations/0009_merge_20190901_1131.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.4 on 2019-09-01 11:31 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0006_comment'), + ('establishment', '0008_contactemail_contactphone'), + ] + + operations = [ + ] From abecc6f99a8009dbe0f459ea8c7bdf3071502fda Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Sun, 1 Sep 2019 14:42:41 +0300 Subject: [PATCH 12/24] update migrations --- .../migrations/0009_merge_20190901_1132.py | 14 -------------- ...20190901_1132.py => 0010_auto_20190901_1142.py} | 4 ++-- 2 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 apps/establishment/migrations/0009_merge_20190901_1132.py rename apps/establishment/migrations/{0010_auto_20190901_1132.py => 0010_auto_20190901_1142.py} (97%) diff --git a/apps/establishment/migrations/0009_merge_20190901_1132.py b/apps/establishment/migrations/0009_merge_20190901_1132.py deleted file mode 100644 index 13be40d7..00000000 --- a/apps/establishment/migrations/0009_merge_20190901_1132.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 2.2.4 on 2019-09-01 11:32 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('establishment', '0008_contactemail_contactphone'), - ('establishment', '0006_comment'), - ] - - operations = [ - ] diff --git a/apps/establishment/migrations/0010_auto_20190901_1132.py b/apps/establishment/migrations/0010_auto_20190901_1142.py similarity index 97% rename from apps/establishment/migrations/0010_auto_20190901_1132.py rename to apps/establishment/migrations/0010_auto_20190901_1142.py index c588a012..9a76424b 100644 --- a/apps/establishment/migrations/0010_auto_20190901_1132.py +++ b/apps/establishment/migrations/0010_auto_20190901_1142.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-09-01 11:32 +# Generated by Django 2.2.4 on 2019-09-01 11:42 from django.conf import settings from django.db import migrations, models @@ -11,7 +11,7 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('establishment', '0009_merge_20190901_1132'), + ('establishment', '0009_merge_20190901_1131'), ] operations = [ From ddabac60d1e5e4a8f29e44beea0b4a9db1dd098c Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Sun, 1 Sep 2019 14:53:46 +0300 Subject: [PATCH 13/24] Fix establishment retrieve view --- apps/establishment/views.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/establishment/views.py b/apps/establishment/views.py index 525118e2..10f47b01 100644 --- a/apps/establishment/views.py +++ b/apps/establishment/views.py @@ -5,24 +5,25 @@ from utils.views import JWTGenericViewMixin from establishment import filters -class EstablishmentListView(JWTGenericViewMixin, generics.ListAPIView): - """Resource for getting a list of establishments.""" +class EstablishmentMixin: + """Establishment mixin.""" permission_classes = (permissions.AllowAny,) serializer_class = serializers.EstablishmentSerializer - filter_class = filters.EstablishmentFilter def get_queryset(self): """Overrided method 'get_queryset'.""" return models.Establishment.objects.all().prefetch_actual_employees() -class EstablishmentRetrieveView(JWTGenericViewMixin, generics.RetrieveAPIView): - """Resource for getting a establishment.""" +class EstablishmentListView(EstablishmentMixin, JWTGenericViewMixin, generics.ListAPIView): + """Resource for getting a list of establishments.""" - permission_classes = (permissions.AllowAny,) - serializer_class = serializers.EstablishmentSerializer - queryset = models.Establishment.objects.all() + filter_class = filters.EstablishmentFilter + + +class EstablishmentRetrieveView(EstablishmentMixin, JWTGenericViewMixin, generics.RetrieveAPIView): + """Resource for getting a establishment.""" class EstablishmentTypeListView(JWTGenericViewMixin, generics.ListAPIView): From 360f88d996ab63db5eb9cdf12a361de6de297e1f Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 15:01:55 +0300 Subject: [PATCH 14/24] replace textfield with tjsonfield in model Review --- apps/establishment/serializers.py | 4 +++- .../migrations/0002_remove_review_text.py | 17 ++++++++++++++++ apps/review/migrations/0003_review_text.py | 20 +++++++++++++++++++ apps/review/models.py | 9 ++++++--- 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 apps/review/migrations/0002_remove_review_text.py create mode 100644 apps/review/migrations/0003_review_text.py diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 7655e070..cf26306d 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -68,11 +68,13 @@ class EstablishmentScheduleSerializer(serializers.ModelSerializer): class ReviewSerializer(serializers.ModelSerializer): """Serializer for model Review.""" + text_translated = serializers.CharField(read_only=True) + class Meta: """Meta class.""" model = review_models.Review fields = ( - 'text', + 'text_translated', ) diff --git a/apps/review/migrations/0002_remove_review_text.py b/apps/review/migrations/0002_remove_review_text.py new file mode 100644 index 00000000..45e58d1f --- /dev/null +++ b/apps/review/migrations/0002_remove_review_text.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.4 on 2019-09-01 11:47 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('review', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='review', + name='text', + ), + ] diff --git a/apps/review/migrations/0003_review_text.py b/apps/review/migrations/0003_review_text.py new file mode 100644 index 00000000..708fccd1 --- /dev/null +++ b/apps/review/migrations/0003_review_text.py @@ -0,0 +1,20 @@ +# Generated by Django 2.2.4 on 2019-09-01 11:53 + +from django.db import migrations + +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('review', '0002_remove_review_text'), + ] + + operations = [ + migrations.AddField( + model_name='review', + name='text', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"Text review"}', null=True, verbose_name='text'), + ), + ] diff --git a/apps/review/models.py b/apps/review/models.py index ff0308e5..97b910dd 100644 --- a/apps/review/models.py +++ b/apps/review/models.py @@ -3,7 +3,8 @@ from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models from django.utils.translation import gettext_lazy as _ -from utils.models import BaseAttributes +from utils.models import BaseAttributes, TraslatedFieldsMixin +from utils.models import TJSONField class ReviewQuerySet(models.QuerySet): @@ -18,7 +19,7 @@ class ReviewQuerySet(models.QuerySet): return self.filter(vintage=year) -class Review(BaseAttributes): +class Review(BaseAttributes, TraslatedFieldsMixin): """Review model""" TO_INVESTIGATE = 0 TO_REVIEW = 1 @@ -33,6 +34,9 @@ class Review(BaseAttributes): related_name='reviews', on_delete=models.CASCADE, verbose_name=_('Reviewer')) + text = TJSONField( + _('text'), null=True, blank=True, + default=None, help_text='{"en-GB":"Text review"}') content_type = models.ForeignKey(generic.ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') @@ -40,7 +44,6 @@ class Review(BaseAttributes): on_delete=models.CASCADE, related_name='reviews', verbose_name=_('Review language')) - text = models.TextField(verbose_name=_('Text')) status = models.PositiveSmallIntegerField(choices=REVIEW_STATUSES, default=TO_INVESTIGATE) child = models.ForeignKey('self', blank=True, default=None, null=True, From 0da20bbcd13512cd073e4e23716892503543fb0a Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Sun, 1 Sep 2019 15:05:25 +0300 Subject: [PATCH 15/24] added awards to employee --- apps/establishment/serializers.py | 2 ++ apps/main/serializers.py | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 0dc946c4..fc013d86 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -90,12 +90,14 @@ class CommentSerializer(serializers.ModelSerializer): 'image' ) + class EstablishmentEmployeeSerializer(serializers.ModelSerializer): """Serializer for actual employees.""" id = serializers.IntegerField(source='employee.id') name = serializers.CharField(source='employee.name') position_translated = serializers.CharField(source='position.name_translated') + awards = AwardSerializer(source='employee.awards', many=True) class Meta: """Meta class.""" diff --git a/apps/main/serializers.py b/apps/main/serializers.py index 478093d0..444d8f57 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -73,6 +73,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer): class AwardSerializer(serializers.ModelSerializer): """Award serializer.""" + title_translated = serializers.CharField(read_only=True, allow_null=True) class Meta: From 45f990af4ce0f81c93c06c22930f17bf9fe3b6a3 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Sun, 1 Sep 2019 15:07:27 +0300 Subject: [PATCH 16/24] update serializer --- apps/establishment/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index d8066562..357bbe4b 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -105,7 +105,7 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer): """Meta class.""" model = models.Employee - fields = ('id', 'name', 'position_translated') + fields = ('id', 'name', 'position_translated', 'awards') class EstablishmentSerializer(serializers.ModelSerializer): From 998204b7c52340a27c8a5c525d01f20709f9e061 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 15:24:55 +0300 Subject: [PATCH 17/24] added created field to comments serializer --- apps/establishment/serializers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 357bbe4b..cd444ef7 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -1,5 +1,6 @@ """Establishment serializers.""" from rest_framework import serializers + from establishment import models from location.serializers import AddressSerializer from main.serializers import MetaDataContentSerializer, AwardSerializer @@ -80,16 +81,17 @@ class ReviewSerializer(serializers.ModelSerializer): class CommentSerializer(serializers.ModelSerializer): """Comment serializer""" nickname = serializers.CharField(source='author.username') - image = serializers.ImageField(source='author.image') + profile_pic = serializers.ImageField(source='author.image') class Meta: """Serializer for model Comment""" model = models.Comment fields = ( + 'created', 'text', 'mark', 'nickname', - 'image' + 'profile_pic' ) From c85347b53a408fde7e6b4bdab13f6a73c001a5fd Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Sun, 1 Sep 2019 16:18:17 +0300 Subject: [PATCH 18/24] add menu --- apps/establishment/admin.py | 22 +++++ .../migrations/0011_menu_plate.py | 53 +++++++++++ .../migrations/0012_auto_20190901_1251.py | 19 ++++ apps/establishment/models.py | 87 +++++++++---------- apps/establishment/serializers.py | 30 ++++++- apps/main/admin.py | 7 ++ apps/main/serializers.py | 10 +++ 7 files changed, 181 insertions(+), 47 deletions(-) create mode 100644 apps/establishment/migrations/0011_menu_plate.py create mode 100644 apps/establishment/migrations/0012_auto_20190901_1251.py diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index 93c669ef..05ab36dd 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -4,6 +4,7 @@ from django.contrib.contenttypes.admin import GenericTabularInline from establishment import models from main.models import Award, MetaDataContent from review import models as review_models +from django.utils.translation import gettext_lazy as _ @admin.register(models.EstablishmentType) @@ -65,3 +66,24 @@ class EstablishmentComment(admin.ModelAdmin): @admin.register(models.Position) class PositionAdmin(admin.ModelAdmin): """Position admin.""" + + +class PlateInline(admin.TabularInline): + """Plate inline admin""" + model = models.Plate + extra = 0 + + +@admin.register(models.Menu) +class MenuAdmin(admin.ModelAdmin): + """Menu admin.""" + list_display = ['id', 'category_translated'] + inlines = [ + PlateInline, + ] + + def category_translated(self, obj): + """Get user's short name.""" + return obj.category_translated + + category_translated.short_description = _('category') \ No newline at end of file diff --git a/apps/establishment/migrations/0011_menu_plate.py b/apps/establishment/migrations/0011_menu_plate.py new file mode 100644 index 00000000..e0d50925 --- /dev/null +++ b/apps/establishment/migrations/0011_menu_plate.py @@ -0,0 +1,53 @@ +# Generated by Django 2.2.4 on 2019-09-01 12:11 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('main', '0013_auto_20190901_1032'), + ('establishment', '0010_auto_20190901_1142'), + ] + + operations = [ + migrations.CreateModel( + name='Menu', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('category', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='name')), + ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menu_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')), + ('establishment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='establishment.Establishment', verbose_name='establishment')), + ('modified_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menu_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by')), + ], + options={ + 'verbose_name': 'menu', + 'verbose_name_plural': 'menu', + }, + bases=(utils.models.TraslatedFieldsMixin, models.Model), + ), + migrations.CreateModel( + name='Plate', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='name')), + ('description', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='description')), + ('price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='price')), + ('is_signature_plate', models.BooleanField(verbose_name='is signature plate')), + ('currency', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Currency', verbose_name='currency')), + ('menu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='establishment.Menu', verbose_name='menu')), + ], + options={ + 'verbose_name': 'plate', + 'verbose_name_plural': 'plates', + }, + bases=(utils.models.TraslatedFieldsMixin, models.Model), + ), + ] diff --git a/apps/establishment/migrations/0012_auto_20190901_1251.py b/apps/establishment/migrations/0012_auto_20190901_1251.py new file mode 100644 index 00000000..3828c997 --- /dev/null +++ b/apps/establishment/migrations/0012_auto_20190901_1251.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-09-01 12:51 + +from django.db import migrations +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0011_menu_plate'), + ] + + operations = [ + migrations.AlterField( + model_name='menu', + name='category', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='category'), + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index e31fdc23..b44ee4f9 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -277,52 +277,47 @@ class ContactEmail(models.Model): # price_glass_max = models.DecimalField( # _('price max'), max_digits=14, decimal_places=2) # -# -# class Plate(TraslatedFieldsMixin, models.Model): -# """Plate model.""" -# -# STARTER = 0 -# MAIN = 1 -# COURSE = 2 -# DESSERT = 3 -# -# PLATE_TYPE_CHOICES = ( -# (STARTER, _('starter')), -# (MAIN, _('main')), -# (COURSE, _('course')), -# (DESSERT, _('dessert')), -# ) -# name = models.CharField(_('name'), max_length=255) -# plate_type = models.PositiveSmallIntegerField(_('plate_type'), choices=PLATE_TYPE_CHOICES) -# description = TJSONField( -# blank=True, null=True, default=None, verbose_name=_('description'), -# help_text='{"en-GB":"some text"}') -# price = models.DecimalField( -# _('price'), max_digits=14, decimal_places=2) -# is_signature_plate = models.BooleanField(_('is signature plate')) -# currency = models.ForeignKey( -# 'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE) -# -# menu = models.ManyToManyField(to='Plate', verbose_name=_(''), through='establishment.Menu') -# -# class Meta: -# verbose_name = _('plate') -# verbose_name_plural = _('plates') -# -# def __str__(self): -# return f'plate_id:{self.id}' -# -# -# class Menu(TraslatedFieldsMixin, BaseAttributes): -# """Menu model.""" -# establishment = models.ForeignKey( -# 'establishment.Establishment', verbose_name=_('establishment'), -# on_delete=models.CASCADE) -# plate = models.ForeignKey(Plate, verbose_name=_('menu'), on_delete=models.CASCADE) -# -# class Meta: -# verbose_name = _('menu') -# verbose_name_plural = _('menu') + + +class Plate(TraslatedFieldsMixin, models.Model): + """Plate model.""" + + name = TJSONField( + blank=True, null=True, default=None, verbose_name=_('name'), + help_text='{"en-GB":"some text"}') + description = TJSONField( + blank=True, null=True, default=None, verbose_name=_('description'), + help_text='{"en-GB":"some text"}') + price = models.DecimalField( + _('price'), max_digits=14, decimal_places=2) + is_signature_plate = models.BooleanField(_('is signature plate')) + currency = models.ForeignKey( + 'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE) + + menu = models.ForeignKey( + 'establishment.Menu', verbose_name=_('menu'), on_delete=models.CASCADE) + + class Meta: + verbose_name = _('plate') + verbose_name_plural = _('plates') + + def __str__(self): + return f'plate_id:{self.id}' + + +class Menu(TraslatedFieldsMixin, BaseAttributes): + """Menu model.""" + category = TJSONField( + blank=True, null=True, default=None, verbose_name=_('category'), + help_text='{"en-GB":"some text"}') + establishment = models.ForeignKey( + 'establishment.Establishment', verbose_name=_('establishment'), + on_delete=models.CASCADE) + + class Meta: + verbose_name = _('menu') + verbose_name_plural = _('menu') + class CommentQuerySet(models.QuerySet): """QuerySets for Comment model.""" diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index cd444ef7..f46cbc4e 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -3,7 +3,7 @@ from rest_framework import serializers from establishment import models from location.serializers import AddressSerializer -from main.serializers import MetaDataContentSerializer, AwardSerializer +from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer from review import models as review_models from timetable.models import Timetable @@ -26,6 +26,32 @@ class ContactEmailsSerializer(serializers.ModelSerializer): ] +class PlateSerializer(serializers.ModelSerializer): + currency = CurrencySerializer(read_only=True) + + class Meta: + model = models.Plate + fields = [ + 'name_translated', + 'currency', + 'price', + 'is_signature_plate', + ] + + +class MenuSerializers(serializers.ModelSerializer): + plates = PlateSerializer(read_only=True, many=True, source='plate_set') + category_translated = serializers.CharField(read_only=True) + + class Meta: + model = models.Menu + fields = [ + 'id', + 'category_translated', + 'plates' + ] + + class EstablishmentTypeSerializer(serializers.ModelSerializer): """Serializer for EstablishmentType model.""" @@ -129,6 +155,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): comments = CommentSerializer(many=True, allow_null=True) employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees', many=True) + menu = MenuSerializers(source='menu_set', many=True, read_only=True) class Meta: """Meta class.""" @@ -154,4 +181,5 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'reviews', 'comments', 'employees', + 'menu', ) diff --git a/apps/main/admin.py b/apps/main/admin.py index 9ff6606a..2d512868 100644 --- a/apps/main/admin.py +++ b/apps/main/admin.py @@ -39,3 +39,10 @@ class MetaDataCategoryAdmin(admin.ModelAdmin): @admin.register(models.MetaDataContent) class MetaDataContentAdmin(admin.ModelAdmin): """MetaDataContent admin""" + + +@admin.register(models.Currency) +class CurrencContentAdmin(admin.ModelAdmin): + """CurrencContent admin""" + + diff --git a/apps/main/serializers.py b/apps/main/serializers.py index 444d8f57..0348026c 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -96,4 +96,14 @@ class MetaDataContentSerializer(serializers.ModelSerializer): fields = [ 'id', 'label_translated', + ] + + +class CurrencySerializer(serializers.ModelSerializer): + """Currency serializer""" + class Meta: + model = models.Currency + fields = [ + 'id', + 'name' ] \ No newline at end of file From 082a8a1470b248e13e41e55e62f43b3481b87685 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Sun, 1 Sep 2019 17:22:53 +0300 Subject: [PATCH 19/24] add fake best_price_menu --- apps/establishment/models.py | 8 ++++++++ apps/establishment/serializers.py | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index b44ee4f9..de2891af 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -152,6 +152,14 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): raise ValidationError('Establishment type of subtype does not match') self.establishment_subtypes.add(establishment_subtype) + @property + def best_price_menu(self): + return 150 + + @property + def best_price_carte(self): + return 200 + class Position(BaseAttributes, TraslatedFieldsMixin): """Position model.""" diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index f46cbc4e..74c7286c 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -157,6 +157,9 @@ class EstablishmentSerializer(serializers.ModelSerializer): many=True) menu = MenuSerializers(source='menu_set', many=True, read_only=True) + best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) + best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) + class Meta: """Meta class.""" @@ -182,4 +185,6 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'comments', 'employees', 'menu', + 'best_price_menu', + 'best_price_carte' ) From 6d6e1169a491aeaea829749ca45be8e7edadc50a Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Sun, 1 Sep 2019 17:30:39 +0300 Subject: [PATCH 20/24] extended establishment model (social) --- .../migrations/0013_auto_20190901_1428.py | 33 +++++++++++++++++++ apps/establishment/models.py | 8 +++++ apps/establishment/serializers.py | 4 +++ 3 files changed, 45 insertions(+) create mode 100644 apps/establishment/migrations/0013_auto_20190901_1428.py diff --git a/apps/establishment/migrations/0013_auto_20190901_1428.py b/apps/establishment/migrations/0013_auto_20190901_1428.py new file mode 100644 index 00000000..9e91b715 --- /dev/null +++ b/apps/establishment/migrations/0013_auto_20190901_1428.py @@ -0,0 +1,33 @@ +# Generated by Django 2.2.4 on 2019-09-01 14:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0012_auto_20190901_1251'), + ] + + operations = [ + migrations.AddField( + model_name='establishment', + name='booking', + field=models.URLField(blank=True, default=None, null=True, verbose_name='Booking URL'), + ), + migrations.AddField( + model_name='establishment', + name='facebook', + field=models.URLField(blank=True, default=None, null=True, verbose_name='Facebook URL'), + ), + migrations.AddField( + model_name='establishment', + name='lafourchette', + field=models.URLField(blank=True, default=None, null=True, verbose_name='Lafourchette URL'), + ), + migrations.AddField( + model_name='establishment', + name='twitter', + field=models.URLField(blank=True, default=None, null=True, verbose_name='Twitter URL'), + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index de2891af..41c4d721 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -108,6 +108,14 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): price_level = models.PositiveIntegerField(blank=True, null=True, default=None, verbose_name=_('Price level')) + facebook = models.URLField(blank=True, null=True, default=None, + verbose_name=_('Facebook URL')) + twitter = models.URLField(blank=True, null=True, default=None, + verbose_name=_('Twitter URL')) + lafourchette = models.URLField(blank=True, null=True, default=None, + verbose_name=_('Lafourchette URL')) + booking = models.URLField(blank=True, null=True, default=None, + verbose_name=_('Booking URL')) awards = generic.GenericRelation(to='main.Award') tags = generic.GenericRelation(to='main.MetaDataContent') reviews = generic.GenericRelation(to='review.Review') diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 74c7286c..6a2fd4f7 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -179,6 +179,10 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', + 'facebook', + 'twitter', + 'lafourchette', + 'booking', 'phones', 'emails', 'reviews', From e91a64ad6b925fdac71afab87fcc4d059e376ed0 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Sun, 1 Sep 2019 17:51:13 +0300 Subject: [PATCH 21/24] add website --- apps/establishment/models.py | 4 +++- apps/establishment/serializers.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 41c4d721..20a9755d 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -108,6 +108,8 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): price_level = models.PositiveIntegerField(blank=True, null=True, default=None, verbose_name=_('Price level')) + website = models.URLField(blank=True, null=True, default=None, + verbose_name=_('Web site URL')) facebook = models.URLField(blank=True, null=True, default=None, verbose_name=_('Facebook URL')) twitter = models.URLField(blank=True, null=True, default=None, @@ -115,7 +117,7 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): lafourchette = models.URLField(blank=True, null=True, default=None, verbose_name=_('Lafourchette URL')) booking = models.URLField(blank=True, null=True, default=None, - verbose_name=_('Booking URL')) + verbose_name=_('Booking URL')) awards = generic.GenericRelation(to='main.Award') tags = generic.GenericRelation(to='main.MetaDataContent') reviews = generic.GenericRelation(to='review.Review') diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 6a2fd4f7..c3bdc75e 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -179,6 +179,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', + 'website', 'facebook', 'twitter', 'lafourchette', From 2f692bacf32779930cb018a2587efa99f242bff7 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Sun, 1 Sep 2019 17:52:01 +0300 Subject: [PATCH 22/24] add migrate --- .../migrations/0014_establishment_website.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 apps/establishment/migrations/0014_establishment_website.py diff --git a/apps/establishment/migrations/0014_establishment_website.py b/apps/establishment/migrations/0014_establishment_website.py new file mode 100644 index 00000000..e685f469 --- /dev/null +++ b/apps/establishment/migrations/0014_establishment_website.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-09-01 14:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0013_auto_20190901_1428'), + ] + + operations = [ + migrations.AddField( + model_name='establishment', + name='website', + field=models.URLField(blank=True, default=None, null=True, verbose_name='Web site URL'), + ), + ] From e28435aba2934ddbeeadaf17b507c04f9a358900 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 1 Sep 2019 18:11:09 +0300 Subject: [PATCH 23/24] added preview image in establishment serializer --- apps/establishment/models.py | 2 ++ apps/establishment/serializers.py | 7 +++++++ project/settings/base.py | 1 + 3 files changed, 10 insertions(+) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index b44ee4f9..15a14e04 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,11 +1,13 @@ """Establishment models.""" from functools import reduce + from django.contrib.contenttypes import fields as generic from django.core.exceptions import ValidationError from django.db import models from django.utils import timezone from django.utils.translation import gettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField + from location.models import Address from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, TraslatedFieldsMixin, BaseAttributes) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index f46cbc4e..1c2e0d1d 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -156,6 +156,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees', many=True) menu = MenuSerializers(source='menu_set', many=True, read_only=True) + preview_image = serializers.SerializerMethodField() class Meta: """Meta class.""" @@ -172,6 +173,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'type', 'subtypes', 'image', + 'preview_image', 'address', 'tags', 'awards', @@ -183,3 +185,8 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'employees', 'menu', ) + + def get_preview_image(self, obj): + """Get preview image""" + return obj.get_full_image_url(request=self.context.get('request'), + thumbnail_key='establishment_preview') diff --git a/project/settings/base.py b/project/settings/base.py index 3d054331..c68d6841 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -323,6 +323,7 @@ THUMBNAIL_ALIASES = { 'large': {'size': (1500, 0), }, 'default': {'size': (300, 200), 'crop': True}, 'gallery': {'size': (240, 160), 'crop': True}, + 'establishment_preview': {'size': (300, 280), 'crop': True}, } } From 664412d0f494f5d9db2109e2071e40a715e6a380 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Mon, 2 Sep 2019 09:56:55 +0300 Subject: [PATCH 24/24] establishment list view - added filter by country code --- apps/establishment/models.py | 4 ++++ apps/establishment/views.py | 6 ++++++ apps/news/filters.py | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 62f4c49f..41e2ae72 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -74,6 +74,10 @@ class EstablishmentQuerySet(models.QuerySet): else: return self.none() + def by_country_code(self, code): + """Return establishments by country code""" + return self.filter(address__city__country__code=code) + def prefetch_actual_employees(self): """Prefetch actual employees.""" return self.prefetch_related( diff --git a/apps/establishment/views.py b/apps/establishment/views.py index 10f47b01..146c6f9b 100644 --- a/apps/establishment/views.py +++ b/apps/establishment/views.py @@ -21,6 +21,12 @@ class EstablishmentListView(EstablishmentMixin, JWTGenericViewMixin, generics.Li filter_class = filters.EstablishmentFilter + def get_queryset(self): + """Overrided method 'get_queryset'.""" + return models.Establishment.objects.all()\ + .prefetch_actual_employees()\ + .by_country_code(code=self.request.country_code) + class EstablishmentRetrieveView(EstablishmentMixin, JWTGenericViewMixin, generics.RetrieveAPIView): """Resource for getting a establishment.""" diff --git a/apps/news/filters.py b/apps/news/filters.py index 7af3452d..c4462189 100644 --- a/apps/news/filters.py +++ b/apps/news/filters.py @@ -22,7 +22,7 @@ class NewsListFilterSet(django_filters.FilterSet): """Crappy search by title according to locale""" if value: locale = self.request.locale - filters = {f'{name}__{locale}': value} + filters = {f'{name}__{locale}__icontains': value} return queryset.filter(**filters) else: return queryset