Merge branch 'feature/gm-192' into feature/gm-148

# Conflicts:
#	apps/news/models.py
#	apps/news/serializers.py
#	apps/news/views.py
This commit is contained in:
Anatoly 2019-10-15 12:08:23 +03:00
commit 2d830b2821
37 changed files with 891 additions and 151 deletions

View File

@ -40,8 +40,7 @@ class PasswordResetConfirmView(JWTGenericViewMixin):
queryset = models.User.objects.active() queryset = models.User.objects.active()
def get_object(self): def get_object(self):
"""Override get_object method """Override get_object method"""
"""
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
uidb64 = self.kwargs.get('uidb64') uidb64 = self.kwargs.get('uidb64')

View File

@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _
from comment.models import Comment from comment.models import Comment
from establishment import models from establishment import models
from main.models import Award, MetaDataContent from main.models import Award
from review import models as review_models from review import models as review_models
@ -24,11 +24,6 @@ class AwardInline(GenericTabularInline):
extra = 0 extra = 0
class MetaDataContentInline(GenericTabularInline):
model = MetaDataContent
extra = 0
class ContactPhoneInline(admin.TabularInline): class ContactPhoneInline(admin.TabularInline):
"""Contact phone inline admin.""" """Contact phone inline admin."""
model = models.ContactPhone model = models.ContactPhone
@ -56,8 +51,7 @@ class EstablishmentAdmin(admin.ModelAdmin):
"""Establishment admin.""" """Establishment admin."""
list_display = ['id', '__str__', 'image_tag', ] list_display = ['id', '__str__', 'image_tag', ]
inlines = [ inlines = [
AwardInline, MetaDataContentInline, AwardInline, ContactPhoneInline, ContactEmailInline,
ContactPhoneInline, ContactEmailInline,
ReviewInline, CommentInline] ReviewInline, CommentInline]
@ -85,3 +79,18 @@ class MenuAdmin(admin.ModelAdmin):
return obj.category_translated return obj.category_translated
category_translated.short_description = _('category') category_translated.short_description = _('category')
@admin.register(models.EstablishmentTypeTagCategory)
class EstablishmentTypeTagCategoryAdmin(admin.ModelAdmin):
"""EstablishmentTypeTagCategory admin."""
@admin.register(models.EstablishmentSubTypeTagCategory)
class EstablishmentSubTypeTagCategoryAdmin(admin.ModelAdmin):
"""EstablishmentTypeTagCategory admin."""
@admin.register(models.EstablishmentTag)
class EstablishmentTagAdmin(admin.ModelAdmin):
"""EstablishmentTag admin."""

View File

@ -26,3 +26,17 @@ class EstablishmentFilter(filters.FilterSet):
if value not in EMPTY_VALUES: if value not in EMPTY_VALUES:
return queryset.search(value, locale=self.request.locale) return queryset.search(value, locale=self.request.locale)
return queryset return queryset
class EstablishmentTypeTagFilter(filters.FilterSet):
"""Establishment tag filter set."""
type_id = filters.NumberFilter(field_name='id')
class Meta:
"""Meta class."""
model = models.EstablishmentType
fields = (
'type_id',
)

View File

@ -0,0 +1,35 @@
# Generated by Django 2.2.4 on 2019-10-09 07:15
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('establishment', '0031_establishment_slug'),
]
operations = [
migrations.CreateModel(
name='EstablishmentTag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
options={
'verbose_name': 'establishment tag',
'verbose_name_plural': 'establishment tags',
},
),
migrations.CreateModel(
name='EstablishmentTypeTagCategory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('establishment_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tag_categories', to='establishment.EstablishmentType', verbose_name='establishment type')),
],
options={
'verbose_name': 'establishment type tag categories',
'verbose_name_plural': 'establishment type tag categories',
},
),
]

View File

@ -0,0 +1,30 @@
# Generated by Django 2.2.4 on 2019-10-09 07:15
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('tag', '0001_initial'),
('establishment', '0032_establishmenttag_establishmenttypetagcategory'),
]
operations = [
migrations.AddField(
model_name='establishmenttypetagcategory',
name='tag_category',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='est_type_tag_categories', to='tag.TagCategory', verbose_name='tag category'),
),
migrations.AddField(
model_name='establishmenttag',
name='establishment',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='establishment.Establishment', verbose_name='establishment'),
),
migrations.AddField(
model_name='establishmenttag',
name='tag',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='tag.Tag', verbose_name='tag'),
),
]

View File

@ -0,0 +1,14 @@
# Generated by Django 2.2.4 on 2019-10-09 14:57
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('establishment', '0033_auto_20191009_0715'),
('establishment', '0033_auto_20191003_0943_squashed_0034_auto_20191003_1036'),
]
operations = [
]

View File

@ -0,0 +1,27 @@
# Generated by Django 2.2.4 on 2019-10-11 10:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('tag', '0002_auto_20191009_1408'),
('establishment', '0034_merge_20191009_1457'),
]
operations = [
migrations.CreateModel(
name='EstablishmentSubTypeTagCategory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('establishment_subtype', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tag_categories', to='establishment.EstablishmentSubType', verbose_name='establishment subtype')),
('tag_category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='est_subtype_tag_categories', to='tag.TagCategory', verbose_name='tag category')),
],
options={
'verbose_name': 'establishment subtype tag categories',
'verbose_name_plural': 'establishment subtype tag categories',
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-10-11 13:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0035_establishmentsubtypetagcategory'),
]
operations = [
migrations.AlterField(
model_name='establishment',
name='establishment_subtypes',
field=models.ManyToManyField(blank=True, related_name='subtype_establishment', to='establishment.EstablishmentSubType', verbose_name='subtype'),
),
]

View File

