added collection gallery; create migrations for models - collection, gallery, news; fixed models - news, collections

This commit is contained in:
Anatoly 2019-08-27 17:15:09 +03:00
parent 0baeeef302
commit 0733323486
18 changed files with 152 additions and 26 deletions

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-08-27 12:05
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('collection', '0005_auto_20190823_1401'),
]
operations = [
migrations.AlterField(
model_name='collection',
name='image',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='gallery.Image', verbose_name='Collection image'),
),
]

View File

@ -1,5 +1,6 @@
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
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 utils.models import ProjectBaseMixin, ImageMixin from utils.models import ProjectBaseMixin, ImageMixin
@ -37,10 +38,17 @@ class CollectionQuerySet(models.QuerySet):
"""Returned only published collection""" """Returned only published collection"""
return self.filter(is_publish=True) return self.filter(is_publish=True)
def valid(self):
"""Returns valid offers"""
now = timezone.now()
return self.filter(start__lte=now, end__gte=now)
class Collection(ProjectBaseMixin, CollectionNameMixin,
ImageMixin, CollectionDateMixin): class Collection(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin):
"""Collection model.""" """Collection model."""
image = models.ForeignKey(
'gallery.Image', blank=True, default=None, null=True,
verbose_name=_('Collection image'), on_delete=models.CASCADE)
is_publish = models.BooleanField( is_publish = models.BooleanField(
default=False, verbose_name=_('Publish status')) default=False, verbose_name=_('Publish status'))
on_top = models.BooleanField( on_top = models.BooleanField(

View File

@ -1,10 +1,12 @@
from rest_framework import serializers from rest_framework import serializers
from collection import models from collection import models
from utils.serializers import ImageSerializerMixin
class CollectionSerializer(serializers.ModelSerializer): class CollectionSerializer(ImageSerializerMixin, serializers.ModelSerializer):
"""Collection serializer""" """Collection serializer"""
class Meta: class Meta:
model = models.Collection model = models.Collection
fields = [ fields = [

View File

@ -34,6 +34,7 @@ class CollectionListView(CollectionViewMixin, generics.ListAPIView):
def get_queryset(self): def get_queryset(self):
"""Override get_queryset method""" """Override get_queryset method"""
return models.Collection.objects.published()\ return models.Collection.objects.published()\
.valid()\
.by_country_code(code=self.request.country_code)\ .by_country_code(code=self.request.country_code)\
.order_by('-on_top', '-created') .order_by('-on_top', '-created')

View File

@ -1,8 +1,8 @@
from django.contrib import admin from django.contrib import admin
from gallery.models import Gallery from gallery.models import Image
@admin.register(Gallery) @admin.register(Image)
class GalleryModelAdmin(admin.ModelAdmin): class ImageModelAdmin(admin.ModelAdmin):
"""Gallery model admin""" """Image model admin"""

View File

@ -0,0 +1,30 @@
# Generated by Django 2.2.4 on 2019-08-27 12:04
from django.db import migrations, models
import django.utils.timezone
import easy_thumbnails.fields
import utils.methods
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Image',
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')),
('image', easy_thumbnails.fields.ThumbnailerImageField(upload_to=utils.methods.image_path, verbose_name='Image')),
],
options={
'verbose_name': 'Image',
'verbose_name_plural': 'Images',
},
),
]

View File

@ -1,16 +1,21 @@
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from easy_thumbnails.fields import ThumbnailerImageField
from utils.methods import image_path
from utils.models import ProjectBaseMixin, ImageMixin from utils.models import ProjectBaseMixin, ImageMixin
class Gallery(ProjectBaseMixin, ImageMixin): class Image(ProjectBaseMixin, ImageMixin):
"""Gallery model.""" """Image model."""
image = ThumbnailerImageField(upload_to=image_path,
verbose_name=_('Image'))
class Meta: class Meta:
"""Meta class.""" """Meta class."""
verbose_name = _('Gallery') verbose_name = _('Image')
verbose_name_plural = _('Galleries') verbose_name_plural = _('Images')
def __str__(self): def __str__(self):
"""String representation""" """String representation of image instance"""
return str(self.get_image_url) return str(self.id)

View File

@ -1,19 +1,24 @@
"""Serializers for model Image"""
from rest_framework import serializers from rest_framework import serializers
from . import models from . import models
class GallerySerializer(serializers.ModelSerializer): class ImageSerializer(serializers.ModelSerializer):
"""Serializer for model Gallery.""" """Serializer for model Image."""
# REQUEST
image = serializers.ImageField(write_only=True)
# RESPONSE # RESPONSE
url = serializers.URLField(source='get_image_url') url = serializers.URLField(source='get_image_url',
required=False)
class Meta: class Meta:
"""Meta class""" """Meta class"""
model = models.Gallery model = models.Image
fields = ( fields = (
'id',
'image', 'image',
'url' 'url',
) )
read_only_fields = ( read_only_fields = (
'url', 'url',

View File

@ -5,7 +5,7 @@ from . import views
app_name = 'gallery' app_name = 'gallery'
url_patterns = [ urlpatterns = [
path('upload/', views.GalleryUploadImage.as_view(), path('upload/', views.GalleryUploadImage.as_view(),
name='upload_image') name='upload_image')
] ]

View File

@ -5,6 +5,6 @@ from . import models, serializers
class GalleryUploadImage(generics.CreateAPIView): class GalleryUploadImage(generics.CreateAPIView):
"""Upload image to gallery""" """Upload image to gallery"""
model = models.Gallery model = models.Image
queryset = models.Gallery.objects.all() queryset = models.Image.objects.all()
serializer_class = serializers.GallerySerializer serializer_class = serializers.ImageSerializer

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-08-27 12:05
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('news', '0005_auto_20190823_1149'),
]
operations = [
migrations.AlterField(
model_name='news',
name='image',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='gallery.Image', verbose_name='News image'),
),
]

View File

@ -1,5 +1,6 @@
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
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 utils.models import (ProjectBaseMixin, BaseAttributes, from utils.models import (ProjectBaseMixin, BaseAttributes,
@ -36,8 +37,13 @@ class NewsQuerySet(models.QuerySet):
"""Return only published news""" """Return only published news"""
return self.filter(is_publish=True) return self.filter(is_publish=True)
def valid(self):
"""Returns valid offers"""
now = timezone.now()
return self.filter(start__lte=now, end__gte=now)
class News(ImageMixin, BaseAttributes):
class News(BaseAttributes):
"""News model.""" """News model."""
news_type = models.ForeignKey( news_type = models.ForeignKey(
NewsType, verbose_name=_('news type'), on_delete=models.CASCADE) NewsType, verbose_name=_('news type'), on_delete=models.CASCADE)
@ -64,6 +70,9 @@ class News(ImageMixin, BaseAttributes):
country = models.ForeignKey( country = models.ForeignKey(
'location.Country', blank=True, null=True, 'location.Country', blank=True, null=True,
verbose_name=_('country'), on_delete=models.CASCADE) verbose_name=_('country'), on_delete=models.CASCADE)
image = models.ForeignKey(
'gallery.Image', blank=True, default=None, null=True,
verbose_name=_('News image'), on_delete=models.CASCADE)
is_highlighted = models.BooleanField( is_highlighted = models.BooleanField(
default=False, verbose_name=_('Is highlighted')) default=False, verbose_name=_('Is highlighted'))
# TODO: metadata_keys - описание ключей для динамического построения полей метаданных # TODO: metadata_keys - описание ключей для динамического построения полей метаданных

View File

@ -3,6 +3,7 @@ from rest_framework import serializers
from location.models import Address from location.models import Address
from location.serializers import AddressSerializer from location.serializers import AddressSerializer
from news import models from news import models
from utils.serializers import ImageSerializerMixin
class NewsTypeSerializer(serializers.ModelSerializer): class NewsTypeSerializer(serializers.ModelSerializer):
@ -23,7 +24,7 @@ class NewsLocalizationMixinSerializer(serializers.ModelSerializer):
description_trans = serializers.CharField(read_only=True) description_trans = serializers.CharField(read_only=True)
class NewsSerializer(NewsLocalizationMixinSerializer): class NewsSerializer(NewsLocalizationMixinSerializer, ImageSerializerMixin):
"""News serializer.""" """News serializer."""
address = AddressSerializer() address = AddressSerializer()
@ -50,7 +51,6 @@ class NewsCreateUpdateSerializer(NewsSerializer):
title = serializers.JSONField() title = serializers.JSONField()
subtitle = serializers.JSONField() subtitle = serializers.JSONField()
description = serializers.JSONField() description = serializers.JSONField()
image = serializers.ImageField(required=True)
news_type = serializers.PrimaryKeyRelatedField( news_type = serializers.PrimaryKeyRelatedField(
queryset=models.NewsType.objects.all(), write_only=True) queryset=models.NewsType.objects.all(), write_only=True)
address = serializers.PrimaryKeyRelatedField( address = serializers.PrimaryKeyRelatedField(

View File

@ -26,6 +26,7 @@ class NewsList(NewsViewMixin, JWTListAPIView):
"""Override get_queryset method""" """Override get_queryset method"""
return News.objects.annotate_localized_fields(locale=self.request.locale)\ return News.objects.annotate_localized_fields(locale=self.request.locale)\
.published()\ .published()\
.valid()\
.by_country_code(code=self.request.country_code)\ .by_country_code(code=self.request.country_code)\
.order_by('-is_highlighted', '-created') .order_by('-is_highlighted', '-created')

View File

@ -1,5 +1,7 @@
"""Utils app models.""" """Utils app models."""
from os.path import exists
from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.contrib.gis.db import models from django.contrib.gis.db import models
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
@ -74,7 +76,14 @@ class ImageMixin(models.Model):
def get_image_url(self, key=None): def get_image_url(self, key=None):
"""Get image thumbnail url.""" """Get image thumbnail url."""
return self.get_image(key).url if self.image else None return self.get_image(key).url if self.image and exists(self.image.path) else None
def get_full_image_url(self, request, thumbnail_key=None):
"""Get full image url"""
if self.image and exists(self.image.path):
return request.build_absolute_uri(self.get_image(thumbnail_key).url)
else:
return None
def image_tag(self): def image_tag(self):
"""Admin preview tag.""" """Admin preview tag."""

15
apps/utils/serializers.py Normal file
View File

@ -0,0 +1,15 @@
"""Serializer mixins"""
from rest_framework import serializers
class ImageSerializerMixin(serializers.Serializer):
"""
Image serializer mixin.
Need to return an absolute path of cropped image instead of relative path
"""
# RESPONSE
image = serializers.SerializerMethodField()
def get_image(self, obj):
"""Get full image URL"""
return obj.image.get_full_image_url(self.context.get('request'))

View File

@ -57,6 +57,7 @@ PROJECT_APPS = [
'authorization.apps.AuthorizationConfig', 'authorization.apps.AuthorizationConfig',
'collection.apps.CollectionConfig', 'collection.apps.CollectionConfig',
'establishment.apps.EstablishmentConfig', 'establishment.apps.EstablishmentConfig',
'gallery.apps.GalleryConfig',
'location.apps.LocationConfig', 'location.apps.LocationConfig',
'main.apps.MainConfig', 'main.apps.MainConfig',
'news.apps.NewsConfig', 'news.apps.NewsConfig',

View File

@ -54,6 +54,8 @@ urlpatterns_auth = [
] ]
api_urlpatterns = [ api_urlpatterns = [
path('gallery/', include(('gallery.urls', 'gallery'),
namespace='gallery')),
path('location/', include(('location.urls', 'location'), path('location/', include(('location.urls', 'location'),
namespace='location')), namespace='location')),
path('main/', include(('main.urls', 'main'), path('main/', include(('main.urls', 'main'),