version 0.0.17: added annotator for translation JSONFields, and refactored JWTView a little bit

This commit is contained in:
Anatoly 2019-08-15 18:33:36 +03:00
parent c7d7f99c68
commit 394d82342c
5 changed files with 105 additions and 24 deletions

View File

@ -20,10 +20,7 @@ from authorization.models import Application
from authorization.serializers import common as serializers from authorization.serializers import common as serializers
from utils import exceptions as utils_exceptions from utils import exceptions as utils_exceptions
from utils.views import (JWTGenericViewMixin, from utils.views import (JWTGenericViewMixin,
JWTCreateAPIView, JWTCreateAPIView)
JWTDestroyAPIView,
JWTUpdateAPIView,
JWTRetrieveAPIView)
# Mixins # Mixins
@ -33,7 +30,7 @@ class JWTAuthViewMixin(JWTCreateAPIView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
"""Implement POST method""" """Implement POST method"""
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
@ -102,7 +99,7 @@ class OAuth2ViewMixin(CsrfExemptMixin, OAuthLibMixin, BaseOAuth2ViewMixin):
# Sign in via Facebook # Sign in via Facebook
class OAuth2SignUpView(OAuth2ViewMixin, JWTAuthViewMixin): class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin):
""" """
Implements an endpoint to convert a provider token to an access token Implements an endpoint to convert a provider token to an access token
@ -130,7 +127,7 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTAuthViewMixin):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
# Preparing request data # Preparing request data
@ -187,7 +184,7 @@ class SignUpView(JWTCreateAPIView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
"""Implement POST-method""" """Implement POST-method"""
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
@ -224,7 +221,7 @@ class RefreshTokenView(JWTGenericViewMixin):
serializer_class = serializers.RefreshTokenSerializer serializer_class = serializers.RefreshTokenSerializer
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
@ -245,13 +242,13 @@ class RefreshTokenView(JWTGenericViewMixin):
# Logout # Logout
class LogoutView(JWTAuthViewMixin): class LogoutView(JWTGenericViewMixin):
"""Logout user""" """Logout user"""
serializer_class = serializers.LogoutSerializer serializer_class = serializers.LogoutSerializer
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
"""Override create method""" """Override create method"""
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)

View File