@ -16,12 +16,29 @@ from phonenumber_field.modelfields import PhoneNumberField
from collection.models import Collection from collection.models import Collection
from location.models import Address from location.models import Address
from main.models import Award, MetaDataContent from main.models import Award
from tag.models import Tag, TagCategory
from review.models import Review from review.models import Review
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
TranslatedFieldsMixin, BaseAttributes) TranslatedFieldsMixin, BaseAttributes)
class EstablishmentTypeQuerySet(models.QuerySet):
"""QuerySet for model EstablishmentType."""
def with_base_related(self):
"""Return QuerySet with base related."""
return self.prefetch_related(
models.Prefetch('tag_categories',
EstablishmentTypeTagCategory.objects.select_related('tag_category')),
models.Prefetch('establishmentsubtype_set',
EstablishmentSubType.objects.prefetch_related(
models.Prefetch(
'tag_categories',
EstablishmentSubTypeTagCategory.objects.select_related('tag_category'))))
)
# todo: establishment type&subtypes check # todo: establishment type&subtypes check
class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin): class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin):
"""Establishment type model.""" """Establishment type model."""
@ -32,6 +49,8 @@ class EstablishmentType(TranslatedFieldsMixin, ProjectBaseMixin):
help_text='{"en-GB":"some text"}') help_text='{"en-GB":"some text"}')
use_subtypes = models.BooleanField(_('Use subtypes'), default=True) use_subtypes = models.BooleanField(_('Use subtypes'), default=True)
objects = EstablishmentTypeQuerySet.as_manager()
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -76,10 +95,13 @@ class EstablishmentQuerySet(models.QuerySet):
def with_base_related(self): def with_base_related(self):
"""Return qs with related objects.""" """Return qs with related objects."""
return self.select_related('address').prefetch_related( return self.select_related('address', 'establishment_type').prefetch_related(
models.Prefetch('tags', models.Prefetch('tags',
MetaDataContent.objects.select_related( EstablishmentTag.objects.select_related('tag')),
'metadata__category')) models.Prefetch('establishment_type__tag_categories',
EstablishmentTypeTagCategory.objects.select_related('tag_category')),
models.Prefetch('establishment_type__establishmentsubtype_set',
EstablishmentSubType.objects.prefetch_related('tag_categories')),
) )
def with_extended_related(self): def with_extended_related(self):
@ -256,6 +278,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
on_delete=models.PROTECT, on_delete=models.PROTECT,
verbose_name=_('type')) verbose_name=_('type'))
establishment_subtypes = models.ManyToManyField(EstablishmentSubType, establishment_subtypes = models.ManyToManyField(EstablishmentSubType,
blank=True,
related_name='subtype_establishment', related_name='subtype_establishment',
verbose_name=_('subtype')) verbose_name=_('subtype'))
address = models.ForeignKey(Address, blank=True, null=True, default=None, address = models.ForeignKey(Address, blank=True, null=True, default=None,
@ -478,6 +501,7 @@ class ContactEmail(models.Model):
def __str__(self): def __str__(self):
return f'{self.email}' return f'{self.email}'
# #
# class Wine(TranslatedFieldsMixin, models.Model): # class Wine(TranslatedFieldsMixin, models.Model):
# """Wine model.""" # """Wine model."""
@ -551,3 +575,82 @@ class SocialNetwork(models.Model):
def __str__(self): def __str__(self):
return self.title return self.title
class EstablishmentTagQuerySet(models.QuerySet):
"""Establishment tag QuerySet."""
def by_country_code(self, code):
"""Return establishment tags by establishment country code."""
return self.filter(establishment__address__city__country__code=code)
class EstablishmentTag(models.Model):
"""Establishment tag model."""
tag = models.ForeignKey('tag.Tag',
on_delete=models.CASCADE,
related_name='tags',
verbose_name=_('tag'))
establishment = models.ForeignKey('establishment.Establishment',
on_delete=models.CASCADE,
related_name='tags',
verbose_name=_('establishment'))
objects = EstablishmentTagQuerySet.as_manager()
class Meta:
verbose_name = _('establishment tag')
verbose_name_plural = _('establishment tags')
class EstablishmentTypeTagCategoryQuerySet(models.QuerySet):
"""EstablishmentTypeTagCategory QuerySet."""
def by_country_code(self, code):
"""Return establishment tags by country code"""
return self.filter(tag_category__country__code=code)
def with_base_related(self):
"""Return with related relations."""
return self.select_related('establishment_type', 'tag_category')
class EstablishmentTypeTagCategory(models.Model):
"""Tag categories based on establishment type."""
establishment_type = models.ForeignKey(EstablishmentType,
on_delete=models.CASCADE,
related_name='tag_categories',
verbose_name=_('establishment type'))
tag_category = models.ForeignKey('tag.TagCategory',
on_delete=models.CASCADE,
related_name='est_type_tag_categories',
verbose_name=_('tag category'))
objects = EstablishmentTypeTagCategoryQuerySet.as_manager()
class Meta:
verbose_name = _('establishment type tag categories')
verbose_name_plural = _('establishment type tag categories')
class EstablishmentSubTypeTagCategoryQuerySet(models.QuerySet):
"""QuerySet for tag categories based on establishment subtype."""
def with_base_related(self):
"""Return queryset with base related."""
return self.select_related('establishment_subtype', 'tag_category')
class EstablishmentSubTypeTagCategory(models.Model):
"""Tag categories based on establishment subtype."""
establishment_subtype = models.ForeignKey(EstablishmentSubType,
on_delete=models.CASCADE,
related_name='tag_categories',
verbose_name=_('establishment subtype'))
tag_category = models.ForeignKey('tag.TagCategory',
on_delete=models.CASCADE,
related_name='est_subtype_tag_categories',
verbose_name=_('tag category'))
objects = EstablishmentSubTypeTagCategoryQuerySet.as_manager()
class Meta:
verbose_name = _('establishment subtype tag categories')
verbose_name_plural = _('establishment subtype tag categories')

View File

@ -1,13 +1,16 @@
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from establishment import models from establishment import models
from establishment.serializers import ( from establishment.serializers import (
EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer,
ContactPhonesSerializer, SocialNetworkRelatedSerializers, ContactPhonesSerializer, SocialNetworkRelatedSerializers,
EstablishmentTypeSerializer) EstablishmentTypeBaseSerializer, EstablishmentSubTypeBaseSerializer,
EstablishmentTypeTagCategoryBaseSerializer)
from utils.decorators import with_base_attributes
from main.models import Currency from main.models import Currency
from tag.serializers import TagBaseSerializer
from utils.decorators import with_base_attributes
from utils.serializers import TranslatedField
class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): class EstablishmentListCreateSerializer(EstablishmentBaseSerializer):
@ -21,7 +24,7 @@ class EstablishmentListCreateSerializer(EstablishmentBaseSerializer):
emails = ContactEmailsSerializer(read_only=True, many=True, ) emails = ContactEmailsSerializer(read_only=True, many=True, )
socials = SocialNetworkRelatedSerializers(read_only=True, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=True, many=True, )
slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) slug = serializers.SlugField(required=True, allow_blank=False, max_length=50)
type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) type = EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True)
class Meta: class Meta:
model = models.Establishment model = models.Establishment
@ -55,7 +58,7 @@ class EstablishmentRUDSerializer(EstablishmentBaseSerializer):
phones = ContactPhonesSerializer(read_only=False, many=True, ) phones = ContactPhonesSerializer(read_only=False, many=True, )
emails = ContactEmailsSerializer(read_only=False, many=True, ) emails = ContactEmailsSerializer(read_only=False, many=True, )
socials = SocialNetworkRelatedSerializers(read_only=False, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=False, many=True, )
type = EstablishmentTypeSerializer(source='establishment_type') type = EstablishmentTypeBaseSerializer(source='establishment_type')
class Meta: class Meta:
model = models.Establishment model = models.Establishment
@ -142,3 +145,95 @@ class EmployeeBackSerializers(serializers.ModelSerializer):
'name' 'name'
] ]
class EstablishmentTagCreateSerializer(serializers.ModelSerializer):
"""Serializer for model EstablishmentTag."""
class Meta:
model = models.EstablishmentTag
fields = [
'tag',
'establishment'
]
extra_kwargs = {
'tag': {'write_only': True},
'establishment': {'write_only': True},
}
def validate(self, attrs):
"""Validate method."""
establishment = attrs.get('establishment')
tag = attrs.get('tag')
# Check if tag is already added to establishment.
if establishment.tags.filter(tag=tag).exists():
raise serializers.ValidationError(detail={'detail': _('Tag is already added.')})
# Сhecking tag availability for establishment type.
if not establishment.establishment_type.use_subtypes:
qs = establishment.establishment_type.tag_categories.filter(tag_category=tag.category)
else:
# Сhecking tag availability for establishment subtype.
qs = establishment.establishment_type.tag_categories.filter(
establishmentsubtype_set__tag_category=tag.category)
if not qs.exists():
raise serializers.ValidationError(
detail={'detail': _('Tag is not available for this establishment type|subtype.')})
return attrs
class EstablishmentSubTypeTagCategoryBaseSerializer(serializers.ModelSerializer):
"""Serializer for intermediate model EstablishmentSubTypeTagCategories."""
id = serializers.IntegerField(source='tag_category.id', read_only=True)
label_translated = TranslatedField(source='tag_category.label_translated')
tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True)
class Meta:
"""Meta class."""
model = models.EstablishmentSubTypeTagCategory
fields = [
'id',
'label_translated',
'tags',
'establishment_subtype',
'tag_category',
]
extra_kwargs = {
'establishment_subtype': {'write_only': True},
'tag_category': {'write_only': True},
}
def validate(self, attrs):
"""Override validate method."""
if models.EstablishmentTypeTagCategory.objects.filter(
establishment_type=attrs.get('establishment_type'),
tag_category=attrs.get('tag_category')).exists():
raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')})
return attrs
class EstablishmentSubTypeSerializer(EstablishmentSubTypeBaseSerializer):
"""Extended serializer for EstablishmentSubType model with tags."""
tag_categories = EstablishmentSubTypeTagCategoryBaseSerializer(many=True, read_only=True)
class Meta(EstablishmentSubTypeBaseSerializer.Meta):
"""Meta class"""
fields = [
'id',
'name_translated',
'tag_categories'
]
class EstablishmentTagsByType(EstablishmentTypeBaseSerializer):
"""Tags by establishment type"""
tag_categories = EstablishmentTypeTagCategoryBaseSerializer(many=True)
subtypes = EstablishmentSubTypeSerializer(many=True, source='establishmentsubtype_set')
class Meta(EstablishmentTypeBaseSerializer.Meta):
"""Meta class."""
fields = [
'id',
'name_translated',
'tag_categories',
'subtypes',
]

