Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Anatoly 2019-09-01 15:02:38 +03:00
commit a1fed35c69
5 changed files with 189 additions and 19 deletions

View File

@ -1,7 +1,6 @@
"""Establishment admin conf.""" """Establishment admin conf."""
from django.contrib import admin from django.contrib import admin
from django.contrib.contenttypes.admin import GenericTabularInline from django.contrib.contenttypes.admin import GenericTabularInline
from establishment import models from establishment import models
from main.models import Award, MetaDataContent from main.models import Award, MetaDataContent
from review import models as review_models from review import models as review_models
@ -38,6 +37,7 @@ class ContactEmailInline(admin.TabularInline):
model = models.ContactEmail model = models.ContactEmail
extra = 0 extra = 0
class ReviewInline(GenericTabularInline): class ReviewInline(GenericTabularInline):
model = review_models.Review model = review_models.Review
extra = 0 extra = 0
@ -60,3 +60,8 @@ class EstablishmentSchedule(admin.ModelAdmin):
@admin.register(models.Comment) @admin.register(models.Comment)
class EstablishmentComment(admin.ModelAdmin): class EstablishmentComment(admin.ModelAdmin):
"""Establishment comments.""" """Establishment comments."""
@admin.register(models.Position)
class PositionAdmin(admin.ModelAdmin):
"""Position admin."""

View File

@ -0,0 +1,81 @@
# Generated by Django 2.2.4 on 2019-09-01 11:42
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),
('establishment', '0009_merge_20190901_1131'),
]
operations = [
migrations.CreateModel(
name='Employee',
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')),
('name', models.CharField(max_length=255, verbose_name='Last name')),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='employee_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')),
],
options={
'verbose_name': 'Employee',
'verbose_name_plural': 'Employees',
},
),
migrations.CreateModel(
name='Position',
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')),
('name', utils.models.TJSONField(blank=True, default=None, help_text='{"en":"some text"}', null=True, verbose_name='Description')),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='position_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='position_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by')),
],
options={
'verbose_name': 'Position',
'verbose_name_plural': 'Positions',
},
bases=(models.Model, utils.models.TraslatedFieldsMixin),
),
migrations.CreateModel(
name='EstablishmentEmployee',
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')),
('from_date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='From date')),
('to_date', models.DateTimeField(blank=True, default=None, null=True, verbose_name='To date')),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='establishmentemployee_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')),
('employee', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='establishment.Employee', verbose_name='Employee')),
('establishment', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='establishment.Establishment', verbose_name='Establishment')),
('modified_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='establishmentemployee_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by')),
('position', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='establishment.Position', verbose_name='Position')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='employee',
name='establishments',
field=models.ManyToManyField(related_name='employees', through='establishment.EstablishmentEmployee', to='establishment.Establishment'),
),
migrations.AddField(
model_name='employee',
name='modified_by',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='employee_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by'),
),
migrations.AddField(
model_name='employee',
name='user',
field=models.OneToOneField(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='User'),
),
]

View File

@ -1,15 +1,14 @@
"""Establishment models.""" """Establishment models."""
from functools import reduce
from django.contrib.contenttypes import fields as generic from django.contrib.contenttypes import fields as generic
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField from phonenumber_field.modelfields import PhoneNumberField
from location.models import Address from location.models import Address
from utils.models import ( from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField,
ProjectBaseMixin, ImageMixin, TJSONField, TraslatedFieldsMixin, BaseAttributes)
TraslatedFieldsMixin, BaseAttributes
)
# todo: establishment type&subtypes check # todo: establishment type&subtypes check
@ -73,6 +72,14 @@ class EstablishmentQuerySet(models.QuerySet):
else: else:
return self.none() 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): class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin):
"""Establishment model.""" """Establishment model."""
@ -127,6 +134,7 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin):
country = self.address.city.country country = self.address.city.country
return country.low_price, country.high_price return country.low_price, country.high_price
# todo: make via prefetch
@property @property
def subtypes(self): def subtypes(self):
return EstablishmentSubType.objects.filter( return EstablishmentSubType.objects.filter(
@ -145,6 +153,65 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin):
self.establishment_subtypes.add(establishment_subtype) 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): class EstablishmentScheduleQuerySet(models.QuerySet):
"""QuerySet for model EstablishmentSchedule""" """QuerySet for model EstablishmentSchedule"""

View File

@ -1,6 +1,5 @@
"""Establishment serializers.""" """Establishment serializers."""
from rest_framework import serializers from rest_framework import serializers
from establishment import models from establishment import models
from location.serializers import AddressSerializer from location.serializers import AddressSerializer
from main.serializers import MetaDataContentSerializer, AwardSerializer from main.serializers import MetaDataContentSerializer, AwardSerializer
@ -93,6 +92,19 @@ class CommentSerializer(serializers.ModelSerializer):
'image' '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')
class Meta:
"""Meta class."""
model = models.Employee
fields = ('id', 'name', 'position_translated')
class EstablishmentSerializer(serializers.ModelSerializer): class EstablishmentSerializer(serializers.ModelSerializer):
"""Serializer for Establishment model.""" """Serializer for Establishment model."""
@ -109,10 +121,10 @@ class EstablishmentSerializer(serializers.ModelSerializer):
allow_null=True) allow_null=True)
phones = ContactPhonesSerializer(read_only=True, many=True, ) phones = ContactPhonesSerializer(read_only=True, many=True, )
emails = ContactEmailsSerializer(read_only=True, many=True, ) emails = ContactEmailsSerializer(read_only=True, many=True, )
reviews = ReviewSerializer(source='reviews.last', reviews = ReviewSerializer(source='reviews.last', allow_null=True)
allow_null=True) comments = CommentSerializer(many=True, allow_null=True)
comments = CommentSerializer(many=True, employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees',
allow_null=True) many=True)
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -137,4 +149,5 @@ class EstablishmentSerializer(serializers.ModelSerializer):
'emails', 'emails',
'reviews', 'reviews',
'comments', 'comments',
'employees',
) )

View File

@ -5,22 +5,26 @@ from utils.views import JWTGenericViewMixin
from establishment import filters from establishment import filters
class EstablishmentListView(JWTGenericViewMixin, generics.ListAPIView): class EstablishmentMixin:
"""Resource for getting a list of establishments.""" """Establishment mixin."""
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentSerializer serializer_class = serializers.EstablishmentSerializer
queryset = models.Establishment.objects.all()
def get_queryset(self):
"""Overrided method 'get_queryset'."""
return models.Establishment.objects.all().prefetch_actual_employees()
class EstablishmentListView(EstablishmentMixin, JWTGenericViewMixin, generics.ListAPIView):
"""Resource for getting a list of establishments."""
filter_class = filters.EstablishmentFilter filter_class = filters.EstablishmentFilter
class EstablishmentRetrieveView(JWTGenericViewMixin, generics.RetrieveAPIView): class EstablishmentRetrieveView(EstablishmentMixin, JWTGenericViewMixin, generics.RetrieveAPIView):
"""Resource for getting a establishment.""" """Resource for getting a establishment."""
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentSerializer
queryset = models.Establishment.objects.all()
class EstablishmentTypeListView(JWTGenericViewMixin, generics.ListAPIView): class EstablishmentTypeListView(JWTGenericViewMixin, generics.ListAPIView):
"""Resource for getting a list of establishment types.""" """Resource for getting a list of establishment types."""