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

This commit is contained in:
Anatoly 2019-09-02 11:10:52 +03:00
commit 3c7fc7a436
52 changed files with 1129 additions and 30 deletions

View File

@ -18,7 +18,7 @@ class UserAdmin(BaseUserAdmin):
fieldsets = ( fieldsets = (
(None, {'fields': ('email', 'password',)}), (None, {'fields': ('email', 'password',)}),
(_('Personal info'), { (_('Personal info'), {
'fields': ('username', 'first_name', 'last_name', )}), 'fields': ('username', 'first_name', 'last_name', 'image')}),
(_('Subscription'), { (_('Subscription'), {
'fields': ( 'fields': (
'newsletter', 'newsletter',

View File

@ -1,8 +1,10 @@
"""Establishment admin conf.""" """Establishment admin conf."""
from django.contrib import admin from django.contrib import admin
from establishment import models
from django.contrib.contenttypes.admin import GenericTabularInline from django.contrib.contenttypes.admin import GenericTabularInline
from establishment import models
from main.models import Award, MetaDataContent 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) @admin.register(models.EstablishmentType)
@ -25,12 +27,63 @@ class MetaDataContentInline(GenericTabularInline):
extra = 0 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
class ReviewInline(GenericTabularInline):
model = review_models.Review
extra = 0
@admin.register(models.Establishment) @admin.register(models.Establishment)
class EstablishmentAdmin(admin.ModelAdmin): class EstablishmentAdmin(admin.ModelAdmin):
"""Establishment admin.""" """Establishment admin."""
inlines = [AwardInline, MetaDataContentInline] inlines = [
AwardInline, MetaDataContentInline,
ContactPhoneInline, ContactEmailInline,
ReviewInline]
@admin.register(models.EstablishmentSchedule) @admin.register(models.EstablishmentSchedule)
class EstablishmentSchedule(admin.ModelAdmin): class EstablishmentSchedule(admin.ModelAdmin):
"""Establishment schedule""" """Establishment schedule"""
@admin.register(models.Comment)
class EstablishmentComment(admin.ModelAdmin):
"""Establishment comments."""
@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')

View File

@ -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'),
),
]

View File

@ -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',
},
),
]

View File

@ -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 = [
]

View File

@ -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',
),
]

View File

@ -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',
},
),
]

View File

@ -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 = [
]

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

@ -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),
),
]

View File

@ -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'),
),
]

View File

@ -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'),
),
]

View File

@ -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'),
),
]

View File