@ -1,14 +1,47 @@
from django.contrib.postgres.fields import JSONField
from django.contrib.postgres.fields.jsonb import KeyTextTransform
from django.db import models from django.db import models
from utils.models import ProjectBaseMixin, BaseAttributes
from django.contrib.postgres.fields import JSONField, ArrayField
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from utils.models import ProjectBaseMixin, BaseAttributes
class NewsType(models.Model): class NewsType(models.Model):
"""NewsType model.""" """NewsType model."""
name = models.CharField(_('name'), max_length=250) name = models.CharField(_('name'), max_length=250)
class NewsManager(models.Manager):
"""Manager for model News"""
def annotate_localized_fields(self, locale):
"""Return queryset by locale"""
prefix = 'trans'
# Prepare fields to localization (only JSONField can be localized)
fields = [field.name for field in self.model._meta.fields if isinstance(field, JSONField)]
# Check filters to check if field has localization
filters = {f'{field}__has_key': locale for field in fields}
# Filter QuerySet by prepared filters
queryset = self.filter(**filters)
# Prepare field for annotator
localized_fields = {f'{field}_{prefix}': KeyTextTransform(f'{locale}', field) for field in fields}
# Annotate them
for _ in fields:
queryset = queryset.annotate(**localized_fields)
return queryset
class NewsQuerySet(models.QuerySet):
"""QuerySet for model News"""
def by_type(self, news_type):
"""Filter News by type"""
return self.filter(news_type__name=news_type)
class News(BaseAttributes): class News(BaseAttributes):
"""News model.""" """News model."""
news_type = models.ForeignKey( news_type = models.ForeignKey(
@ -34,6 +67,8 @@ class News(BaseAttributes):
# TODO: metadata_keys - описание ключей для динамического построения полей метаданных # TODO: metadata_keys - описание ключей для динамического построения полей метаданных
# TODO: metadata_values - Описание значений для динамических полей из MetadataKeys # TODO: metadata_values - Описание значений для динамических полей из MetadataKeys
objects = NewsManager.from_queryset(NewsQuerySet)()
class Meta: class Meta:
verbose_name = _('news') verbose_name = _('news')
verbose_name_plural = _('news') verbose_name_plural = _('news')

View File

@ -8,18 +8,23 @@ class NewsSerializer(serializers.ModelSerializer):
"""News serializer.""" """News serializer."""
address = AddressSerializer() address = AddressSerializer()
# Localized fields
title_trans = serializers.CharField()
subtitle_trans = serializers.CharField()
description_trans = serializers.CharField()
class Meta: class Meta:
model = models.News model = models.News
fields = [ fields = [
'id', 'id',
'news_type', 'news_type',
'title',
'subtitle',
'description',
'start', 'start',
'end', 'end',
'playlist', 'playlist',
'address' 'address',
'title_trans',
'subtitle_trans',
'description_trans',
] ]

View File

@ -1,12 +1,22 @@
from rest_framework import generics, permissions from rest_framework import generics, permissions
from news.models import News from news.models import News
from news.serializers import common as serializers from news.serializers import common as serializers
from utils.views import JWTGenericViewMixin from utils.views import (JWTGenericViewMixin,
JWTListAPIView)
class NewsList(generics.ListAPIView): # Mixins
class NewsViewMixin(JWTGenericViewMixin):
"""View mixin for News model"""
def get_queryset(self, *args, **kwargs):
"""Override get_queryset method"""
return News.objects.annotate_localized_fields(
locale=self._get_locale(request=self.request))
class NewsList(NewsViewMixin, JWTListAPIView):
"""News list view.""" """News list view."""
queryset = News.objects.all()
permission_classes = (permissions.AllowAny, ) permission_classes = (permissions.AllowAny, )
serializer_class = serializers.NewsSerializer serializer_class = serializers.NewsSerializer

View File

@ -17,6 +17,10 @@ class JWTGenericViewMixin(generics.GenericAPIView):
REFRESH_TOKEN_HTTP_ONLY = False REFRESH_TOKEN_HTTP_ONLY = False
REFRESH_TOKEN_SECURE = False REFRESH_TOKEN_SECURE = False
COOKIE = namedtuple('COOKIE', ['key', 'value', 'http_only', 'secure']) COOKIE = namedtuple('COOKIE', ['key', 'value', 'http_only', 'secure'])
def _get_locale(self, request):
"""Get locale from request"""
return request.COOKIES.get('locale')
def _check_locale(self, locale: str): def _check_locale(self, locale: str):
@ -77,12 +81,42 @@ class JWTGenericViewMixin(generics.GenericAPIView):
secure=self.REFRESH_TOKEN_SECURE)] secure=self.REFRESH_TOKEN_SECURE)]
class JWTListAPIView(JWTGenericViewMixin, generics.ListAPIView):
"""
Concrete view for creating a model instance.
"""
def get(self, request, *args, **kwargs):
_locale = self._get_locale(request=request)
try:
locale = self._check_locale(locale=_locale)
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
response = self.get_paginated_response(serializer.data)
else:
serializer = self.get_serializer(queryset, many=True)
response = Response(serializer.data)
access_token, refresh_token = self._get_tokens_from_cookies(request)
except exceptions.LocaleNotExisted:
raise exceptions.LocaleNotExisted(locale=_locale)
else:
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(locale=locale,
access_token=access_token.value,
refresh_token=refresh_token.value),
response=response)
class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView): class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView):
""" """
Concrete view for creating a model instance. Concrete view for creating a model instance.
""" """
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request=request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
@ -108,7 +142,7 @@ class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView):
""" """
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
"""Implement GET method""" """Implement GET method"""
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request=request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
@ -138,7 +172,7 @@ class JWTDestroyAPIView(JWTGenericViewMixin, generics.DestroyAPIView):
Concrete view for deleting a model instance. Concrete view for deleting a model instance.
""" """
def delete(self, request, *args, **kwargs): def delete(self, request, *args, **kwargs):
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request=request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
instance = self.get_object() instance = self.get_object()
@ -161,7 +195,7 @@ class JWTUpdateAPIView(JWTGenericViewMixin, generics.UpdateAPIView):
Concrete view for updating a model instance. Concrete view for updating a model instance.
""" """
def put(self, request, *args, **kwargs): def put(self, request, *args, **kwargs):
_locale = request.COOKIES.get('locale') _locale = self._get_locale(request=request)
try: try:
locale = self._check_locale(locale=_locale) locale = self._check_locale(locale=_locale)
partial = kwargs.pop('partial', False) partial = kwargs.pop('partial', False)