refactor news tags

This commit is contained in:
evgeniy-st 2019-10-09 18:25:40 +03:00
parent 2191a505a5
commit 074a5ec5ea
11 changed files with 131 additions and 31 deletions

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'))
ratings = generic.GenericRelation(Rating) ratings = generic.GenericRelation(Rating)
objects = NewsQuerySet.as_manager() objects = NewsQuerySet.as_manager()
@ -163,4 +165,3 @@ class News(BaseAttributes, TranslatedFieldsMixin):
@property @property
def same_theme(self): def same_theme(self):
return self.__class__.objects.same_theme(self)[:3] return self.__class__.objects.same_theme(self)[:3]

View File

@ -3,8 +3,8 @@ from rest_framework import serializers
from account.serializers.common import UserBaseSerializer from account.serializers.common import UserBaseSerializer
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
@ -27,7 +27,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)
class Meta: class Meta:
"""Meta class.""" """Meta class."""

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,7 +1,10 @@
"""News app views.""" """News app views."""
from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions from rest_framework import generics, permissions
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."""
@ -34,6 +37,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."""
@ -43,6 +47,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

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

@ -1,24 +1,25 @@
"""Tag app models.""" """Tag app models."""
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from configuration.models import TranslationSettings from configuration.models import TranslationSettings
from utils.models import TJSONField, TranslatedFieldsMixin from utils.models import TJSONField, TranslatedFieldsMixin
class Tag(TranslatedFieldsMixin, models.Model): class Tag(TranslatedFieldsMixin, models.Model):
"""Tag model.""" """Tag model."""
label = TJSONField(
_('label'), null=True, blank=True, label = TJSONField(blank=True, null=True, default=None,
default=None, help_text='{"en-GB":"some text"}') verbose_name=_('label'),
category = models.ForeignKey('TagCategory', help_text='{"en-GB":"some text"}')
on_delete=models.SET_NULL, null=True, category = models.ForeignKey('TagCategory', on_delete=models.PROTECT,
related_name='tags', null=True, related_name='tags',
verbose_name='category') verbose_name=_('Category'))
class Meta: class Meta:
verbose_name = _('tag') """Meta class."""
verbose_name_plural = _('tags')
verbose_name = _('Tag')
verbose_name_plural = _('Tags')
def __str__(self): def __str__(self):
label = 'None' label = 'None'
@ -28,20 +29,34 @@ class Tag(TranslatedFieldsMixin, models.Model):
return f'id:{self.id}-{label}' 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): class TagCategory(TranslatedFieldsMixin, models.Model):
"""Tag base category model.""" """Tag base category model."""
label = TJSONField(
_('label'), null=True, blank=True, label = TJSONField(blank=True, null=True, default=None,
default=None, help_text='{"en-GB":"some text"}') verbose_name=_('label'),
help_text='{"en-GB":"some text"}')
country = models.ForeignKey('location.Country', country = models.ForeignKey('location.Country',
on_delete=models.SET_NULL, null=True, on_delete=models.SET_NULL, null=True,
default=None) default=None)
public = models.BooleanField(default=False) public = models.BooleanField(default=False)
objects = TagCategoryQuerySet.as_manager()
class Meta: class Meta:
verbose_name = _('tag category') """Meta class."""
verbose_name_plural = _('tag categories')
verbose_name = _('Tag category')
verbose_name_plural = _('Tag categories')
def __str__(self): def __str__(self):
label = 'None' label = 'None'

View File

@ -1,14 +1,17 @@
"""Tag serializers.""" """Tag serializers."""
from rest_framework import serializers from rest_framework import serializers
from . import models from tag import models
from utils.serializers import TranslatedField from utils.serializers import TranslatedField
class TagBaseSerializer(serializers.ModelSerializer): class TagBaseSerializer(serializers.ModelSerializer):
"""Serializer for model Tag.""" """Serializer for model Tag."""
label_translated = TranslatedField() label_translated = TranslatedField()
class Meta: class Meta:
"""Meta class."""
model = models.Tag model = models.Tag
fields = [ fields = [
'id', 'id',
@ -24,21 +27,33 @@ class TagBaseSerializer(serializers.ModelSerializer):
class TagCategoryBaseSerializer(serializers.ModelSerializer): class TagCategoryBaseSerializer(serializers.ModelSerializer):
"""Serializer for model TagCategory.""" """Serializer for model TagCategory."""
label_translated = TranslatedField() label_translated = TranslatedField()
country_translated = TranslatedField(source='country.name_translated') country_translated = TranslatedField(source='country.name_translated')
class Meta: class Meta:
"""Meta class.""" """Meta class."""
model = models.TagCategory model = models.TagCategory
fields = [ fields = (
'id', 'id',
'label', 'label',
'label_translated', 'label_translated',
'country', 'country',
'country_translated', 'country_translated',
'public', 'public',
] )
extra_kwargs = { extra_kwargs = {
'label': {'write_only': True}, 'label': {'write_only': True},
'country': {'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', )

View File

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

View File

@ -3,11 +3,9 @@ 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'), path('tags/', include(('tag.urls', 'tag'), namespace='tag'))
namespace='tag'))
] ]

View File

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