Merge branch 'feature/add-city-endpoints' into feature/migrate-city-photos

This commit is contained in:
littlewolf 2019-11-08 14:15:34 +03:00
commit 48d9ce37f7
8 changed files with 248 additions and 5 deletions

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-11-07 08:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gallery', '0006_merge_20191027_1758'),
('location', '0023_auto_20191107_0742'),
]
operations = [
migrations.AddField(
model_name='city',
name='gallery',
field=models.ManyToManyField(through='location.CityGallery', to='gallery.Image'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-07 20:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('location', '0024_city_gallery'),
]
operations = [
migrations.AlterField(
model_name='city',
name='gallery',
field=models.ManyToManyField(blank=True, through='location.CityGallery', to='gallery.Image'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-07 20:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('location', '0025_auto_20191107_2005'),
]
operations = [
migrations.AlterField(
model_name='city',
name='gallery',
field=models.ManyToManyField(blank=True, null=True, through='location.CityGallery', to='gallery.Image'),
),
]

View File

@ -109,6 +109,8 @@ class City(models.Model):
map_ref = models.CharField(max_length=255, blank=True, null=True)
situation = models.CharField(max_length=255, blank=True, null=True)
gallery = models.ManyToManyField('gallery.Image', through='location.CityGallery', blank=True)
objects = CityQuerySet.as_manager()
class Meta:

View File

@ -4,6 +4,7 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from location import models
from utils.serializers import TranslatedField
from gallery.models import Image
class CountrySerializer(serializers.ModelSerializer):
@ -56,6 +57,116 @@ class RegionSerializer(serializers.ModelSerializer):
]
class CropImageSerializer(serializers.Serializer):
"""Serializer for crop images for City object."""
preview_url = serializers.SerializerMethodField()
promo_horizontal_web_url = serializers.SerializerMethodField()
promo_horizontal_mobile_url = serializers.SerializerMethodField()
tile_horizontal_web_url = serializers.SerializerMethodField()
tile_horizontal_mobile_url = serializers.SerializerMethodField()
tile_vertical_web_url = serializers.SerializerMethodField()
highlight_vertical_web_url = serializers.SerializerMethodField()
editor_web_url = serializers.SerializerMethodField()
editor_mobile_url = serializers.SerializerMethodField()
def get_preview_url(self, obj):
"""Get crop preview."""
return obj.instance.get_image_url('news_preview')
def get_promo_horizontal_web_url(self, obj):
"""Get crop promo_horizontal_web."""
return obj.instance.get_image_url('news_promo_horizontal_web')
def get_promo_horizontal_mobile_url(self, obj):
"""Get crop promo_horizontal_mobile."""
return obj.instance.get_image_url('news_promo_horizontal_mobile')
def get_tile_horizontal_web_url(self, obj):
"""Get crop tile_horizontal_web."""
return obj.instance.get_image_url('news_tile_horizontal_web')
def get_tile_horizontal_mobile_url(self, obj):
"""Get crop tile_horizontal_mobile."""
return obj.instance.get_image_url('news_tile_horizontal_mobile')
def get_tile_vertical_web_url(self, obj):
"""Get crop tile_vertical_web."""
return obj.instance.get_image_url('news_tile_vertical_web')
def get_highlight_vertical_web_url(self, obj):
"""Get crop highlight_vertical_web."""
return obj.instance.get_image_url('news_highlight_vertical_web')
def get_editor_web_url(self, obj):
"""Get crop editor_web."""
return obj.instance.get_image_url('news_editor_web')
def get_editor_mobile_url(self, obj):
"""Get crop editor_mobile."""
return obj.instance.get_image_url('news_editor_mobile')
class CityImageSerializer(serializers.ModelSerializer):
"""Serializer for returning crop images of news image."""
orientation_display = serializers.CharField(source='get_orientation_display',
read_only=True)
original_url = serializers.URLField(source='image.url')
auto_crop_images = CropImageSerializer(source='image', allow_null=True)
class Meta:
model = Image
fields = [
'id',
'title',
'orientation_display',
'original_url',
'auto_crop_images',
]
extra_kwargs = {
'orientation': {'write_only': True}
}
class CityGallerySerializer(serializers.ModelSerializer):
"""Serializer class for model NewsGallery."""
class Meta:
"""Meta class"""
model = models.CityGallery
fields = [
'id',
'is_main',
]
def get_request_kwargs(self):
"""Get url kwargs from request."""
return self.context.get('request').parser_context.get('kwargs')
def validate(self, attrs):
"""Override validate method."""
news_pk = self.get_request_kwargs().get('pk')
image_id = self.get_request_kwargs().get('image_id')
news_qs = models.City.objects.filter(pk=news_pk)
image_qs = Image.objects.filter(id=image_id)
if not news_qs.exists():
raise serializers.ValidationError({'detail': _('News not found')})
if not image_qs.exists():
raise serializers.ValidationError({'detail': _('Image not found')})
news = news_qs.first()
image = image_qs.first()
attrs['news'] = news
attrs['image'] = image
return attrs
class CitySerializer(serializers.ModelSerializer):
"""City serializer."""
region = RegionSerializer(read_only=True)
@ -69,7 +180,8 @@ class CitySerializer(serializers.ModelSerializer):
queryset=models.Country.objects.all(),
write_only=True
)
country = CountrySerializer()
city_gallery = CityGallerySerializer(many=True, read_only=True)
country = CountrySerializer(read_only=True)
class Meta:
model = models.City
@ -80,10 +192,10 @@ class CitySerializer(serializers.ModelSerializer):
'region',
'region_id',
'country_id',
'country',
'postal_code',
'is_island',
'city_gallery'
'city_gallery',
'country'
]

View File

@ -162,6 +162,7 @@ class CityTests(BaseTestCase):
response = self.client.post('/api/back/location/cities/', data=data, format='json')
response_data = response.json()
print(response_data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response = self.client.get(f'/api/back/location/cities/{response_data["id"]}/', format='json')

View File

@ -12,6 +12,11 @@ urlpatterns = [
path('cities/', views.CityListCreateView.as_view(), name='city-list'),
path('cities/<int:pk>/', views.CityRUDView.as_view(), name='city-detail'),
path('cities/<int:pk>/gallery/', views.CityGalleryListView.as_view(),
name='gallery-list'),
path('cities/<int:pk>/gallery/<int:image_id>/', views.CityGalleryCreateDestroyView.as_view(),
name='gallery-create-destroy'),
path('countries/', views.CountryListView.as_view(), name='country-list'),
path('countries/<int:pk>/', views.CountryRetrieveView.as_view(), name='country-retrieve'),

View File

@ -1,6 +1,10 @@
"""Location app views."""
from rest_framework import generics
from rest_framework import permissions
from django.conf import settings
from django.db.transaction import on_commit
from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions, status
from rest_framework.response import Response
from gallery.tasks import delete_image
from location import models, serializers
@ -103,6 +107,70 @@ class CityUpdateView(CityViewMixin, generics.UpdateAPIView):
serializer_class = serializers.CitySerializer
class CityGalleryListView(generics.ListAPIView):
"""Resource for returning gallery for news for back-office users."""
serializer_class = serializers.CityImageSerializer
permission_classes = (permissions.IsAuthenticated,)
queryset = models.City.objects
def get_object(self):
"""Override get_object method."""
qs = super(CityGalleryListView, self).get_queryset()
city = get_object_or_404(qs, pk=self.kwargs['pk'])
# May raise a permission denied
self.check_object_permissions(self.request, city)
return city
def get_queryset(self):
"""Override get_queryset method."""
return self.get_object().gallery.all()
class CityGalleryCreateDestroyView(generics.CreateAPIView,
generics.DestroyAPIView):
permission_classes = (permissions.IsAuthenticated,)
queryset = models.City.objects
"""Resource for a create gallery for news for back-office users."""
serializer_class = serializers.CityGallerySerializer
def get_object(self):
"""
Returns the object the view is displaying.
"""
city_qs = self.filter_queryset(self.get_queryset())
city = get_object_or_404(city_qs, pk=self.kwargs['pk'])
gallery = get_object_or_404(city.news_gallery, image_id=self.kwargs['image_id'])
# May raise a permission denied
self.check_object_permissions(self.request, gallery)
return gallery
def create(self, request, *args, **kwargs):
"""Overridden create method"""
super().create(request, *args, **kwargs)
return Response(status=status.HTTP_201_CREATED)
def destroy(self, request, *args, **kwargs):
"""Override destroy method."""
gallery_obj = self.get_object()
if settings.USE_CELERY:
on_commit(lambda: delete_image.delay(image_id=gallery_obj.image.id,
completely=False))
else:
on_commit(lambda: delete_image(image_id=gallery_obj.image.id,
completely=False))
# Delete an instances of NewsGallery model
gallery_obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
# Address
class AddressCreateView(AddressViewMixin, generics.CreateAPIView):
"""Create view for model Address"""