Merge branch 'develop' into feature/navigation-bar
# Conflicts: # apps/main/serializers.py
This commit is contained in:
commit
6541070d1c
|
|
@ -0,0 +1,29 @@
|
|||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from sorl.thumbnail import get_thumbnail
|
||||
|
||||
from collection.models import Collection
|
||||
from utils.methods import image_url_valid, get_image_meta_by_url
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
SORL_THUMBNAIL_ALIAS = 'collection_image'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with transaction.atomic():
|
||||
for collection in Collection.objects.all():
|
||||
if not image_url_valid(collection.image_url):
|
||||
continue
|
||||
|
||||
_, width, height = get_image_meta_by_url(collection.image_url)
|
||||
sorl_settings = settings.SORL_THUMBNAIL_ALIASES[self.SORL_THUMBNAIL_ALIAS]
|
||||
sorl_width_height = sorl_settings['geometry_string'].split('x')
|
||||
|
||||
if int(sorl_width_height[0]) > width or int(sorl_width_height[1]) > height:
|
||||
collection.image_url = get_thumbnail(
|
||||
file_=collection.image_url,
|
||||
**settings.SORL_THUMBNAIL_ALIASES[self.SORL_THUMBNAIL_ALIAS]
|
||||
).url
|
||||
|
||||
collection.save()
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from sorl.thumbnail import get_thumbnail
|
||||
|
||||
from establishment.models import Establishment
|
||||
from utils.methods import image_url_valid, get_image_meta_by_url
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
SORL_THUMBNAIL_ALIAS = 'establishment_collection_image'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with transaction.atomic():
|
||||
for establishment in Establishment.objects.all():
|
||||
if not image_url_valid(establishment.preview_image_url):
|
||||
continue
|
||||
|
||||
_, width, height = get_image_meta_by_url(establishment.preview_image_url)
|
||||
sorl_settings = settings.SORL_THUMBNAIL_ALIASES[self.SORL_THUMBNAIL_ALIAS]
|
||||
sorl_width_height = sorl_settings['geometry_string'].split('x')
|
||||
|
||||
if int(sorl_width_height[0]) > width or int(sorl_width_height[1]) > height:
|
||||
establishment.preview_image_url = get_thumbnail(
|
||||
file_=establishment.preview_image_url,
|
||||
**sorl_settings
|
||||
)
|
||||
establishment.save()
|
||||
|
|
@ -58,8 +58,6 @@ class EstablishmentType(TypeDefaultImageMixin, TranslatedFieldsMixin, ProjectBas
|
|||
blank=True, null=True, default=None,
|
||||
verbose_name='default image')
|
||||
|
||||
chosen_tags = generic.GenericRelation(to='tag.ChosenTag')
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,27 @@
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from account.serializers.common import UserShortSerializer
|
||||
from establishment import models
|
||||
from establishment import serializers as model_serializers
|
||||
from establishment.models import ContactPhone
|
||||
from gallery.models import Image
|
||||
from location.models import Address
|
||||
from location.serializers import AddressDetailSerializer, TranslatedField
|
||||
from main.models import Currency
|
||||
from location.models import Address
|
||||
from main.serializers import AwardSerializer
|
||||
from utils.decorators import with_base_attributes
|
||||
from utils.serializers import TimeZoneChoiceField
|
||||
from gallery.models import Image
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from account.serializers.common import UserShortSerializer
|
||||
|
||||
|
||||
def phones_handler(phones_list, establishment):
|
||||
"""
|
||||
create or update phones for establishment 35016 string
|
||||
"""
|
||||
ContactPhone.objects.filter(establishment=establishment).delete()
|
||||
|
||||
for new_phone in phones_list:
|
||||
ContactPhone.objects.create(establishment=establishment, phone=new_phone)
|
||||
|
||||
|
||||
class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSerializer):
|
||||
|
|
@ -37,6 +48,11 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria
|
|||
address_id = serializers.PrimaryKeyRelatedField(write_only=True, source='address',
|
||||
queryset=Address.objects.all())
|
||||
tz = TimeZoneChoiceField()
|
||||
phones_list = serializers.ListField(
|
||||
child=serializers.CharField(max_length=20),
|
||||
allow_empty=True,
|
||||
write_only=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = models.Establishment
|
||||
|
|
@ -62,8 +78,15 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria
|
|||
'tags',
|
||||
'tz',
|
||||
'address_id',
|
||||
'phones_list',
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
phones_list = validated_data.pop('phones_list')
|
||||
instance = super().create(validated_data)
|
||||
phones_handler(phones_list, instance)
|
||||
return instance
|
||||
|
||||
|
||||
class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
||||
"""Establishment create serializer"""
|
||||
|
|
@ -80,6 +103,11 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
|||
socials = model_serializers.SocialNetworkRelatedSerializers(read_only=False,
|
||||
many=True, )
|
||||
type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type')
|
||||
phones_list = serializers.ListField(
|
||||
child=serializers.CharField(max_length=20),
|
||||
allow_empty=True,
|
||||
write_only=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = models.Establishment
|
||||
|
|
@ -99,8 +127,15 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
|||
'is_publish',
|
||||
'address',
|
||||
'tags',
|
||||
'phones_list',
|
||||
]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
phones_list = validated_data.pop('phones_list')
|
||||
instance = super().update(instance, validated_data)
|
||||
phones_handler(phones_list, instance)
|
||||
return instance
|
||||
|
||||
|
||||
class SocialChoiceSerializers(serializers.ModelSerializer):
|
||||
"""SocialChoice serializers."""
|
||||
|
|
@ -166,7 +201,6 @@ class ContactEmailBackSerializers(model_serializers.PlateSerializer):
|
|||
]
|
||||
|
||||
|
||||
|
||||
class PositionBackSerializer(serializers.ModelSerializer):
|
||||
"""Position Back serializer."""
|
||||
|
||||
|
|
@ -181,6 +215,7 @@ class PositionBackSerializer(serializers.ModelSerializer):
|
|||
'index_name',
|
||||
]
|
||||
|
||||
|
||||
# TODO: test decorator
|
||||
@with_base_attributes
|
||||
class EmployeeBackSerializers(serializers.ModelSerializer):
|
||||
|
|
@ -190,24 +225,22 @@ class EmployeeBackSerializers(serializers.ModelSerializer):
|
|||
establishment = serializers.SerializerMethodField()
|
||||
awards = AwardSerializer(many=True, read_only=True)
|
||||
|
||||
|
||||
def get_public_mark(self, obj):
|
||||
"""Get last list actual public_mark"""
|
||||
qs = obj.establishmentemployee_set.actual().order_by('-from_date')\
|
||||
qs = obj.establishmentemployee_set.actual().order_by('-from_date') \
|
||||
.values('establishment__public_mark').first()
|
||||
return qs['establishment__public_mark'] if qs else None
|
||||
|
||||
|
||||
def get_positions(self, obj):
|
||||
"""Get last list actual positions"""
|
||||
est_id = obj.establishmentemployee_set.actual().\
|
||||
est_id = obj.establishmentemployee_set.actual(). \
|
||||
order_by('-from_date').first()
|
||||
|
||||
if not est_id:
|
||||
return None
|
||||
|
||||
qs = obj.establishmentemployee_set.actual()\
|
||||
.filter(establishment_id=est_id.establishment_id)\
|
||||
qs = obj.establishmentemployee_set.actual() \
|
||||
.filter(establishment_id=est_id.establishment_id) \
|
||||
.prefetch_related('position').values('position')
|
||||
|
||||
positions = models.Position.objects.filter(id__in=[q['position'] for q in qs])
|
||||
|
|
@ -216,7 +249,7 @@ class EmployeeBackSerializers(serializers.ModelSerializer):
|
|||
|
||||
def get_establishment(self, obj):
|
||||
"""Get last actual establishment"""
|
||||
est = obj.establishmentemployee_set.actual().order_by('-from_date')\
|
||||
est = obj.establishmentemployee_set.actual().order_by('-from_date') \
|
||||
.first()
|
||||
|
||||
if not est:
|
||||
|
|
@ -380,6 +413,7 @@ class EstablishmentNoteListCreateSerializer(EstablishmentNoteBaseSerializer):
|
|||
|
||||
class EstablishmentAdminListSerializer(UserShortSerializer):
|
||||
"""Establishment admin serializer."""
|
||||
|
||||
class Meta:
|
||||
model = UserShortSerializer.Meta.model
|
||||
fields = [
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ from comment.serializers import common as comment_serializers
|
|||
from establishment import models
|
||||
from location.serializers import AddressBaseSerializer, CitySerializer, AddressDetailSerializer, \
|
||||
CityShortSerializer
|
||||
from location.serializers import EstablishmentWineRegionBaseSerializer, \
|
||||
EstablishmentWineOriginBaseSerializer
|
||||
from main.serializers import AwardSerializer, CurrencySerializer
|
||||
from review.serializers import ReviewShortSerializer
|
||||
from tag.serializers import TagBaseSerializer
|
||||
|
|
@ -16,8 +18,6 @@ from utils import exceptions as utils_exceptions
|
|||
from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer
|
||||
from utils.serializers import (ProjectModelSerializer, TranslatedField,
|
||||
FavoritesCreateSerializer)
|
||||
from location.serializers import EstablishmentWineRegionBaseSerializer, \
|
||||
EstablishmentWineOriginBaseSerializer
|
||||
|
||||
|
||||
class ContactPhonesSerializer(serializers.ModelSerializer):
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from configuration.models import TranslationSettings
|
|||
from location.models import Country
|
||||
from main import methods
|
||||
from review.models import Review
|
||||
from tag.models import Tag
|
||||
from utils.exceptions import UnprocessableEntityError
|
||||
from utils.methods import dictfetchall
|
||||
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
|
||||
|
|
@ -118,6 +119,8 @@ class Feature(ProjectBaseMixin, PlatformMixin):
|
|||
site_settings = models.ManyToManyField(SiteSettings, through='SiteFeature')
|
||||
old_id = models.IntegerField(null=True, blank=True)
|
||||
|
||||
chosen_tags = generic.GenericRelation(to='tag.ChosenTag')
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
verbose_name = _('Feature')
|
||||
|
|
@ -126,6 +129,10 @@ class Feature(ProjectBaseMixin, PlatformMixin):
|
|||
def __str__(self):
|
||||
return f'{self.slug}'
|
||||
|
||||
@property
|
||||
def get_chosen_tags(self):
|
||||
return Tag.objects.filter(chosen_tags__in=self.chosen_tags.all()).distinct()
|
||||
|
||||
|
||||
class SiteFeatureQuerySet(models.QuerySet):
|
||||
"""Extended queryset for SiteFeature model."""
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from account.models import User
|
|||
from account.serializers.back import BackUserSerializer
|
||||
from location.serializers import CountrySerializer
|
||||
from main import models
|
||||
from tag.serializers import TagBackOfficeSerializer
|
||||
from utils.serializers import ProjectModelSerializer, TranslatedField, RecursiveFieldSerializer
|
||||
|
||||
|
||||
|
|
@ -90,6 +91,8 @@ class SiteFeatureSerializer(serializers.ModelSerializer):
|
|||
route = serializers.CharField(source='feature.route.name', allow_null=True)
|
||||
source = serializers.IntegerField(source='feature.source', allow_null=True)
|
||||
nested = RecursiveFieldSerializer(many=True, read_only=True, allow_null=True)
|
||||
chosen_tags = TagBackOfficeSerializer(
|
||||
source='feature.get_chosen_tags', many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -102,6 +105,7 @@ class SiteFeatureSerializer(serializers.ModelSerializer):
|
|||
'route',
|
||||
'source',
|
||||
'nested',
|
||||
'chosen_tags',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
68
apps/news/management/commands/news_optimize_images.py
Normal file
68
apps/news/management/commands/news_optimize_images.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# coding=utf-8
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from utils.methods import get_url_images_in_text, get_image_meta_by_url
|
||||
from news.models import News
|
||||
from sorl.thumbnail import get_thumbnail
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
IMAGE_MAX_SIZE_IN_BYTES = 1048576 # ~ 1mb
|
||||
IMAGE_QUALITY_PERCENTS = 50
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'-s',
|
||||
'--size',
|
||||
default=self.IMAGE_MAX_SIZE_IN_BYTES,
|
||||
help='Максимальный размер файла в байтах',
|
||||
type=int
|
||||
)
|
||||
parser.add_argument(
|
||||
'-q',
|
||||
'--quality',
|
||||
default=self.IMAGE_QUALITY_PERCENTS,
|
||||
help='Качество изображения',
|
||||
type=int
|
||||
)
|
||||
|
||||
def optimize(self, text, max_size, max_quality):
|
||||
"""optimize news images"""
|
||||
for image in get_url_images_in_text(text):
|
||||
try:
|
||||
size, width, height = get_image_meta_by_url(image)
|
||||
except IOError as ie:
|
||||
self.stdout.write(self.style.NOTICE(f'{ie}\n'))
|
||||
continue
|
||||
|
||||
if size < max_size:
|
||||
self.stdout.write(self.style.SUCCESS(f'No need to compress images size is {size / (2**20)}Mb\n'))
|
||||
continue
|
||||
|
||||
percents = round(max_size / (size * 0.01))
|
||||
width = round(width * percents / 100)
|
||||
height = round(height * percents / 100)
|
||||
optimized_image = get_thumbnail(
|
||||
file_=image,
|
||||
geometry_string=f'{width}x{height}',
|
||||
upscale=False,
|
||||
quality=max_quality
|
||||
).url
|
||||
text = text.replace(image, optimized_image)
|
||||
self.stdout.write(self.style.SUCCESS(f'Optimized {image} -> {optimized_image}\n'
|
||||
f'Quality [{percents}%]\n'))
|
||||
|
||||
return text
|
||||
|
||||
def handle(self, *args, **options):
|
||||
size = options['size']
|
||||
quality = options['quality']
|
||||
|
||||
for news in News.objects.all():
|
||||
if not isinstance(news.description, dict):
|
||||
continue
|
||||
news.description = {
|
||||
locale: self.optimize(text, size, quality)
|
||||
for locale, text in news.description.items()
|
||||
}
|
||||
news.save()
|
||||
|
|
@ -54,7 +54,6 @@ class NewsType(models.Model):
|
|||
name = models.CharField(_('name'), max_length=250)
|
||||
tag_categories = models.ManyToManyField('tag.TagCategory',
|
||||
related_name='news_types')
|
||||
chosen_tags = generic.GenericRelation(to='tag.ChosenTag')
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
|
|||
|
|
@ -38,6 +38,13 @@ class ProductType(TypeDefaultImageMixin, TranslatedFieldsMixin, ProjectBaseMixin
|
|||
(SOUVENIR, 'souvenir'),
|
||||
(BOOK, 'book')
|
||||
)
|
||||
|
||||
INDEX_PLURAL_ONE = {
|
||||
'food': 'food',
|
||||
'wines': 'wine',
|
||||
'liquors': 'liquor',
|
||||
}
|
||||
|
||||
name = TJSONField(blank=True, null=True, default=None,
|
||||
verbose_name=_('Name'), help_text='{"en-GB":"some text"}')
|
||||
index_name = models.CharField(max_length=50, unique=True, db_index=True,
|
||||
|
|
|
|||
|
|
@ -19,10 +19,13 @@ urlpatterns = [
|
|||
|
||||
# similar products by type/subtype
|
||||
# temporary uses single mechanism, bec. description in process
|
||||
path('slug/<slug:slug>/similar/wines/', views.SimilarListView.as_view(),
|
||||
name='similar-wine'),
|
||||
path('slug/<slug:slug>/similar/liquors/', views.SimilarListView.as_view(),
|
||||
name='similar-liquor'),
|
||||
path('slug/<slug:slug>/similar/food/', views.SimilarListView.as_view(),
|
||||
name='similar-food'),
|
||||
# path('slug/<slug:slug>/similar/wines/', views.SimilarListView.as_view(),
|
||||
# name='similar-wine'),
|
||||
# path('slug/<slug:slug>/similar/liquors/', views.SimilarListView.as_view(),
|
||||
# name='similar-liquor'),
|
||||
# path('slug/<slug:slug>/similar/food/', views.SimilarListView.as_view(),
|
||||
# name='similar-food'),
|
||||
|
||||
path('slug/<slug:slug>/similar/<str:type>/', views.SimilarListView.as_view(),
|
||||
name='similar-products')
|
||||
]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from rest_framework import generics, permissions
|
|||
from comment.models import Comment
|
||||
from comment.serializers import CommentRUDSerializer
|
||||
from product import filters, serializers
|
||||
from product.models import Product
|
||||
from product.models import Product, ProductType
|
||||
from utils.views import FavoritesCreateDestroyMixinView
|
||||
from utils.pagination import PortionPagination
|
||||
from django.conf import settings
|
||||
|
|
@ -44,8 +44,16 @@ class ProductSimilarView(ProductListView):
|
|||
"""
|
||||
Return base product instance for a getting list of similar products.
|
||||
"""
|
||||
product = get_object_or_404(Product.objects.all(),
|
||||
slug=self.kwargs.get('slug'))
|
||||
find_by = {
|
||||
'slug': self.kwargs.get('slug'),
|
||||
}
|
||||
|
||||
if isinstance(self.kwargs.get('type'), str):
|
||||
if not self.kwargs.get('type') in ProductType.INDEX_PLURAL_ONE:
|
||||
return None
|
||||
find_by['product_type'] = get_object_or_404(ProductType.objects.all(), index_name=ProductType.INDEX_PLURAL_ONE[self.kwargs.get('type')])
|
||||
|
||||
product = get_object_or_404(Product.objects.all(), **find_by)
|
||||
return product
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from tag import models
|
|||
from utils.exceptions import BindingObjectNotFound, ObjectAlreadyAdded, RemovedBindingObjectNotFound
|
||||
from utils.serializers import TranslatedField
|
||||
from utils.models import get_default_locale, get_language, to_locale
|
||||
from main.models import Feature
|
||||
|
||||
|
||||
def translate_obj(obj):
|
||||
|
|
@ -309,48 +310,25 @@ class ChosenTagSerializer(serializers.ModelSerializer):
|
|||
class ChosenTagBindObjectSerializer(serializers.Serializer):
|
||||
"""Serializer for binding chosen tag and objects"""
|
||||
|
||||
ESTABLISHMENT_TYPE = 'establishment_type'
|
||||
NEWS_TYPE = 'news_type'
|
||||
|
||||
TYPE_CHOICES = (
|
||||
(ESTABLISHMENT_TYPE, 'Establishment type'),
|
||||
(NEWS_TYPE, 'News type'),
|
||||
)
|
||||
|
||||
type = serializers.ChoiceField(TYPE_CHOICES)
|
||||
object_id = serializers.IntegerField()
|
||||
feature_id = serializers.IntegerField()
|
||||
|
||||
def validate(self, attrs):
|
||||
view = self.context.get('view')
|
||||
request = self.context.get('request')
|
||||
|
||||
obj_type = attrs.get('type')
|
||||
obj_id = attrs.get('object_id')
|
||||
obj_id = attrs.get('feature_id')
|
||||
|
||||
tag = view.get_object()
|
||||
attrs['tag'] = tag
|
||||
|
||||
if obj_type == self.ESTABLISHMENT_TYPE:
|
||||
establishment_type = EstablishmentType.objects.filter(pk=obj_id). \
|
||||
first()
|
||||
if not establishment_type:
|
||||
raise BindingObjectNotFound()
|
||||
if request.method == 'DELETE' and not establishment_type. \
|
||||
chosen_tags.filter(tag=tag). \
|
||||
exists():
|
||||
raise RemovedBindingObjectNotFound()
|
||||
attrs['related_object'] = establishment_type
|
||||
|
||||
elif obj_type == self.NEWS_TYPE:
|
||||
news_type = NewsType.objects.filter(pk=obj_id).first()
|
||||
if not news_type:
|
||||
raise BindingObjectNotFound()
|
||||
if request.method == 'POST' and news_type.chosen_tags. \
|
||||
filter(tag=tag).exists():
|
||||
raise ObjectAlreadyAdded()
|
||||
if request.method == 'DELETE' and not news_type.chosen_tags. \
|
||||
filter(tag=tag).exists():
|
||||
raise RemovedBindingObjectNotFound()
|
||||
attrs['related_object'] = news_type
|
||||
feature = Feature.objects.filter(pk=obj_id). \
|
||||
first()
|
||||
if not feature:
|
||||
raise BindingObjectNotFound()
|
||||
if request.method == 'DELETE' and not feature. \
|
||||
chosen_tags.filter(tag=tag). \
|
||||
exists():
|
||||
raise RemovedBindingObjectNotFound()
|
||||
attrs['related_object'] = feature
|
||||
|
||||
return attrs
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import random
|
|||
import re
|
||||
import string
|
||||
from collections import namedtuple
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
|
|
@ -119,6 +122,7 @@ def absolute_url_decorator(func):
|
|||
return f'{settings.MEDIA_URL}{url_path}/'
|
||||
else:
|
||||
return url_path
|
||||
|
||||
return get_absolute_image_url
|
||||
|
||||
|
||||
|
|
@ -169,3 +173,16 @@ def section_name_into_index_name(section_name: str):
|
|||
result = re.findall(re_exp, section_name)
|
||||
if result:
|
||||
return f"{' '.join([word.capitalize() if i == 0 else word for i, word in enumerate(result[:-2])])}"
|
||||
|
||||
|
||||
def get_url_images_in_text(text):
|
||||
"""Find images urls in text"""
|
||||
return re.findall(r'(?:http:|https:)?//.*\.(?:png|jpg|svg)', text)
|
||||
|
||||
|
||||
def get_image_meta_by_url(url) -> (int, int, int):
|
||||
"""Returns image size (bytes, width, height)"""
|
||||
image_raw = requests.get(url)
|
||||
image = Image.open(BytesIO(image_raw.content))
|
||||
width, height = image.size
|
||||
return int(image_raw.headers.get('content-length')), width, height
|
||||
|
|
@ -5,14 +5,13 @@ from sorl.thumbnail.engines.pil_engine import Engine as PILEngine
|
|||
class GMEngine(PILEngine):
|
||||
|
||||
def create(self, image, geometry, options):
|
||||
"""
|
||||
Processing conductor, returns the thumbnail as an image engine instance
|
||||
"""
|
||||
image = self.cropbox(image, geometry, options)
|
||||
image = self.orientation(image, geometry, options)
|
||||
image = self.colorspace(image, geometry, options)
|
||||
image = self.remove_border(image, options)
|
||||
image = self.scale(image, geometry, options)
|
||||
image = self.crop(image, geometry, options)
|
||||
image = self.scale(image, geometry, options)
|
||||
image = self.rounded(image, geometry, options)
|
||||
image = self.blur(image, geometry, options)
|
||||
image = self.padding(image, geometry, options)
|
||||
|
|
|
|||
|
|
@ -27,4 +27,7 @@
|
|||
./manage.py transfer --overlook
|
||||
./manage.py transfer --inquiries
|
||||
./manage.py transfer --product_review
|
||||
./manage.py transfer --transfer_text_review
|
||||
./manage.py transfer --transfer_text_review
|
||||
|
||||
# оптимизация изображений
|
||||
/manage.py news_optimize_images # сжимает картинки в описаниях новостей
|
||||
|
|
@ -385,6 +385,7 @@ THUMBNAIL_QUALITY = 85
|
|||
THUMBNAIL_DEBUG = False
|
||||
SORL_THUMBNAIL_ALIASES = {
|
||||
'news_preview': {'geometry_string': '300x260', 'crop': 'center'},
|
||||
'news_description': {'geometry_string': '100x100'},
|
||||
'news_promo_horizontal_web': {'geometry_string': '1900x600', 'crop': 'center'},
|
||||
'news_promo_horizontal_mobile': {'geometry_string': '375x260', 'crop': 'center'},
|
||||
'news_tile_horizontal_web': {'geometry_string': '300x275', 'crop': 'center'},
|
||||
|
|
@ -411,6 +412,8 @@ SORL_THUMBNAIL_ALIASES = {
|
|||
'city_detail': {'geometry_string': '1120x1120', 'crop': 'center'},
|
||||
'city_original': {'geometry_string': '2048x1536', 'crop': 'center'},
|
||||
'type_preview': {'geometry_string': '300x260', 'crop': 'center'},
|
||||
'collection_image': {'geometry_string': '940x620', 'upscale': False, 'quality': 100},
|
||||
'establishment_collection_image': {'geometry_string': '940x620', 'upscale': False, 'quality': 100}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user