@ -1,12 +1,16 @@
"""Establishment models.""" """Establishment models."""
from functools import reduce from functools import reduce
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 location.models import Address from location.models import Address
from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField,
TraslatedFieldsMixin, BaseAttributes) TraslatedFieldsMixin, BaseAttributes)
from django.contrib.contenttypes import fields as generic
# todo: establishment type&subtypes check # todo: establishment type&subtypes check
@ -14,7 +18,7 @@ class EstablishmentType(ProjectBaseMixin, TraslatedFieldsMixin):
"""Establishment type model.""" """Establishment type model."""
name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), 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) use_subtypes = models.BooleanField(_('Use subtypes'), default=True)
class Meta: class Meta:
@ -38,7 +42,7 @@ class EstablishmentSubType(ProjectBaseMixin, TraslatedFieldsMixin):
"""Establishment type model.""" """Establishment type model."""
name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), 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, establishment_type = models.ForeignKey(EstablishmentType,
on_delete=models.CASCADE, on_delete=models.CASCADE,
verbose_name=_('Type')) verbose_name=_('Type'))
@ -70,15 +74,27 @@ class EstablishmentQuerySet(models.QuerySet):
else: else:
return self.none() 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(
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."""
name = TJSONField(blank=True, null=True, default=None, 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, description = TJSONField(blank=True, null=True, default=None,
verbose_name=_('Description'), verbose_name=_('Description'),
help_text='{"en":"some text"}') help_text='{"en-GB":"some text"}')
public_mark = models.PositiveIntegerField(blank=True, null=True, public_mark = models.PositiveIntegerField(blank=True, null=True,
default=None, default=None,
verbose_name=_('Public mark'),) verbose_name=_('Public mark'),)
@ -98,8 +114,19 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin):
price_level = models.PositiveIntegerField(blank=True, null=True, price_level = models.PositiveIntegerField(blank=True, null=True,
default=None, default=None,
verbose_name=_('Price level')) 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,
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') awards = generic.GenericRelation(to='main.Award')
tags = generic.GenericRelation(to='main.MetaDataContent') tags = generic.GenericRelation(to='main.MetaDataContent')
reviews = generic.GenericRelation(to='review.Review')
objects = EstablishmentQuerySet.as_manager() objects = EstablishmentQuerySet.as_manager()
@ -123,6 +150,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(
@ -140,6 +168,73 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin):
raise ValidationError('Establishment type of subtype does not match') raise ValidationError('Establishment type of subtype does not match')
self.establishment_subtypes.add(establishment_subtype) 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."""
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"""
@ -160,3 +255,124 @@ class EstablishmentSchedule(BaseAttributes):
"""Meta class""" """Meta class"""
verbose_name = _('Establishment schedule') verbose_name = _('Establishment schedule')
verbose_name_plural = _('Establishment schedules') verbose_name_plural = _('Establishment schedules')
class ContactPhone(models.Model):
"""Contact phone model."""
establishment = models.ForeignKey(
Establishment, 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."""
establishment = models.ForeignKey(
Establishment, 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."""
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."""
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)

View File

@ -1,11 +1,57 @@
"""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, CurrencySerializer
from review import models as review_models
from timetable.models import Timetable 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 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): class EstablishmentTypeSerializer(serializers.ModelSerializer):
"""Serializer for EstablishmentType model.""" """Serializer for EstablishmentType model."""
@ -46,6 +92,50 @@ 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_translated',
)
class CommentSerializer(serializers.ModelSerializer):
"""Comment serializer"""
nickname = serializers.CharField(source='author.username')
profile_pic = serializers.ImageField(source='author.image')
class Meta:
"""Serializer for model Comment"""
model = models.Comment
fields = (
'created',
'text',
'mark',
'nickname',
'profile_pic'
)
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."""
model = models.Employee
fields = ('id', 'name', 'position_translated', 'awards')
class EstablishmentSerializer(serializers.ModelSerializer): class EstablishmentSerializer(serializers.ModelSerializer):
"""Serializer for Establishment model.""" """Serializer for Establishment model."""
@ -59,6 +149,17 @@ class EstablishmentSerializer(serializers.ModelSerializer):
schedule = EstablishmentScheduleSerializer(source='schedule.schedule', schedule = EstablishmentScheduleSerializer(source='schedule.schedule',
many=True, many=True,
allow_null=True) allow_null=True)
phones = ContactPhonesSerializer(read_only=True, many=True, )
emails = ContactEmailsSerializer(read_only=True, many=True, )
reviews = ReviewSerializer(source='reviews.last', allow_null=True)
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)
preview_image = serializers.SerializerMethodField()
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: class Meta:
"""Meta class.""" """Meta class."""
@ -75,8 +176,27 @@ class EstablishmentSerializer(serializers.ModelSerializer):
'type', 'type',
'subtypes', 'subtypes',
'image', 'image',
'preview_image',
'address', 'address',
'tags', 'tags',
'awards', 'awards',
'schedule', 'schedule',
'website',
'facebook',
'twitter',
'lafourchette',
'booking',
'phones',
'emails',
'reviews',
'comments',
'employees',
'menu',
'best_price_menu',
'best_price_carte'
) )
def get_preview_image(self, obj):
"""Get preview image"""
return obj.get_full_image_url(request=self.context.get('request'),
thumbnail_key='establishment_preview')

View File

@ -5,22 +5,32 @@ from utils.views import JWTGenericViewMixin
from establishment import filters from establishment import filters
class EstablishmentListView(JWTGenericViewMixin, generics.ListAPIView): class EstablishmentMixin:
"""Establishment mixin."""
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentSerializer
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.""" """Resource for getting a list of establishments."""
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentSerializer
queryset = models.Establishment.objects.all()
filter_class = filters.EstablishmentFilter 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(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."""

View File

@ -30,6 +30,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='country', model_name='country',
name='name', 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'),
), ),
] ]

View File

@ -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'),
),
]

View File