View File

@ -1,17 +1,19 @@
"""Establishment serializers.""" """Establishment serializers."""
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from comment import models as comment_models from comment import models as comment_models
from comment.serializers import common as comment_serializers from comment.serializers import common as comment_serializers
from establishment import models from establishment import models
from favorites.models import Favorites from favorites.models import Favorites
from location.serializers import AddressBaseSerializer from location.serializers import AddressBaseSerializer
from main.models import MetaDataContent from main.serializers import AwardSerializer, CurrencySerializer
from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer
from review import models as review_models from review import models as review_models
from tag.serializers import TagBaseSerializer
from timetable.serialziers import ScheduleRUDSerializer from timetable.serialziers import ScheduleRUDSerializer
from utils import exceptions as utils_exceptions from utils import exceptions as utils_exceptions
from utils.serializers import TranslatedField, ProjectModelSerializer from utils.serializers import ProjectModelSerializer
from utils.serializers import TranslatedField
class ContactPhonesSerializer(serializers.ModelSerializer): class ContactPhonesSerializer(serializers.ModelSerializer):
@ -86,30 +88,6 @@ class MenuRUDSerializers(ProjectModelSerializer):
] ]
class EstablishmentTypeSerializer(serializers.ModelSerializer):
"""Serializer for EstablishmentType model."""
name_translated = serializers.CharField(allow_null=True)
class Meta:
"""Meta class."""
model = models.EstablishmentType
fields = ('id', 'name_translated')
class EstablishmentSubTypeSerializer(serializers.ModelSerializer):
"""Serializer for EstablishmentSubType models."""
name_translated = serializers.CharField(allow_null=True)
class Meta:
"""Meta class."""
model = models.EstablishmentSubType
fields = ('id', 'name_translated')
class ReviewSerializer(serializers.ModelSerializer): class ReviewSerializer(serializers.ModelSerializer):
"""Serializer for model Review.""" """Serializer for model Review."""
text_translated = serializers.CharField(read_only=True) text_translated = serializers.CharField(read_only=True)
@ -122,6 +100,75 @@ class ReviewSerializer(serializers.ModelSerializer):
) )
class EstablishmentTypeBaseSerializer(serializers.ModelSerializer):
"""Serializer for EstablishmentType model."""
name_translated = TranslatedField()
class Meta:
"""Meta class."""
model = models.EstablishmentType
fields = [
'id',
'name',
'name_translated',
'use_subtypes'
]
extra_kwargs = {
'name': {'write_only': True},
'use_subtypes': {'write_only': True},
}
class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer):
"""Serializer for EstablishmentSubType models."""
name_translated = TranslatedField()
class Meta:
"""Meta class."""
model = models.EstablishmentSubType
fields = [
'id',
'name',
'name_translated',
'establishment_type'
]
extra_kwargs = {
'name': {'write_only': True},
'establishment_type': {'write_only': True}
}
class EstablishmentTypeTagCategoryBaseSerializer(serializers.ModelSerializer):
"""Serializer for intermediate model EstablishmentTypeTagCategories."""
id = serializers.IntegerField(source='tag_category.id', read_only=True)
label_translated = TranslatedField(source='tag_category.label_translated')
tags = TagBaseSerializer(source='tag_category.tags', many=True, read_only=True)
class Meta:
"""Meta class."""
model = models.EstablishmentTypeTagCategory
fields = [
'id',
'label_translated',
'tags',
'establishment_type',
'tag_category',
]
extra_kwargs = {
'establishment_type': {'write_only': True},
'tag_category': {'write_only': True},
}
def validate(self, attrs):
"""Override validate method."""
if models.EstablishmentTypeTagCategory.objects.filter(
establishment_type=attrs.get('establishment_type'),
tag_category=attrs.get('tag_category')).exists():
raise serializers.ValidationError(detail={'detail': _('Objects is already attached.')})
return attrs
class EstablishmentEmployeeSerializer(serializers.ModelSerializer): class EstablishmentEmployeeSerializer(serializers.ModelSerializer):
"""Serializer for actual employees.""" """Serializer for actual employees."""
@ -138,14 +185,28 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer):
fields = ('id', 'name', 'position_translated', 'awards', 'priority') fields = ('id', 'name', 'position_translated', 'awards', 'priority')
class EstablishmentTagSerializer(serializers.ModelSerializer):
"""Serializer for intermediate model EstablishmentTag."""
id = serializers.IntegerField(source='tag.id')
label_translated = serializers.CharField(source='tag.label_translated')
class Meta:
"""Meta class."""
model = models.EstablishmentTag
fields = [
'id',
'label_translated'
]
class EstablishmentBaseSerializer(ProjectModelSerializer): class EstablishmentBaseSerializer(ProjectModelSerializer):
"""Base serializer for Establishment model.""" """Base serializer for Establishment model."""
preview_image = serializers.URLField(source='preview_image_url') preview_image = serializers.URLField(source='preview_image_url')
slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) slug = serializers.SlugField(allow_blank=False, required=True, max_length=50)
address = AddressBaseSerializer() address = AddressBaseSerializer()
tags = MetaDataContentSerializer(many=True)
in_favorites = serializers.BooleanField(allow_null=True) in_favorites = serializers.BooleanField(allow_null=True)
tags = EstablishmentTagSerializer(many=True)
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -171,8 +232,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
description_translated = TranslatedField() description_translated = TranslatedField()
image = serializers.URLField(source='image_url') image = serializers.URLField(source='image_url')
type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) type = EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True)
subtypes = EstablishmentSubTypeSerializer(many=True, source='establishment_subtypes') subtypes = EstablishmentSubTypeBaseSerializer(many=True, source='establishment_subtypes')
awards = AwardSerializer(many=True) awards = AwardSerializer(many=True)
schedule = ScheduleRUDSerializer(many=True, allow_null=True) schedule = ScheduleRUDSerializer(many=True, allow_null=True)
phones = ContactPhonesSerializer(read_only=True, many=True) phones = ContactPhonesSerializer(read_only=True, many=True)
@ -306,17 +367,3 @@ class EstablishmentFavoritesCreateSerializer(serializers.ModelSerializer):
}) })
return super().create(validated_data) return super().create(validated_data)
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)
class Meta:
"""Meta class."""
model = MetaDataContent
fields = [
'id',
'label_translated',
]

