Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # apps/establishment/urls/back.py
This commit is contained in:
commit
5a36613c97
|
|
@ -35,11 +35,8 @@ class PasswordResetSerializer(serializers.Serializer):
|
|||
if filters:
|
||||
filters.update({'is_active': True})
|
||||
user_qs = models.User.objects.filter(**filters)
|
||||
|
||||
if not user_qs.exists():
|
||||
raise utils_exceptions.UserNotFoundError()
|
||||
user = user_qs.first()
|
||||
|
||||
if user_qs.exists():
|
||||
user = user_qs.first()
|
||||
attrs['user'] = user
|
||||
return attrs
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class PasswordResetView(generics.GenericAPIView):
|
|||
"""Override create method"""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
if serializer.validated_data.get('user'):
|
||||
if not serializer.validated_data.get('user').is_anonymous:
|
||||
user = serializer.validated_data.pop('user')
|
||||
if settings.USE_CELERY:
|
||||
tasks.send_reset_password_email.delay(user_id=user.id,
|
||||
|
|
|
|||
39
apps/advertisement/migrations/0002_auto_20190917_1307.py
Normal file
39
apps/advertisement/migrations/0002_auto_20190917_1307.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-17 13:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('translation', '0003_auto_20190901_1032'),
|
||||
('advertisement', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='advertisement',
|
||||
name='source',
|
||||
field=models.PositiveSmallIntegerField(choices=[(0, 'Mobile'), (1, 'Web')], default=0, verbose_name='Source'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='advertisement',
|
||||
name='target_languages',
|
||||
field=models.ManyToManyField(to='translation.Language'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='advertisement',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='advertisement',
|
||||
name='block_level',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='advertisement',
|
||||
name='block_level',
|
||||
field=models.CharField(max_length=10, verbose_name='Block level')
|
||||
)
|
||||
]
|
||||
18
apps/advertisement/migrations/0003_auto_20190919_1344.py
Normal file
18
apps/advertisement/migrations/0003_auto_20190919_1344.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-19 13:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('advertisement', '0002_auto_20190917_1307'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='advertisement',
|
||||
name='source',
|
||||
field=models.PositiveSmallIntegerField(choices=[(0, 'Mobile'), (1, 'Web'), (2, 'All')], default=0, verbose_name='Source'),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,28 +1,22 @@
|
|||
"""Advertisement app models."""
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from utils.models import ProjectBaseMixin, ImageMixin
|
||||
from translation.models import Language
|
||||
from utils.models import ProjectBaseMixin, ImageMixin, PlatformMixin
|
||||
|
||||
|
||||
class Advertisement(ImageMixin, ProjectBaseMixin):
|
||||
class Advertisement(ImageMixin, ProjectBaseMixin, PlatformMixin):
|
||||
"""Advertisement model."""
|
||||
|
||||
LEVEL_1 = 1
|
||||
LEVEL_2 = 2
|
||||
LEVEL_3 = 3
|
||||
|
||||
BLOCK_LEVEL_CHOICES = (
|
||||
(LEVEL_1, _('Ad block level 1')),
|
||||
(LEVEL_2, _('Ad block level 2')),
|
||||
(LEVEL_3, _('Ad block level 3'))
|
||||
)
|
||||
|
||||
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
|
||||
url = models.URLField(verbose_name=_('Ad URL'))
|
||||
width = models.PositiveIntegerField(verbose_name=_('Block width'))
|
||||
height = models.PositiveIntegerField(verbose_name=_('Block height'))
|
||||
block_level = models.PositiveSmallIntegerField(choices=BLOCK_LEVEL_CHOICES,
|
||||
verbose_name=_('Block level'))
|
||||
block_level = models.CharField(verbose_name=_('Block level'), max_length=10)
|
||||
target_languages = models.ManyToManyField(Language)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Advertisement')
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from advertisement import models
|
||||
from translation.serializers import LanguageSerializer
|
||||
|
||||
|
||||
class AdvertisementSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -11,9 +12,11 @@ class AdvertisementSerializer(serializers.ModelSerializer):
|
|||
model = models.Advertisement
|
||||
fields = (
|
||||
'id',
|
||||
'uuid',
|
||||
'url',
|
||||
'image',
|
||||
'width',
|
||||
'height',
|
||||
'block_level',
|
||||
'source'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ from django.urls import path
|
|||
|
||||
from advertisement.views import web as views
|
||||
|
||||
app_name = 'advertisement'
|
||||
app_name = 'advertisements'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.AdvertisementListView.as_view(), name='list')
|
||||
path('<str:page>/', views.AdvertisementListView.as_view(), name='list')
|
||||
]
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ class AdvertisementListView(generics.ListAPIView):
|
|||
"""List view for model Advertisement"""
|
||||
pagination_class = None
|
||||
model = models.Advertisement
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
queryset = models.Advertisement.objects.all()
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
serializer_class = serializers.AdvertisementSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return models.Advertisement.objects\
|
||||
.filter(page__page_name__contains=self.kwargs['page'])\
|
||||
.filter(target_languages__locale=self.request.locale)
|
||||
|
|
|
|||
23
apps/authorization/migrations/0008_auto_20190919_1344.py
Normal file
23
apps/authorization/migrations/0008_auto_20190919_1344.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-19 13:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authorization', '0007_jwtaccesstoken_refresh_token'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='application',
|
||||
name='source',
|
||||
field=models.PositiveSmallIntegerField(choices=[(0, 'Mobile'), (1, 'Web'), (2, 'All')], default=0, verbose_name='Source'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='jwtrefreshtoken',
|
||||
name='source',
|
||||
field=models.PositiveSmallIntegerField(choices=[(0, 'Mobile'), (1, 'Web'), (2, 'All')], default=0, verbose_name='Source'),
|
||||
),
|
||||
]
|
||||
|
|
@ -48,8 +48,8 @@ class CollectionItemSerializer(serializers.ModelSerializer):
|
|||
fields = [
|
||||
'id',
|
||||
'collection',
|
||||
'item_type',
|
||||
'item_ids'
|
||||
'content_type',
|
||||
'object_id',
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -61,11 +61,6 @@ class EstablishmentAdmin(admin.ModelAdmin):
|
|||
ReviewInline, CommentInline]
|
||||
|
||||
|
||||
@admin.register(models.EstablishmentSchedule)
|
||||
class EstablishmentSchedule(admin.ModelAdmin):
|
||||
"""Establishment schedule"""
|
||||
|
||||
|
||||
@admin.register(models.Position)
|
||||
class PositionAdmin(admin.ModelAdmin):
|
||||
"""Position admin."""
|
||||
|
|
|
|||
18
apps/establishment/migrations/0019_position_priority.py
Normal file
18
apps/establishment/migrations/0019_position_priority.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-13 13:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('establishment', '0018_socialnetwork'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='position',
|
||||
name='priority',
|
||||
field=models.IntegerField(default=None, null=True, unique=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-18 12:07
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('establishment', '0020_merge_20190917_1415'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='EstablishmentSchedule',
|
||||
),
|
||||
]
|
||||
14
apps/establishment/migrations/0021_merge_20190919_0955.py
Normal file
14
apps/establishment/migrations/0021_merge_20190919_0955.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-19 09:55
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('establishment', '0020_merge_20190917_1415'),
|
||||
('establishment', '0019_position_priority'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
19
apps/establishment/migrations/0022_establishment_schedule.py
Normal file
19
apps/establishment/migrations/0022_establishment_schedule.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-18 14:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('timetable', '0001_initial'),
|
||||
('establishment', '0021_delete_establishmentschedule'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='establishment',
|
||||
name='schedule',
|
||||
field=models.ManyToManyField(related_name='schedule', to='timetable.Timetable', verbose_name='Establishment schedule'),
|
||||
),
|
||||
]
|
||||
14
apps/establishment/migrations/0023_merge_20190919_1136.py
Normal file
14
apps/establishment/migrations/0023_merge_20190919_1136.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-19 11:36
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('establishment', '0021_merge_20190919_0955'),
|
||||
('establishment', '0022_establishment_schedule'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
|
|
@ -262,6 +262,13 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
|||
booking = models.URLField(blank=True, null=True, default=None,
|
||||
verbose_name=_('Booking URL'))
|
||||
is_publish = models.BooleanField(default=False, verbose_name=_('Publish status'))
|
||||
schedule = models.ManyToManyField(to='timetable.Timetable',
|
||||
verbose_name=_('Establishment schedule'),
|
||||
related_name='schedule')
|
||||
# holidays_from = models.DateTimeField(verbose_name=_('Holidays from'),
|
||||
# help_text=_('Holidays closing date from'))
|
||||
# holidays_to = models.DateTimeField(verbose_name=_('Holidays to'),
|
||||
# help_text=_('Holidays closing date to'))
|
||||
awards = generic.GenericRelation(to='main.Award')
|
||||
tags = generic.GenericRelation(to='main.MetaDataContent')
|
||||
reviews = generic.GenericRelation(to='review.Review')
|
||||
|
|
@ -335,6 +342,8 @@ class Position(BaseAttributes, TranslatedFieldsMixin):
|
|||
name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'),
|
||||
help_text='{"en":"some text"}')
|
||||
|
||||
priority = models.IntegerField(unique=True, null=True, default=None)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
|
|
@ -392,23 +401,6 @@ class EstablishmentScheduleQuerySet(models.QuerySet):
|
|||
"""QuerySet for model EstablishmentSchedule"""
|
||||
|
||||
|
||||
class EstablishmentSchedule(BaseAttributes):
|
||||
"""Establishment schedule model."""
|
||||
establishment = models.OneToOneField(Establishment,
|
||||
related_name='schedule',
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_('Establishment'))
|
||||
schedule = models.ManyToManyField(to='timetable.Timetable',
|
||||
verbose_name=_('Establishment schedule'))
|
||||
|
||||
objects = EstablishmentScheduleQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
"""Meta class"""
|
||||
verbose_name = _('Establishment schedule')
|
||||
verbose_name_plural = _('Establishment schedules')
|
||||
|
||||
|
||||
class ContactPhone(models.Model):
|
||||
"""Contact phone model."""
|
||||
establishment = models.ForeignKey(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import json
|
||||
from rest_framework import serializers
|
||||
|
||||
from establishment import models
|
||||
from timetable.models import Timetable
|
||||
from establishment.serializers import (
|
||||
EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer,
|
||||
ContactPhonesSerializer, SocialNetworkRelatedSerializers)
|
||||
ContactPhonesSerializer, SocialNetworkRelatedSerializers, EstablishmentDetailSerializer
|
||||
)
|
||||
from main.models import Currency
|
||||
|
||||
|
||||
|
|
@ -83,4 +86,15 @@ class ContactEmailBackSerializers(PlateSerializer):
|
|||
'id',
|
||||
'establishment',
|
||||
'email'
|
||||
]
|
||||
|
||||
|
||||
class EmployeeBackSerializers(serializers.ModelSerializer):
|
||||
"""Social network serializers."""
|
||||
class Meta:
|
||||
model = models.Employee
|
||||
fields = [
|
||||
'id',
|
||||
'user',
|
||||
'name'
|
||||
]
|
||||
|
|
@ -9,7 +9,7 @@ from location.serializers import AddressSerializer
|
|||
from main.models import MetaDataContent
|
||||
from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer
|
||||
from review import models as review_models
|
||||
from timetable.models import Timetable
|
||||
from timetable.serialziers import ScheduleRUDSerializer
|
||||
from utils import exceptions as utils_exceptions
|
||||
|
||||
|
||||
|
|
@ -111,22 +111,6 @@ class EstablishmentSubTypeSerializer(serializers.ModelSerializer):
|
|||
fields = ('id', 'name_translated')
|
||||
|
||||
|
||||
class EstablishmentScheduleSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for Establishment model."""
|
||||
weekday = serializers.CharField(source='get_weekday_display')
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = Timetable
|
||||
fields = (
|
||||
'weekday',
|
||||
'lunch_start',
|
||||
'lunch_end',
|
||||
'dinner_start',
|
||||
'dinner_end',
|
||||
)
|
||||
|
||||
|
||||
class ReviewSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model Review."""
|
||||
text_translated = serializers.CharField(read_only=True)
|
||||
|
|
@ -146,12 +130,13 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer):
|
|||
name = serializers.CharField(source='employee.name')
|
||||
position_translated = serializers.CharField(source='position.name_translated')
|
||||
awards = AwardSerializer(source='employee.awards', many=True)
|
||||
priority = serializers.IntegerField(source='position.priority')
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.Employee
|
||||
fields = ('id', 'name', 'position_translated', 'awards')
|
||||
fields = ('id', 'name', 'position_translated', 'awards', 'priority')
|
||||
|
||||
|
||||
class EstablishmentBaseSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -160,7 +145,7 @@ class EstablishmentBaseSerializer(serializers.ModelSerializer):
|
|||
subtypes = EstablishmentSubTypeSerializer(many=True)
|
||||
address = AddressSerializer()
|
||||
tags = MetaDataContentSerializer(many=True)
|
||||
preview_image = serializers.ImageField(source='image')
|
||||
preview_image = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -203,9 +188,7 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
|
|||
"""Serializer for Establishment model."""
|
||||
description_translated = serializers.CharField(allow_null=True)
|
||||
awards = AwardSerializer(many=True)
|
||||
schedule = EstablishmentScheduleSerializer(source='schedule.schedule',
|
||||
many=True,
|
||||
allow_null=True)
|
||||
schedule = ScheduleRUDSerializer(many=True, allow_null=True)
|
||||
phones = ContactPhonesSerializer(read_only=True, many=True, )
|
||||
emails = ContactEmailsSerializer(read_only=True, many=True, )
|
||||
review = serializers.SerializerMethodField()
|
||||
|
|
@ -355,6 +338,7 @@ class EstablishmentFavoritesCreateSerializer(serializers.ModelSerializer):
|
|||
|
||||
class EstablishmentTagListSerializer(serializers.ModelSerializer):
|
||||
"""List establishment tag serializer."""
|
||||
id = serializers.IntegerField(source='metadata.id')
|
||||
label_translated = serializers.CharField(
|
||||
source='metadata.label_translated', read_only=True, allow_null=True)
|
||||
|
||||
|
|
@ -362,5 +346,6 @@ class EstablishmentTagListSerializer(serializers.ModelSerializer):
|
|||
"""Meta class."""
|
||||
model = MetaDataContent
|
||||
fields = [
|
||||
'id',
|
||||
'label_translated',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ app_name = 'establishment'
|
|||
urlpatterns = [
|
||||
path('', views.EstablishmentListCreateView.as_view(), name='list'),
|
||||
path('<int:pk>/', views.EstablishmentRetrieveView.as_view(), name='detail'),
|
||||
path('<int:pk>/schedule/<int:schedule_id>/', views.EstablishmentScheduleRUDView.as_view(),
|
||||
name='schedule-rud'),
|
||||
path('<int:pk>/schedule/', views.EstablishmentScheduleCreateView.as_view(),
|
||||
name='schedule-create'),
|
||||
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
|
||||
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
|
||||
path('plates/', views.PlateListCreateView.as_view(), name='plates'),
|
||||
|
|
@ -20,5 +24,6 @@ urlpatterns = [
|
|||
path('phones/<int:pk>/', views.PhonesRUDView.as_view(), name='phones-rud'),
|
||||
path('emails/', views.EmailListCreateView.as_view(), name='emails'),
|
||||
path('emails/<int:pk>/', views.EmailRUDView.as_view(), name='emails-rud'),
|
||||
|
||||
path('employees/', views.EmployeeListCreateView.as_view(), name='employees'),
|
||||
path('employees/<int:pk>/', views.EmployeeRUDView.as_view(), name='employees-rud'),
|
||||
]
|
||||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
from rest_framework import generics
|
||||
|
||||
from establishment import models, serializers
|
||||
from establishment import models
|
||||
from establishment import serializers
|
||||
from establishment.views.common import EstablishmentMixin
|
||||
|
||||
|
||||
|
|
@ -73,4 +74,16 @@ class EmailListCreateView(generics.ListCreateAPIView):
|
|||
class EmailRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Social RUD view."""
|
||||
serializer_class = serializers.ContactEmailBackSerializers
|
||||
queryset = models.ContactEmail.objects.all()
|
||||
queryset = models.ContactEmail.objects.all()
|
||||
|
||||
|
||||
class EmployeeListCreateView(generics.ListCreateAPIView):
|
||||
"""Emplyoee list create view."""
|
||||
serializer_class = serializers.EmployeeBackSerializers
|
||||
queryset = models.Employee.objects.all()
|
||||
pagination_class = None
|
||||
|
||||
class EmployeeRUDView(generics.RetrieveDestroyAPIView):
|
||||
"""Social RUD view."""
|
||||
serializer_class = serializers.EmployeeBackSerializers
|
||||
queryset = models.Employee.objects.all()
|
||||
|
|
@ -6,9 +6,9 @@ from rest_framework import generics, permissions
|
|||
from comment import models as comment_models
|
||||
from establishment import filters
|
||||
from establishment import models, serializers
|
||||
from main.models import MetaDataContent
|
||||
from utils.views import JWTGenericViewMixin
|
||||
from establishment.views import EstablishmentMixin
|
||||
from main.models import MetaDataContent
|
||||
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
|
||||
|
||||
|
||||
class EstablishmentListView(EstablishmentMixin, generics.ListAPIView):
|
||||
|
|
@ -34,12 +34,12 @@ class EstablishmentSimilarListView(EstablishmentListView):
|
|||
.order_by('-total_mark')[:13]
|
||||
|
||||
|
||||
class EstablishmentRetrieveView(EstablishmentMixin, JWTGenericViewMixin, generics.RetrieveAPIView):
|
||||
class EstablishmentRetrieveView(EstablishmentMixin, generics.RetrieveAPIView):
|
||||
"""Resource for getting a establishment."""
|
||||
serializer_class = serializers.EstablishmentDetailSerializer
|
||||
|
||||
|
||||
class EstablishmentTypeListView(JWTGenericViewMixin, generics.ListAPIView):
|
||||
class EstablishmentTypeListView(generics.ListAPIView):
|
||||
"""Resource for getting a list of establishment types."""
|
||||
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
|
|
@ -122,7 +122,7 @@ class EstablishmentFavoritesCreateDestroyView(generics.CreateAPIView, generics.D
|
|||
return obj
|
||||
|
||||
|
||||
class EstablishmentNearestRetrieveView(EstablishmentMixin, JWTGenericViewMixin, generics.ListAPIView):
|
||||
class EstablishmentNearestRetrieveView(EstablishmentMixin, generics.ListAPIView):
|
||||
"""Resource for getting list of nearest establishments."""
|
||||
serializer_class = serializers.EstablishmentListSerializer
|
||||
filter_class = filters.EstablishmentFilter
|
||||
|
|
@ -150,4 +150,42 @@ class EstablishmentTagListView(generics.ListAPIView):
|
|||
def get_queryset(self):
|
||||
"""Override get_queryset method"""
|
||||
return MetaDataContent.objects.by_content_type(app_label='establishment',
|
||||
model='establishment')
|
||||
model='establishment')\
|
||||
.distinct('metadata__label')
|
||||
|
||||
|
||||
class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Establishment schedule RUD view"""
|
||||
serializer_class = ScheduleRUDSerializer
|
||||
|
||||
def get_object(self):
|
||||
"""
|
||||
Returns the object the view is displaying.
|
||||
"""
|
||||
lookup_url_kwargs = ('pk', 'schedule_id')
|
||||
|
||||
assert lookup_url_kwargs not in self.kwargs.keys(), (
|
||||
'Expected view %s to be called with a URL keyword argument '
|
||||
'named "%s". Fix your URL conf, or set the `.lookup_field` '
|
||||
'attribute on the view correctly.' %
|
||||
(self.__class__.__name__, lookup_url_kwargs)
|
||||
)
|
||||
|
||||
establishment_pk = self.kwargs['pk']
|
||||
schedule_id = self.kwargs['schedule_id']
|
||||
|
||||
establishment = get_object_or_404(klass=models.Establishment.objects.all(),
|
||||
pk=establishment_pk)
|
||||
schedule = get_object_or_404(klass=establishment.schedule,
|
||||
id=schedule_id)
|
||||
|
||||
# May raise a permission denied
|
||||
self.check_object_permissions(self.request, establishment)
|
||||
self.check_object_permissions(self.request, schedule)
|
||||
|
||||
return schedule
|
||||
|
||||
|
||||
class EstablishmentScheduleCreateView(generics.CreateAPIView):
|
||||
"""Establishment schedule Create view"""
|
||||
serializer_class = ScheduleCreateSerializer
|
||||
|
|
|
|||
18
apps/main/migrations/0014_feature_priority.py
Normal file
18
apps/main/migrations/0014_feature_priority.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-12 13:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0013_auto_20190901_1032'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='feature',
|
||||
name='priority',
|
||||
field=models.IntegerField(default=None, null=True, unique=True),
|
||||
),
|
||||
]
|
||||
14
apps/main/migrations/0015_merge_20190918_1341.py
Normal file
14
apps/main/migrations/0015_merge_20190918_1341.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-18 13:41
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0014_feature_priority'),
|
||||
('main', '0014_carousel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
26
apps/main/migrations/0015_page.py
Normal file
26
apps/main/migrations/0015_page.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-17 13:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('advertisement', '0002_auto_20190917_1307'),
|
||||
('main', '0014_carousel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Page',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('page_name', models.CharField(max_length=255, unique=True)),
|
||||
('advertisements', models.ManyToManyField(to='advertisement.Advertisement')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Page',
|
||||
'verbose_name_plural': 'Pages',
|
||||
},
|
||||
),
|
||||
]
|
||||
14
apps/main/migrations/0016_merge_20190919_0954.py
Normal file
14
apps/main/migrations/0016_merge_20190919_0954.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-19 09:54
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0015_page'),
|
||||
('main', '0015_merge_20190918_1341'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
||||
|
|
@ -5,8 +5,11 @@ from django.contrib.postgres.fields import JSONField
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from advertisement.models import Advertisement
|
||||
from location.models import Country
|
||||
from main import methods
|
||||
from review.models import Review
|
||||
from utils.models import (ProjectBaseMixin, TJSONField,
|
||||
TranslatedFieldsMixin, ImageMixin)
|
||||
from utils.querysets import ContentTypeQuerySetMixin
|
||||
|
|
@ -160,6 +163,7 @@ class Feature(ProjectBaseMixin):
|
|||
"""Feature model."""
|
||||
|
||||
slug = models.CharField(max_length=255, unique=True)
|
||||
priority = models.IntegerField(unique=True, null=True, default=None)
|
||||
site_settings = models.ManyToManyField(SiteSettings, through='SiteFeature')
|
||||
|
||||
class Meta:
|
||||
|
|
@ -311,6 +315,13 @@ class Carousel(models.Model):
|
|||
if hasattr(self.content_object, 'awards'):
|
||||
return self.content_object.awards
|
||||
|
||||
@property
|
||||
def vintage_year(self):
|
||||
if hasattr(self.content_object, 'reviews'):
|
||||
review_qs = self.content_object.reviews.by_status(Review.READY)
|
||||
if review_qs.exists():
|
||||
return review_qs.last().vintage
|
||||
|
||||
@property
|
||||
def toque_number(self):
|
||||
if hasattr(self.content_object, 'toque_number'):
|
||||
|
|
@ -323,12 +334,26 @@ class Carousel(models.Model):
|
|||
|
||||
@property
|
||||
def image(self):
|
||||
# Check if Generic obj has an image
|
||||
if not hasattr(self.content_object.image, 'url'):
|
||||
# Check if Generic obj has a FK to gallery
|
||||
return self.content_object.image.image.url
|
||||
return self.content_object.image.url
|
||||
if hasattr(self.content_object.image, 'url'):
|
||||
return self.content_object.image
|
||||
if hasattr(self.content_object.image.image, 'url'):
|
||||
return self.content_object.image.image
|
||||
|
||||
@property
|
||||
def model_name(self):
|
||||
return self.content_object.__class__.__name__
|
||||
|
||||
|
||||
class Page(models.Model):
|
||||
"""Page model."""
|
||||
|
||||
page_name = models.CharField(max_length=255, unique=True)
|
||||
advertisements = models.ManyToManyField(Advertisement)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
verbose_name = _('Page')
|
||||
verbose_name_plural = _('Pages')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.page_name}'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""Main app serializers."""
|
||||
from rest_framework import serializers
|
||||
|
||||
from advertisement.serializers.web import AdvertisementSerializer
|
||||
from location.serializers import CountrySerializer
|
||||
from main import models
|
||||
|
||||
|
|
@ -15,20 +16,23 @@ class FeatureSerializer(serializers.ModelSerializer):
|
|||
fields = (
|
||||
'id',
|
||||
'slug',
|
||||
'priority'
|
||||
)
|
||||
|
||||
|
||||
class SiteFeatureSerializer(serializers.ModelSerializer):
|
||||
|
||||
id = serializers.IntegerField(source='feature.id')
|
||||
slug = serializers.CharField(source='feature.slug')
|
||||
priority = serializers.IntegerField(source='feature.priority')
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.SiteFeature
|
||||
fields = ('main',
|
||||
'id',
|
||||
'slug')
|
||||
'slug',
|
||||
'priority'
|
||||
)
|
||||
|
||||
|
||||
class SiteSettingsSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -36,7 +40,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
|||
|
||||
published_features = SiteFeatureSerializer(source='published_sitefeatures',
|
||||
many=True, allow_null=True)
|
||||
#todo: remove this
|
||||
# todo: remove this
|
||||
country_code = serializers.CharField(source='subdomain', read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -58,7 +62,6 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class SiteSerializer(serializers.ModelSerializer):
|
||||
|
||||
country = CountrySerializer()
|
||||
|
||||
class Meta:
|
||||
|
|
@ -106,7 +109,7 @@ class AwardSerializer(AwardBaseSerializer):
|
|||
|
||||
|
||||
class MetaDataContentSerializer(serializers.ModelSerializer):
|
||||
id = serializers.IntegerField(source='metadata.id', read_only=True,)
|
||||
id = serializers.IntegerField(source='metadata.id', read_only=True, )
|
||||
label_translated = serializers.CharField(
|
||||
source='metadata.label_translated', read_only=True, allow_null=True)
|
||||
|
||||
|
|
@ -120,6 +123,7 @@ class MetaDataContentSerializer(serializers.ModelSerializer):
|
|||
|
||||
class CurrencySerializer(serializers.ModelSerializer):
|
||||
"""Currency serializer"""
|
||||
|
||||
class Meta:
|
||||
model = models.Currency
|
||||
fields = [
|
||||
|
|
@ -134,8 +138,9 @@ class CarouselListSerializer(serializers.ModelSerializer):
|
|||
name = serializers.CharField()
|
||||
toque_number = serializers.CharField()
|
||||
public_mark = serializers.CharField()
|
||||
image = serializers.URLField()
|
||||
image = serializers.ImageField()
|
||||
awards = AwardBaseSerializer(many=True)
|
||||
vintage_year = serializers.IntegerField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -148,4 +153,19 @@ class CarouselListSerializer(serializers.ModelSerializer):
|
|||
'toque_number',
|
||||
'public_mark',
|
||||
'image',
|
||||
'vintage_year',
|
||||
]
|
||||
|
||||
|
||||
class PageSerializer(serializers.ModelSerializer):
|
||||
page_name = serializers.CharField()
|
||||
advertisements = AdvertisementSerializer(source='advertisements', many=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.Carousel
|
||||
fields = [
|
||||
'id',
|
||||
'page_name',
|
||||
'advertisements'
|
||||
]
|
||||
|
|
|
|||
0
apps/recipe/__init__.py
Normal file
0
apps/recipe/__init__.py
Normal file
8
apps/recipe/apps.py
Normal file
8
apps/recipe/apps.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class RecipeConfig(AppConfig):
|
||||
|
||||
name = 'recipe'
|
||||
verbose_name = _('RecipeConfig')
|
||||
44
apps/recipe/migrations/0001_initial.py
Normal file
44
apps/recipe/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-19 11:07
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import easy_thumbnails.fields
|
||||
import utils.methods
|
||||
import utils.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Recipe',
|
||||
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')),
|
||||
('image', easy_thumbnails.fields.ThumbnailerImageField(blank=True, default=None, null=True, upload_to=utils.methods.image_path, verbose_name='Image')),
|
||||
('title', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB": "some text"}', null=True, verbose_name='Title')),
|
||||
('subtitle', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB": "some text"}', null=True, verbose_name='Subtitle')),
|
||||
('description', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB": "some text"}', null=True, verbose_name='Description')),
|
||||
('state', models.PositiveSmallIntegerField(choices=[(0, 'Waiting'), (1, 'Hidden'), (2, 'Published'), (3, 'Published exclusive')], default=0, verbose_name='State')),
|
||||
('author', models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='Author')),
|
||||
('published_at', models.DateTimeField(blank=True, default=None, help_text='Published at', null=True, verbose_name='Published at')),
|
||||
('published_scheduled_at', models.DateTimeField(blank=True, default=None, help_text='Published scheduled at', null=True, verbose_name='Published scheduled at')),
|
||||
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='recipe_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')),
|
||||
('modified_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='recipe_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Recipe',
|
||||
'verbose_name_plural': 'Recipes',
|
||||
},
|
||||
bases=(utils.models.TranslatedFieldsMixin, models.Model),
|
||||
),
|
||||
]
|
||||
0
apps/recipe/migrations/__init__.py
Normal file
0
apps/recipe/migrations/__init__.py
Normal file
57
apps/recipe/models.py
Normal file
57
apps/recipe/models.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
"""Recipe app models."""
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from utils.models import (TranslatedFieldsMixin, ImageMixin, BaseAttributes,
|
||||
TJSONField)
|
||||
|
||||
|
||||
class RecipeQuerySet(models.QuerySet):
|
||||
"""Extended queryset for Recipe model."""
|
||||
|
||||
# todo: what records are considered published?
|
||||
def published(self):
|
||||
return self.filter(state__in=[self.model.PUBLISHED,
|
||||
self.model.PUBLISHED_EXCLUSIVE])
|
||||
|
||||
|
||||
class Recipe(TranslatedFieldsMixin, ImageMixin, BaseAttributes):
|
||||
"""Recipe model."""
|
||||
|
||||
WAITING = 0
|
||||
HIDDEN = 1
|
||||
PUBLISHED = 2
|
||||
PUBLISHED_EXCLUSIVE = 3
|
||||
|
||||
STATE_CHOICES = (
|
||||
(WAITING, _('Waiting')),
|
||||
(HIDDEN, _('Hidden')),
|
||||
(PUBLISHED, _('Published')),
|
||||
(PUBLISHED_EXCLUSIVE, _('Published exclusive')),
|
||||
)
|
||||
|
||||
STR_FIELD_NAME = 'title'
|
||||
|
||||
title = TJSONField(blank=True, null=True, default=None, verbose_name=_('Title'),
|
||||
help_text='{"en-GB": "some text"}')
|
||||
subtitle = TJSONField(blank=True, null=True, default=None, verbose_name=_('Subtitle'),
|
||||
help_text='{"en-GB": "some text"}')
|
||||
description = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'),
|
||||
help_text='{"en-GB": "some text"}')
|
||||
state = models.PositiveSmallIntegerField(default=WAITING, choices=STATE_CHOICES,
|
||||
verbose_name=_('State'))
|
||||
author = models.CharField(max_length=255, blank=True, null=True, default=None,
|
||||
verbose_name=_('Author'))
|
||||
published_at = models.DateTimeField(verbose_name=_('Published at'),
|
||||
blank=True, default=None, null=True,
|
||||
help_text=_('Published at'))
|
||||
published_scheduled_at = models.DateTimeField(verbose_name=_('Published scheduled at'),
|
||||
blank=True, default=None, null=True,
|
||||
help_text=_('Published scheduled at'))
|
||||
|
||||
objects = RecipeQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
verbose_name = _('Recipe')
|
||||
verbose_name_plural = _('Recipes')
|
||||
0
apps/recipe/serializers/__init__.py
Normal file
0
apps/recipe/serializers/__init__.py
Normal file
30
apps/recipe/serializers/common.py
Normal file
30
apps/recipe/serializers/common.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"""Recipe app common serializers."""
|
||||
from rest_framework import serializers
|
||||
from recipe import models
|
||||
|
||||
|
||||
class RecipeListSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for list of recipes."""
|
||||
|
||||
title_translated = serializers.CharField(allow_null=True, read_only=True)
|
||||
subtitle_translated = serializers.CharField(allow_null=True, read_only=True)
|
||||
in_favorites = serializers.BooleanField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.Recipe
|
||||
fields = ('id', 'title_translated', 'subtitle_translated', 'author',
|
||||
'published_at', 'in_favorites')
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
class RecipeDetailSerializer(RecipeListSerializer):
|
||||
"""Serializer for more information about the recipe."""
|
||||
|
||||
description_translated = serializers.CharField(allow_null=True, read_only=True)
|
||||
|
||||
class Meta(RecipeListSerializer.Meta):
|
||||
"""Meta class."""
|
||||
|
||||
fields = RecipeListSerializer.Meta.fields + ('description_translated',)
|
||||
0
apps/recipe/urls/__init__.py
Normal file
0
apps/recipe/urls/__init__.py
Normal file
10
apps/recipe/urls/common.py
Normal file
10
apps/recipe/urls/common.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
"""Recipe app common urlpatterns."""
|
||||
from django.urls import path
|
||||
from recipe.views import common as views
|
||||
|
||||
|
||||
app_name = 'recipe'
|
||||
urlpatterns = [
|
||||
path('', views.RecipeListView.as_view(), name='list'),
|
||||
path('<int:pk>/', views.RecipeDetailView.as_view(), name='detail'),
|
||||
]
|
||||
6
apps/recipe/urls/web.py
Normal file
6
apps/recipe/urls/web.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
"""Recipe app web urlconf."""
|
||||
from recipe.urls.common import urlpatterns as common_urlpatterns
|
||||
|
||||
|
||||
urlpatterns = []
|
||||
urlpatterns.extend(common_urlpatterns)
|
||||
0
apps/recipe/views/__init__.py
Normal file
0
apps/recipe/views/__init__.py
Normal file
28
apps/recipe/views/common.py
Normal file
28
apps/recipe/views/common.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
"""Recipe app common views."""
|
||||
from rest_framework import generics, permissions
|
||||
from recipe import models
|
||||
from recipe.serializers import common as serializers
|
||||
|
||||
|
||||
class RecipeViewMixin(generics.GenericAPIView):
|
||||
"""Recipe view mixin."""
|
||||
|
||||
pagination_class = None
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
qs = models.Recipe.objects.published().annotate_in_favorites(user)
|
||||
return qs
|
||||
|
||||
|
||||
class RecipeListView(RecipeViewMixin, generics.ListAPIView):
|
||||
"""Resource for obtaining a list of recipes."""
|
||||
|
||||
serializer_class = serializers.RecipeListSerializer
|
||||
|
||||
|
||||
class RecipeDetailView(RecipeViewMixin, generics.RetrieveAPIView):
|
||||
"""Resource for detailed recipe information."""
|
||||
|
||||
serializer_class = serializers.RecipeDetailSerializer
|
||||
|
|
@ -16,10 +16,28 @@ class EstablishmentDocument(Document):
|
|||
|
||||
description = fields.ObjectField(attr='description_indexing',
|
||||
properties=OBJECT_FIELD_PROPERTIES)
|
||||
establishment_type = fields.ObjectField(
|
||||
properties={
|
||||
'id': fields.IntegerField(),
|
||||
'name': fields.ObjectField(attr='name_indexing',
|
||||
properties=OBJECT_FIELD_PROPERTIES)
|
||||
})
|
||||
establishment_subtypes = fields.ObjectField(
|
||||
properties={
|
||||
'id': fields.IntegerField(),
|
||||
'name': fields.ObjectField(attr='name_indexing',
|
||||
properties=OBJECT_FIELD_PROPERTIES)
|
||||
},
|
||||
multi=True)
|
||||
tags = fields.ObjectField(
|
||||
properties={
|
||||
'id': fields.IntegerField(attr='id'),
|
||||
'label': fields.ObjectField(attr='label')
|
||||
'id': fields.IntegerField(attr='metadata.id'),
|
||||
'label': fields.ObjectField(attr='metadata.label_indexing',
|
||||
properties=OBJECT_FIELD_PROPERTIES),
|
||||
'category': fields.ObjectField(attr='metadata.category',
|
||||
properties={
|
||||
'id': fields.IntegerField(),
|
||||
})
|
||||
},
|
||||
multi=True)
|
||||
address = fields.ObjectField(
|
||||
|
|
@ -50,6 +68,12 @@ class EstablishmentDocument(Document):
|
|||
),
|
||||
}
|
||||
)
|
||||
collections = fields.ObjectField(
|
||||
properties={
|
||||
'id': fields.IntegerField(attr='collection.id'),
|
||||
'collection_type': fields.IntegerField(attr='collection.collection_type'),
|
||||
},
|
||||
multi=True)
|
||||
|
||||
class Django:
|
||||
|
||||
|
|
@ -61,5 +85,5 @@ class EstablishmentDocument(Document):
|
|||
'price_level',
|
||||
)
|
||||
|
||||
def prepare_tags(self, instance):
|
||||
return instance.tags_indexing
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().published()
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ class EstablishmentDocumentSerializer(DocumentSerializer):
|
|||
'description_translated',
|
||||
'tags',
|
||||
'address',
|
||||
'collections',
|
||||
'establishment_type',
|
||||
'establishment_subtypes',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""Search indexes app views."""
|
||||
from rest_framework import permissions
|
||||
from django_elasticsearch_dsl_drf import constants
|
||||
from django_elasticsearch_dsl_drf.filter_backends import FilteringFilterBackend
|
||||
from django_elasticsearch_dsl_drf.filter_backends import (FilteringFilterBackend,
|
||||
GeoSpatialFilteringFilterBackend)
|
||||
from django_elasticsearch_dsl_drf.viewsets import BaseDocumentViewSet
|
||||
from django_elasticsearch_dsl_drf.pagination import PageNumberPagination
|
||||
from search_indexes import serializers, filters
|
||||
|
|
@ -47,6 +48,7 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
|
|||
filter_backends = [
|
||||
FilteringFilterBackend,
|
||||
filters.CustomSearchFilterBackend,
|
||||
GeoSpatialFilteringFilterBackend,
|
||||
]
|
||||
|
||||
search_fields = (
|
||||
|
|
@ -85,5 +87,29 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
|
|||
},
|
||||
'country': {
|
||||
'field': 'address.city.country.code'
|
||||
},
|
||||
'tags_id': {
|
||||
'field': 'tags.id',
|
||||
},
|
||||
'tags_category_id': {
|
||||
'field': 'tags.category.id',
|
||||
},
|
||||
'collection_type': {
|
||||
'field': 'collections.collection_type'
|
||||
},
|
||||
'establishment_type': {
|
||||
'field': 'establishment_type.id'
|
||||
},
|
||||
'establishment_subtypes': {
|
||||
'field': 'establishment_subtypes.id'
|
||||
},
|
||||
}
|
||||
|
||||
geo_spatial_filter_fields = {
|
||||
'location': {
|
||||
'field': 'address.location',
|
||||
'lookups': [
|
||||
constants.LOOKUP_FILTER_GEO_BOUNDING_BOX,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
43
apps/timetable/migrations/0002_auto_20190919_1124.py
Normal file
43
apps/timetable/migrations/0002_auto_20190919_1124.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Generated by Django 2.2.4 on 2019-09-19 11:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('timetable', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='timetable',
|
||||
name='closed_at',
|
||||
field=models.TimeField(null=True, verbose_name='Closed time'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='timetable',
|
||||
name='opening_at',
|
||||
field=models.TimeField(null=True, verbose_name='Opening time'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='timetable',
|
||||
name='dinner_end',
|
||||
field=models.TimeField(null=True, verbose_name='Dinner end time'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='timetable',
|
||||
name='dinner_start',
|
||||
field=models.TimeField(null=True, verbose_name='Dinner start time'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='timetable',
|
||||
name='lunch_end',
|
||||
field=models.TimeField(null=True, verbose_name='Lunch end time'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='timetable',
|
||||
name='lunch_start',
|
||||
field=models.TimeField(null=True, verbose_name='Lunch start time'),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from utils.models import ProjectBaseMixin
|
||||
|
||||
|
||||
|
|
@ -23,10 +24,13 @@ class Timetable(ProjectBaseMixin):
|
|||
(SUNDAY, _('Sunday')))
|
||||
|
||||
weekday = models.PositiveSmallIntegerField(choices=WEEKDAYS_CHOICES, verbose_name=_('Week day'))
|
||||
lunch_start = models.TimeField(verbose_name=_('Lunch start time'))
|
||||
lunch_end = models.TimeField(verbose_name=_('Lunch end time'))
|
||||
dinner_start = models.TimeField(verbose_name=_('Dinner start time'))
|
||||
dinner_end = models.TimeField(verbose_name=_('Dinner end time'))
|
||||
|
||||
lunch_start = models.TimeField(verbose_name=_('Lunch start time'), null=True)
|
||||
lunch_end = models.TimeField(verbose_name=_('Lunch end time'), null=True)
|
||||
dinner_start = models.TimeField(verbose_name=_('Dinner start time'), null=True)
|
||||
dinner_end = models.TimeField(verbose_name=_('Dinner end time'), null=True)
|
||||
opening_at = models.TimeField(verbose_name=_('Opening time'), null=True)
|
||||
closed_at = models.TimeField(verbose_name=_('Closed time'), null=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
|
|||
|
|
@ -1,16 +1,79 @@
|
|||
"""Serializer for app timetable"""
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
from timetable import models
|
||||
|
||||
from establishment.models import Establishment
|
||||
from timetable.models import Timetable
|
||||
|
||||
|
||||
class TimetableSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model Timetable"""
|
||||
class ScheduleRUDSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for Establishment model."""
|
||||
weekday_display = serializers.CharField(source='get_weekday_display',
|
||||
read_only=True)
|
||||
|
||||
lunch_start = serializers.TimeField(required=False)
|
||||
lunch_end = serializers.TimeField(required=False)
|
||||
dinner_start = serializers.TimeField(required=False)
|
||||
dinner_end = serializers.TimeField(required=False)
|
||||
opening_at = serializers.TimeField(required=False)
|
||||
closed_at = serializers.TimeField(required=False)
|
||||
|
||||
NULLABLE_FIELDS = ['lunch_start', 'lunch_end', 'dinner_start',
|
||||
'dinner_end', 'opening_at', 'closed_at']
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.Timetable
|
||||
fields = (
|
||||
model = Timetable
|
||||
fields = [
|
||||
'id',
|
||||
'weekday_display',
|
||||
'lunch_start',
|
||||
'lunch_end',
|
||||
'dinner_start',
|
||||
'dinner_end',
|
||||
'opening_at',
|
||||
'closed_at',
|
||||
]
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Override validate method"""
|
||||
establishment_pk = self.context.get('request')\
|
||||
.parser_context.get('view')\
|
||||
.kwargs.get('pk')
|
||||
|
||||
# Check if establishment exists.
|
||||
establishment_qs = Establishment.objects.filter(pk=establishment_pk)
|
||||
if not establishment_qs.exists():
|
||||
raise serializers.ValidationError({'detail': _('Establishment not found.')})
|
||||
attrs['establishment'] = establishment_qs.first()
|
||||
|
||||
# If fields not in request data then put it in attrs with None value.
|
||||
if not self.partial:
|
||||
for field in self.NULLABLE_FIELDS:
|
||||
if field not in attrs:
|
||||
attrs.setdefault(field, None)
|
||||
return attrs
|
||||
|
||||
|
||||
class ScheduleCreateSerializer(ScheduleRUDSerializer):
|
||||
"""Serializer for Establishment model."""
|
||||
weekday = serializers.IntegerField(write_only=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = Timetable
|
||||
fields = ScheduleRUDSerializer.Meta.fields + [
|
||||
'weekday',
|
||||
'start',
|
||||
'end',
|
||||
)
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
"""Override create method"""
|
||||
establishment = validated_data.pop('establishment')
|
||||
weekday = validated_data.get('weekday')
|
||||
|
||||
instance = super().create(validated_data)
|
||||
schedule_qs = establishment.schedule.filter(weekday=weekday)
|
||||
if schedule_qs.exists():
|
||||
schedule_qs.delete()
|
||||
establishment.schedule.add(instance)
|
||||
return instance
|
||||
|
|
|
|||
|
|
@ -205,10 +205,12 @@ class PlatformMixin(models.Model):
|
|||
|
||||
MOBILE = 0
|
||||
WEB = 1
|
||||
ALL = 2
|
||||
|
||||
SOURCES = (
|
||||
(MOBILE, _('Mobile')),
|
||||
(WEB, _('Web')),
|
||||
(ALL, _('All'))
|
||||
)
|
||||
source = models.PositiveSmallIntegerField(choices=SOURCES, default=MOBILE,
|
||||
verbose_name=_('Source'))
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ PROJECT_APPS = [
|
|||
'news.apps.NewsConfig',
|
||||
'notification.apps.NotificationConfig',
|
||||
'partner.apps.PartnerConfig',
|
||||
'recipe.apps.RecipeConfig',
|
||||
'search_indexes.apps.SearchIndexesConfig',
|
||||
'translation.apps.TranslationConfig',
|
||||
'configuration.apps.ConfigurationConfig',
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ urlpatterns = [
|
|||
path('partner/', include('partner.urls.web')),
|
||||
path('location/', include('location.urls.web')),
|
||||
path('main/', include('main.urls')),
|
||||
path('recipes/', include('recipe.urls.web')),
|
||||
path('translation/', include('translation.urls')),
|
||||
path('comments/', include('comment.urls.web')),
|
||||
path('favorites/', include('favorites.urls')),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user