@ -17,7 +17,7 @@ class Country(SVGImageMixin, ProjectBaseMixin):
"""Country model.""" """Country model."""
name = JSONField(null=True, blank=True, default=None, 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')) code = models.CharField(max_length=255, unique=True, verbose_name=_('Code'))
low_price = models.IntegerField(default=25, verbose_name=_('Low price')) low_price = models.IntegerField(default=25, verbose_name=_('Low price'))
high_price = models.IntegerField(default=50, verbose_name=_('High price')) high_price = models.IntegerField(default=50, verbose_name=_('High price'))

View File

@ -39,3 +39,10 @@ class MetaDataCategoryAdmin(admin.ModelAdmin):
@admin.register(models.MetaDataContent) @admin.register(models.MetaDataContent)
class MetaDataContentAdmin(admin.ModelAdmin): class MetaDataContentAdmin(admin.ModelAdmin):
"""MetaDataContent admin""" """MetaDataContent admin"""
@admin.register(models.Currency)
class CurrencContentAdmin(admin.ModelAdmin):
"""CurrencContent admin"""

View File

@ -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'),
),
]

View File

@ -190,7 +190,7 @@ class Award(TraslatedFieldsMixin, models.Model):
award_type = models.ForeignKey('main.AwardType', on_delete=models.CASCADE) award_type = models.ForeignKey('main.AwardType', on_delete=models.CASCADE)
title = TJSONField( title = TJSONField(
_('title'), null=True, blank=True, _('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='') vintage_year = models.CharField(_('vintage year'), max_length=255, default='')
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
@ -228,7 +228,7 @@ class MetaData(TraslatedFieldsMixin, models.Model):
"""MetaData model.""" """MetaData model."""
label = TJSONField( label = TJSONField(
_('label'), null=True, blank=True, _('label'), null=True, blank=True,
default=None, help_text='{"en":"some text"}') default=None, help_text='{"en-GB":"some text"}')
category = models.ForeignKey( category = models.ForeignKey(
MetaDataCategory, verbose_name=_('category'), on_delete=models.CASCADE) MetaDataCategory, verbose_name=_('category'), on_delete=models.CASCADE)
@ -250,3 +250,15 @@ class MetaDataContent(models.Model):
object_id = models.PositiveIntegerField() object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id') content_object = generic.GenericForeignKey('content_type', 'object_id')
metadata = models.ForeignKey(MetaData, on_delete=models.CASCADE) 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}'

View File

@ -73,6 +73,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
class AwardSerializer(serializers.ModelSerializer): class AwardSerializer(serializers.ModelSerializer):
"""Award serializer.""" """Award serializer."""
title_translated = serializers.CharField(read_only=True, allow_null=True) title_translated = serializers.CharField(read_only=True, allow_null=True)
class Meta: class Meta:
@ -96,3 +97,13 @@ class MetaDataContentSerializer(serializers.ModelSerializer):
'id', 'id',
'label_translated', 'label_translated',
] ]
class CurrencySerializer(serializers.ModelSerializer):
"""Currency serializer"""
class Meta:
model = models.Currency
fields = [
'id',
'name'
]

View File

@ -22,7 +22,7 @@ class NewsListFilterSet(django_filters.FilterSet):
"""Crappy search by title according to locale""" """Crappy search by title according to locale"""
if value: if value:
locale = self.request.locale locale = self.request.locale
filters = {f'{name}__{locale}': value} filters = {f'{name}__{locale}__icontains': value}
return queryset.filter(**filters) return queryset.filter(**filters)
else: else:
return queryset return queryset

View File

@ -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'),
),
]

View File

@ -43,14 +43,14 @@ class News(BaseAttributes, TraslatedFieldsMixin):
title = TJSONField( title = TJSONField(
_('title'), null=True, blank=True, _('title'), null=True, blank=True,
default=None, help_text='{"en":"some text"}') default=None, help_text='{"en-GB":"some text"}')
subtitle = TJSONField( subtitle = TJSONField(
_('subtitle'), null=True, blank=True, _('subtitle'), null=True, blank=True,
default=None, help_text='{"en":"some text"}' default=None, help_text='{"en-GB":"some text"}'
) )
description = TJSONField( description = TJSONField(
_('description'), null=True, blank=True, _('description'), null=True, blank=True,
default=None, help_text='{"en":"some text"}' default=None, help_text='{"en-GB":"some text"}'
) )
start = models.DateTimeField(_('start')) start = models.DateTimeField(_('start'))
end = models.DateTimeField(_('end')) end = models.DateTimeField(_('end'))