View File

@ -14,6 +14,7 @@ urlpatterns = [
name='schedule-rud'), name='schedule-rud'),
path('<int:pk>/schedule/', views.EstablishmentScheduleCreateView.as_view(), path('<int:pk>/schedule/', views.EstablishmentScheduleCreateView.as_view(),
name='schedule-create'), name='schedule-create'),
path('attach-tag/', views.EstablishmentTagCreateView.as_view(), name='attach-tag'),
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'), path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
path('plates/', views.PlateListCreateView.as_view(), name='plates'), path('plates/', views.PlateListCreateView.as_view(), name='plates'),
@ -26,4 +27,13 @@ urlpatterns = [
path('emails/<int:pk>/', views.EmailRUDView.as_view(), name='emails-rud'), path('emails/<int:pk>/', views.EmailRUDView.as_view(), name='emails-rud'),
path('employees/', views.EmployeeListCreateView.as_view(), name='employees'), path('employees/', views.EmployeeListCreateView.as_view(), name='employees'),
path('employees/<int:pk>/', views.EmployeeRUDView.as_view(), name='employees-rud'), path('employees/<int:pk>/', views.EmployeeRUDView.as_view(), name='employees-rud'),
path('types/', views.EstablishmentTypeListCreateView.as_view(), name='type-list'),
path('types/tags/', views.EstablishmentTypeTagListView.as_view(), name='type-tag-list'),
path('types/<int:pk>/', views.EstablishmentTypeRUDView.as_view(), name='type-rud'),
path('types/attach-tag-category/', views.EstablishmentTypeAttachTagCategoryView.as_view(),
name='type-attach-tag-category'),
path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'),
path('subtypes/<int:pk>/', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'),
path('subtypes/attach-tag-category/', views.EstablishmentSubTypeAttachTagCategoryView.as_view(),
name='subtype-attach-tag-category'),
] ]