0
apps/review/__init__.py Normal file
View File

3
apps/review/admin.py Normal file
View File

@ -0,0 +1,3 @@
# @admin.register(models.Review)
# class ReviewAdminModel(admin.ModelAdmin):
# """Admin model for model Review."""

7
apps/review/apps.py Normal file
View File

@ -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')

View File

@ -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',
},
),
]

View File

@ -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',
),
]

View File

@ -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'),
),
]

View File

64
apps/review/models.py Normal file
View File

@ -0,0 +1,64 @@
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 utils.models import BaseAttributes, TraslatedFieldsMixin
from utils.models import TJSONField
class ReviewQuerySet(models.QuerySet):
"""QuerySets for model Review"""
def by_reviewer(self, user):
"""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, TraslatedFieldsMixin):
"""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='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')
language = models.ForeignKey('translation.Language',
on_delete=models.CASCADE,
related_name='reviews',
verbose_name=_('Review language'))
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'),
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()
class Meta:
"""Meta class."""
verbose_name = _('Review')
verbose_name_plural = _('Reviews')

View File

View File

View File

View File

3
apps/review/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

View File

View File

0
apps/review/urls/web.py Normal file
View File

View File

View File

View File

0
apps/review/views/web.py Normal file
View File

View File

@ -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'),
),
]

View File

@ -49,7 +49,7 @@ class SiteInterfaceDictionary(ProjectBaseMixin):
verbose_name=_('Page')) verbose_name=_('Page'))
keywords = models.CharField(max_length=255, verbose_name='Keywords') keywords = models.CharField(max_length=255, verbose_name='Keywords')
text = JSONField(_('Text'), null=True, blank=True, text = JSONField(_('Text'), null=True, blank=True,
default=None, help_text='{"en":"some text"}') default=None, help_text='{"en-GB":"some text"}')
objects = SiteInterfaceDictionaryManager() objects = SiteInterfaceDictionaryManager()

View File

@ -74,9 +74,6 @@ class OAuthProjectMixin:
return NotImplemented return NotImplemented
basemixin_fields = ['created', 'modified']
class BaseAttributes(ProjectBaseMixin): class BaseAttributes(ProjectBaseMixin):
created_by = models.ForeignKey( created_by = models.ForeignKey(
'account.User', on_delete=models.SET_NULL, verbose_name=_('created by'), 'account.User', on_delete=models.SET_NULL, verbose_name=_('created by'),

View File

@ -66,6 +66,7 @@ PROJECT_APPS = [
'translation.apps.TranslationConfig', 'translation.apps.TranslationConfig',
'configuration.apps.ConfigurationConfig', 'configuration.apps.ConfigurationConfig',
'timetable.apps.TimetableConfig', 'timetable.apps.TimetableConfig',
'review.apps.ReviewConfig',
] ]
EXTERNAL_APPS = [ EXTERNAL_APPS = [
@ -82,6 +83,7 @@ EXTERNAL_APPS = [
'django_extensions', 'django_extensions',
'rest_framework_simplejwt.token_blacklist', 'rest_framework_simplejwt.token_blacklist',
'solo', 'solo',
'phonenumber_field',
] ]
@ -321,6 +323,7 @@ THUMBNAIL_ALIASES = {
'large': {'size': (1500, 0), }, 'large': {'size': (1500, 0), },
'default': {'size': (300, 200), 'crop': True}, 'default': {'size': (300, 200), 'crop': True},
'gallery': {'size': (240, 160), 'crop': True}, 'gallery': {'size': (240, 160), 'crop': True},
'establishment_preview': {'size': (300, 280), 'crop': True},
} }
} }

View File

@ -17,6 +17,7 @@ djangorestframework-xml
celery celery
amqp>=2.4.0 amqp>=2.4.0
geoip2==2.9.0 geoip2==2.9.0
django-phonenumber-field[phonenumbers]==2.1.0
# auth socials # auth socials
djangorestframework-oauth djangorestframework-oauth