View File

@ -7,7 +7,6 @@ app_name = 'establishment'
urlpatterns = [ urlpatterns = [
path('', views.EstablishmentListView.as_view(), name='list'), path('', views.EstablishmentListView.as_view(), name='list'),
path('tags/', views.EstablishmentTagListView.as_view(), name='tags'),
path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(), path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(),
name='recent-reviews'), name='recent-reviews'),
path('slug/<slug:slug>/', views.EstablishmentRetrieveView.as_view(), name='detail'), path('slug/<slug:slug>/', views.EstablishmentRetrieveView.as_view(), name='detail'),

View File

@ -1,9 +1,11 @@
"""Establishment app views.""" """Establishment app views."""
from django.shortcuts import get_object_or_404
from rest_framework import generics, status, permissions
from rest_framework import generics from establishment import models, serializers
from rest_framework.response import Response
from establishment import models from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
from establishment import serializers from establishment.filters import EstablishmentTypeTagFilter
class EstablishmentMixinViews: class EstablishmentMixinViews:
@ -25,6 +27,53 @@ class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = serializers.EstablishmentRUDSerializer serializer_class = serializers.EstablishmentRUDSerializer
class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Establishment schedule RUD view"""
serializer_class = ScheduleRUDSerializer
def get_object(self):
"""
Returns the object the view is displaying.
"""
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
class EstablishmentTypeAttachTagCategoryView(generics.CreateAPIView):
"""Attach tag category to establishment type."""
serializer_class = serializers.EstablishmentTypeTagCategoryBaseSerializer
def get_queryset(self):
"""Override get_queryset method."""
return models.EstablishmentTypeTagCategory.objects.with_base_related()
def post(self, request, *args, **kwargs):
"""Overridden post-method."""
super(EstablishmentTypeAttachTagCategoryView, self).post(request)
return Response(status=status.HTTP_200_OK)
class EstablishmentTagCreateView(EstablishmentMixinViews, generics.CreateAPIView):
"""Attach tag to establishment."""
serializer_class = serializers.EstablishmentTagCreateSerializer
class MenuListCreateView(generics.ListCreateAPIView): class MenuListCreateView(generics.ListCreateAPIView):
"""Menu list create view.""" """Menu list create view."""
serializer_class = serializers.MenuSerializers serializer_class = serializers.MenuSerializers
@ -100,3 +149,52 @@ class EmployeeRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Social RUD view.""" """Social RUD view."""
serializer_class = serializers.EmployeeBackSerializers serializer_class = serializers.EmployeeBackSerializers
queryset = models.Employee.objects.all() queryset = models.Employee.objects.all()
class EstablishmentTypeListCreateView(generics.ListCreateAPIView):
"""Establishment type list/create view."""
serializer_class = serializers.EstablishmentTypeBaseSerializer
queryset = models.EstablishmentType.objects.all()
pagination_class = None
class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Establishment type retrieve/update/destroy view."""
serializer_class = serializers.EstablishmentTypeBaseSerializer
queryset = models.EstablishmentType.objects.all()
class EstablishmentTypeTagListView(generics.ListAPIView):
"""List of tags with categories by establishment type."""
serializer_class = serializers.EstablishmentTagsByType
queryset = models.EstablishmentType.objects.with_base_related()
filter_class = EstablishmentTypeTagFilter
permission_classes = (permissions.AllowAny, )
pagination_class = None
class EstablishmentSubtypeListCreateView(generics.ListCreateAPIView):
"""Establishment subtype list/create view."""
serializer_class = serializers.EstablishmentSubTypeBaseSerializer
queryset = models.EstablishmentSubType.objects.all()
pagination_class = None
class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Establishment subtype retrieve/update/destroy view."""
serializer_class = serializers.EstablishmentSubTypeBaseSerializer
queryset = models.EstablishmentSubType.objects.all()
class EstablishmentSubTypeAttachTagCategoryView(generics.CreateAPIView):
"""Attach tag category to establishment subtype."""
serializer_class = serializers.EstablishmentSubTypeTagCategoryBaseSerializer
def get_queryset(self):
"""Override get_queryset method."""
return models.EstablishmentSubTypeTagCategory.objects.with_base_related()
def post(self, request, *args, **kwargs):
"""Overridden post-method."""
super(EstablishmentSubTypeAttachTagCategoryView, self).post(request)
return Response(status=status.HTTP_200_OK)

View File

@ -9,7 +9,6 @@ from establishment import filters
from establishment import models, serializers from establishment import models, serializers
from main import methods from main import methods
from main.models import MetaDataContent from main.models import MetaDataContent
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
from utils.pagination import EstablishmentPortionPagination from utils.pagination import EstablishmentPortionPagination
@ -19,9 +18,10 @@ class EstablishmentMixinView:
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
def get_queryset(self): def get_queryset(self):
"""Overrided method 'get_queryset'.""" """Overridden method 'get_queryset'."""
return models.Establishment.objects.published().with_base_related().\ return models.Establishment.objects.published() \
annotate_in_favorites(self.request.user) .with_base_related() \
.annotate_in_favorites(self.request.user)
class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView): class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView):
@ -84,7 +84,7 @@ class EstablishmentTypeListView(generics.ListAPIView):
"""Resource for getting a list of establishment types.""" """Resource for getting a list of establishment types."""
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentTypeSerializer serializer_class = serializers.EstablishmentTypeBaseSerializer
queryset = models.EstablishmentType.objects.all() queryset = models.EstablishmentType.objects.all()
@ -174,44 +174,3 @@ class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIVi
return qs.by_distance_from_point(**{k: v for k, v in filter_kwargs.items() return qs.by_distance_from_point(**{k: v for k, v in filter_kwargs.items()
if v is not None}) if v is not None})
return qs return qs
class EstablishmentTagListView(generics.ListAPIView):
"""List view for establishment tags."""
serializer_class = serializers.EstablishmentTagListSerializer
permission_classes = (permissions.AllowAny,)
pagination_class = None
def get_queryset(self):
"""Override get_queryset method"""
return MetaDataContent.objects.by_content_type(app_label='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.
"""
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

View File

@ -25,22 +25,6 @@ class AwardAdmin(admin.ModelAdmin):
# list_display_links = ['id', '__str__'] # list_display_links = ['id', '__str__']
@admin.register(models.MetaData)
class MetaDataAdmin(admin.ModelAdmin):
"""MetaData admin."""
@admin.register(models.MetaDataCategory)
class MetaDataCategoryAdmin(admin.ModelAdmin):
"""MetaData admin."""
list_display = ['id', 'country', 'content_type']
@admin.register(models.MetaDataContent)
class MetaDataContentAdmin(admin.ModelAdmin):
"""MetaDataContent admin"""
@admin.register(models.Currency) @admin.register(models.Currency)
class CurrencContentAdmin(admin.ModelAdmin): class CurrencContentAdmin(admin.ModelAdmin):
"""CurrencContent admin""" """CurrencContent admin"""

View File

@ -0,0 +1,24 @@
# Generated by Django 2.2.4 on 2019-10-09 14:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tag', '0002_auto_20191009_1408'),
('news', '0020_remove_news_author'),
]
operations = [
migrations.AddField(
model_name='news',
name='tags',
field=models.ManyToManyField(related_name='news', to='tag.Tag', verbose_name='Tags'),
),
migrations.AddField(
model_name='newstype',
name='tag_categories',
field=models.ManyToManyField(related_name='news_types', to='tag.TagCategory'),
),
]

View File

@ -12,6 +12,8 @@ class NewsType(models.Model):
"""NewsType model.""" """NewsType model."""
name = models.CharField(_('name'), max_length=250) name = models.CharField(_('name'), max_length=250)
tag_categories = models.ManyToManyField('tag.TagCategory',
related_name='news_types')
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -133,8 +135,8 @@ class News(BaseAttributes, TranslatedFieldsMixin):
country = models.ForeignKey('location.Country', blank=True, null=True, country = models.ForeignKey('location.Country', blank=True, null=True,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
verbose_name=_('country')) verbose_name=_('country'))
tags = generic.GenericRelation(to='main.MetaDataContent') tags = models.ManyToManyField('tag.Tag', related_name='news',
verbose_name=_('Tags'))
gallery = models.ManyToManyField('gallery.Image', through='news.NewsGallery') gallery = models.ManyToManyField('gallery.Image', through='news.NewsGallery')
ratings = generic.GenericRelation(Rating) ratings = generic.GenericRelation(Rating)

View File

@ -6,8 +6,8 @@ from account.serializers.common import UserBaseSerializer
from gallery.models import Image from gallery.models import Image
from location import models as location_models from location import models as location_models
from location.serializers import CountrySimpleSerializer from location.serializers import CountrySimpleSerializer
from main.serializers import MetaDataContentSerializer
from news import models from news import models
from tag.serializers import TagBaseSerializer
from utils.serializers import TranslatedField, ProjectModelSerializer from utils.serializers import TranslatedField, ProjectModelSerializer
@ -100,7 +100,7 @@ class NewsBaseSerializer(ProjectModelSerializer):
# related fields # related fields
news_type = NewsTypeSerializer(read_only=True) news_type = NewsTypeSerializer(read_only=True)
tags = MetaDataContentSerializer(read_only=True, many=True) tags = TagBaseSerializer(read_only=True, many=True)
gallery = NewsImageSerializer(read_only=True, many=True) gallery = NewsImageSerializer(read_only=True, many=True)
class Meta: class Meta:

View File

@ -7,5 +7,7 @@ app_name = 'news'
urlpatterns = [ urlpatterns = [
path('', views.NewsListView.as_view(), name='list'), path('', views.NewsListView.as_view(), name='list'),
path('types/', views.NewsTypeListView.as_view(), name='type'), path('types/', views.NewsTypeListView.as_view(), name='type'),
path('types/<int:pk>/tags/', views.NewsTypeTagsView.as_view(),
name='type-tags'),
path('slug/<slug:slug>/', views.NewsDetailView.as_view(), name='rud'), path('slug/<slug:slug>/', views.NewsDetailView.as_view(), name='rud'),
] ]

View File

@ -1,4 +1,6 @@
"""News app views.""" """News app views."""
from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions
from django.conf import settings from django.conf import settings
from django.db.transaction import on_commit from django.db.transaction import on_commit
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@ -8,6 +10,8 @@ from rest_framework.response import Response
from gallery.tasks import delete_image from gallery.tasks import delete_image
from news import filters, models, serializers from news import filters, models, serializers
from rating.tasks import add_rating from rating.tasks import add_rating
from tag.serializers import TagCategoryDetailSerializer
class NewsMixinView: class NewsMixinView:
"""News mixin.""" """News mixin."""
@ -40,6 +44,7 @@ class NewsDetailView(NewsMixinView, generics.RetrieveAPIView):
"""Override get_queryset method.""" """Override get_queryset method."""
return super().get_queryset().with_extended_related() return super().get_queryset().with_extended_related()
class NewsTypeListView(generics.ListAPIView): class NewsTypeListView(generics.ListAPIView):
"""NewsType list view.""" """NewsType list view."""
@ -49,6 +54,18 @@ class NewsTypeListView(generics.ListAPIView):
serializer_class = serializers.NewsTypeSerializer serializer_class = serializers.NewsTypeSerializer
class NewsTypeTagsView(generics.ListAPIView):
"""Resource to get a list of tags for a news type."""
pagination_class = None
permission_classes = (permissions.AllowAny, )
serializer_class = TagCategoryDetailSerializer
def get_queryset(self):
news_type = get_object_or_404(models.NewsType, pk=self.kwargs.get('pk'))
return news_type.tag_categories.with_related()
class NewsBackOfficeMixinView: class NewsBackOfficeMixinView:
"""News back office mixin view.""" """News back office mixin view."""

View File

@ -21,24 +21,29 @@ class EstablishmentDocument(Document):
properties={ properties={
'id': fields.IntegerField(), 'id': fields.IntegerField(),
'name': fields.ObjectField(attr='name_indexing', 'name': fields.ObjectField(attr='name_indexing',
properties=OBJECT_FIELD_PROPERTIES) properties=OBJECT_FIELD_PROPERTIES),
'tag_categories': fields.ObjectField(properties={
'tag_category': fields.ObjectField(
properties={
'id': fields.IntegerField()
}
)
}),
}) })
establishment_subtypes = fields.ObjectField( establishment_subtypes = fields.ObjectField(
properties={ properties={
'id': fields.IntegerField(), 'id': fields.IntegerField(),
'name': fields.ObjectField(attr='name_indexing', 'name': fields.ObjectField(attr='name_indexing',
properties=OBJECT_FIELD_PROPERTIES) properties={
'id': fields.IntegerField(),
}),
}, },
multi=True) multi=True)
tags = fields.ObjectField( tags = fields.ObjectField(
properties={ properties={
'id': fields.IntegerField(attr='metadata.id'), 'tag': fields.ObjectField(properties={
'label': fields.ObjectField(attr='metadata.label_indexing', 'id': fields.IntegerField(),
properties=OBJECT_FIELD_PROPERTIES), }),
'category': fields.ObjectField(attr='metadata.category',
properties={
'id': fields.IntegerField(),
})
}, },
multi=True) multi=True)
address = fields.ObjectField( address = fields.ObjectField(

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

12
apps/tag/admin.py Normal file
View File

@ -0,0 +1,12 @@
from django.contrib import admin
from .models import Tag, TagCategory
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
"""Admin model for model Tag."""
@admin.register(TagCategory)
class TagCategoryAdmin(admin.ModelAdmin):
"""Admin model for model TagCategory."""

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

@ -0,0 +1,7 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class TagConfig(AppConfig):
name = 'tag'
verbose_name = _('tag')

View File

@ -0,0 +1,44 @@
# Generated by Django 2.2.4 on 2019-10-09 07:15
from django.db import migrations, models
import django.db.models.deletion
import utils.models
class Migration(migrations.Migration):
initial = True
dependencies = [
('location', '0010_auto_20190904_0711'),
]
operations = [
migrations.CreateModel(
name='TagCategory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('label', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='label')),
('public', models.BooleanField(default=False)),
('country', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='location.Country')),
],
options={
'verbose_name': 'tag category',
'verbose_name_plural': 'tag categories',
},
bases=(utils.models.TranslatedFieldsMixin, models.Model),
),
migrations.CreateModel(
name='Tag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('label', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='label')),
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tags', to='tag.TagCategory', verbose_name='category')),
],
options={
'verbose_name': 'tag',
'verbose_name_plural': 'tags',
},
bases=(utils.models.TranslatedFieldsMixin, models.Model),
),
]

View File

@ -0,0 +1,27 @@
# Generated by Django 2.2.4 on 2019-10-09 14:08
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('tag', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='tag',
options={'verbose_name': 'Tag', 'verbose_name_plural': 'Tags'},
),
migrations.AlterModelOptions(
name='tagcategory',
options={'verbose_name': 'Tag category', 'verbose_name_plural': 'Tag categories'},
),
migrations.AlterField(
model_name='tag',
name='category',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tags', to='tag.TagCategory', verbose_name='Category'),
),
]

View File

66
apps/tag/models.py Normal file
View File

@ -0,0 +1,66 @@
"""Tag app models."""
from django.db import models
from django.utils.translation import gettext_lazy as _
from configuration.models import TranslationSettings
from utils.models import TJSONField, TranslatedFieldsMixin
class Tag(TranslatedFieldsMixin, models.Model):
"""Tag model."""
label = TJSONField(blank=True, null=True, default=None,
verbose_name=_('label'),
help_text='{"en-GB":"some text"}')
category = models.ForeignKey('TagCategory', on_delete=models.PROTECT,
null=True, related_name='tags',
verbose_name=_('Category'))
class Meta:
"""Meta class."""
verbose_name = _('Tag')
verbose_name_plural = _('Tags')
def __str__(self):
label = 'None'
lang = TranslationSettings.get_solo().default_language
if self.label and lang in self.label:
label = self.label[lang]
return f'id:{self.id}-{label}'
class TagCategoryQuerySet(models.QuerySet):
"""Extended queryset for TagCategory model."""
def by_news_type(self, news_type):
return self.filter(news_types=news_type)
def with_related(self):
return self.select_related('country').prefetch_related('tags')
class TagCategory(TranslatedFieldsMixin, models.Model):
"""Tag base category model."""
label = TJSONField(blank=True, null=True, default=None,
verbose_name=_('label'),
help_text='{"en-GB":"some text"}')
country = models.ForeignKey('location.Country',
on_delete=models.SET_NULL, null=True,
default=None)
public = models.BooleanField(default=False)
objects = TagCategoryQuerySet.as_manager()
class Meta:
"""Meta class."""
verbose_name = _('Tag category')
verbose_name_plural = _('Tag categories')
def __str__(self):
label = 'None'
lang = TranslationSettings.get_solo().default_language
if self.label and lang in self.label:
label = self.label[lang]
return f'id:{self.id}-{label}'

59
apps/tag/serializers.py Normal file
View File

@ -0,0 +1,59 @@
"""Tag serializers."""
from rest_framework import serializers
from tag import models
from utils.serializers import TranslatedField
class TagBaseSerializer(serializers.ModelSerializer):
"""Serializer for model Tag."""
label_translated = TranslatedField()
class Meta:
"""Meta class."""
model = models.Tag
fields = [
'id',
'label',
'label_translated',
'category'
]
extra_kwargs = {
'label': {'write_only': True},
'category': {'write_only': True}
}
class TagCategoryBaseSerializer(serializers.ModelSerializer):
"""Serializer for model TagCategory."""
label_translated = TranslatedField()
country_translated = TranslatedField(source='country.name_translated')
class Meta:
"""Meta class."""
model = models.TagCategory
fields = (
'id',
'label',
'label_translated',
'country',
'country_translated',
'public',
)
extra_kwargs = {
'label': {'write_only': True},
'country': {'write_only': True},
}
class TagCategoryDetailSerializer(TagCategoryBaseSerializer):
tags = TagBaseSerializer(many=True)
class Meta(TagCategoryBaseSerializer.Meta):
"""Meta class."""
fields = TagCategoryBaseSerializer.Meta.fields + ('tags', )

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

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

10
apps/tag/urls.py Normal file
View File

@ -0,0 +1,10 @@
"""Urlconf for app tag."""
from django.urls import path
from . import views
app_name = 'tag'
urlpatterns = [
path('', views.TagListCreateView.as_view(), name='list-create'),
path('category/', views.TagCategoryListCreateView.as_view(), name='category-list-create'),
]

19
apps/tag/views.py Normal file
View File

@ -0,0 +1,19 @@
"""Tag views."""
from rest_framework import generics
from tag import serializers, models
class TagListCreateView(generics.ListCreateAPIView):
"""List/create tag view."""
queryset = models.Tag.objects.all()
serializer_class = serializers.TagBaseSerializer
pagination_class = None
class TagCategoryListCreateView(generics.ListCreateAPIView):
"""List/create tag category view."""
queryset = models.TagCategory.objects.all()
serializer_class = serializers.TagCategoryBaseSerializer
pagination_class = None

View File

@ -73,6 +73,7 @@ PROJECT_APPS = [
'comment.apps.CommentConfig', 'comment.apps.CommentConfig',
'favorites.apps.FavoritesConfig', 'favorites.apps.FavoritesConfig',
'rating.apps.RatingConfig', 'rating.apps.RatingConfig',
'tag.apps.TagConfig',
] ]
EXTERNAL_APPS = [ EXTERNAL_APPS = [

View File

@ -3,11 +3,11 @@ from django.urls import path, include
app_name = 'back' app_name = 'back'
urlpatterns = [ urlpatterns = [
path('gallery/', include(('gallery.urls', 'gallery'), path('gallery/', include(('gallery.urls', 'gallery'), namespace='gallery')),
namespace='gallery')),
path('establishments/', include('establishment.urls.back')), path('establishments/', include('establishment.urls.back')),
path('location/', include('location.urls.back')), path('location/', include('location.urls.back')),
path('news/', include('news.urls.back')), path('news/', include('news.urls.back')),
path('tags/', include(('tag.urls', 'tag'), namespace='tag'))
path('account/', include('account.urls.back')), path('account/', include('account.urls.back')),
path('comment/', include('comment.urls.back')), path('comment/', include('comment.urls.back')),
] ]

View File

@ -24,7 +24,8 @@ urlpatterns = [
path('collections/', include('collection.urls.web')), path('collections/', include('collection.urls.web')),
path('establishments/', include('establishment.urls.web')), path('establishments/', include('establishment.urls.web')),
path('news/', include('news.urls.web')), path('news/', include('news.urls.web')),
path('notifications/', include(('notification.urls.web', "notification"), namespace='notification')), path('notifications/', include(('notification.urls.web', "notification"),
namespace='notification')),
path('partner/', include('partner.urls.web')), path('partner/', include('partner.urls.web')),
path('location/', include('location.urls.web')), path('location/', include('location.urls.web')),
path('main/', include('main.urls')), path('main/', include('main.urls')),