Merge branch 'develop' into features/migrate-wine
# Conflicts: # apps/product/models.py # apps/transfer/management/commands/transfer.py # apps/transfer/models.py
This commit is contained in:
commit
d46ba31654
|
|
@ -113,7 +113,7 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin):
|
||||||
|
|
||||||
# Check OAuth2 response
|
# Check OAuth2 response
|
||||||
if oauth2_status != status.HTTP_200_OK:
|
if oauth2_status != status.HTTP_200_OK:
|
||||||
raise utils_exceptions.OAuth2Error()
|
raise utils_exceptions.OAuth2Error(detail=body)
|
||||||
|
|
||||||
# Get authenticated user
|
# Get authenticated user
|
||||||
user = User.objects.by_oauth2_access_token(token=body.get('access_token'))\
|
user = User.objects.by_oauth2_access_token(token=body.get('access_token'))\
|
||||||
|
|
|
||||||
23
apps/booking/migrations/0003_auto_20191025_1613.py
Normal file
23
apps/booking/migrations/0003_auto_20191025_1613.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-25 16:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('booking', '0002_auto_20191003_1601'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='booking',
|
||||||
|
name='amount',
|
||||||
|
field=models.CharField(default=None, max_length=30, null=True, verbose_name='prepayment price'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='booking',
|
||||||
|
name='stripe_key',
|
||||||
|
field=models.TextField(default=None, null=True, verbose_name='stripe service payment key'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/booking/migrations/0004_booking_stripe_token.py
Normal file
18
apps/booking/migrations/0004_booking_stripe_token.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-25 16:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('booking', '0003_auto_20191025_1613'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='booking',
|
||||||
|
name='stripe_token',
|
||||||
|
field=models.TextField(default=None, null=True, verbose_name='stripe service pre-payed booking token'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -24,6 +24,9 @@ class Booking(ProjectBaseMixin):
|
||||||
pending_booking_id = models.TextField(verbose_name=_('external service pending booking'), default=None)
|
pending_booking_id = models.TextField(verbose_name=_('external service pending booking'), default=None)
|
||||||
booking_id = models.TextField(verbose_name=_('external service booking id'), default=None, null=True,
|
booking_id = models.TextField(verbose_name=_('external service booking id'), default=None, null=True,
|
||||||
db_index=True, )
|
db_index=True, )
|
||||||
|
stripe_key = models.TextField(null=True, default=None, verbose_name=_('stripe service payment key'))
|
||||||
|
stripe_token = models.TextField(null=True, default=None, verbose_name=_('stripe service pre-payed booking token'))
|
||||||
|
amount = models.CharField(null=True, default=None, verbose_name=_('prepayment price'), max_length=30)
|
||||||
user = models.ForeignKey(
|
user = models.ForeignKey(
|
||||||
'account.User', verbose_name=_('booking owner'), null=True,
|
'account.User', verbose_name=_('booking owner'), null=True,
|
||||||
related_name='bookings',
|
related_name='bookings',
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
import json
|
import json
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from rest_framework import status
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from rest_framework import serializers, status
|
||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
import booking.models.models as models
|
import booking.models.models as models
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractBookingService(ABC):
|
class AbstractBookingService(ABC):
|
||||||
|
|
@ -24,8 +27,14 @@ class AbstractBookingService(ABC):
|
||||||
self.url = settings.LASTABLE_SERVICE
|
self.url = settings.LASTABLE_SERVICE
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_certain_keys(d: dict, keys_to_preserve: set) -> dict:
|
def get_certain_keys(d: dict, keys_to_preserve: set, required: set = {}, check: bool = True) -> dict:
|
||||||
""" Helper """
|
""" Helper """
|
||||||
|
if len(required) == 0 and check:
|
||||||
|
required = keys_to_preserve.copy()
|
||||||
|
if required and check:
|
||||||
|
diff = required - d.keys()
|
||||||
|
if diff:
|
||||||
|
raise serializers.ValidationError({field: _(f'This field is required') for field in diff})
|
||||||
return {key: d[key] for key in d.keys() & keys_to_preserve}
|
return {key: d[key] for key in d.keys() & keys_to_preserve}
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
@ -66,21 +75,21 @@ class GuestonlineService(AbstractBookingService):
|
||||||
def get_common_headers(self):
|
def get_common_headers(self):
|
||||||
return {'X-Token': self.token, 'Content-type': 'application/json', 'Accept': 'application/json'}
|
return {'X-Token': self.token, 'Content-type': 'application/json', 'Accept': 'application/json'}
|
||||||
|
|
||||||
def check_whether_booking_available(self, restaurant_id, date: str):
|
def check_whether_booking_available(self, restaurant_id, *args, **kwargs):
|
||||||
super().check_whether_booking_available(restaurant_id, date)
|
url = f'{self.url}v1/periods'
|
||||||
url = f'{self.url}v1/runtime_services'
|
params = {'restaurant_id': restaurant_id, **kwargs}
|
||||||
params = {'restaurant_id': restaurant_id, 'date': date, 'expands[]': 'table_availabilities'}
|
|
||||||
r = requests.get(url, headers=self.get_common_headers(), params=params)
|
r = requests.get(url, headers=self.get_common_headers(), params=params)
|
||||||
if not status.is_success(r.status_code):
|
if not status.is_success(r.status_code):
|
||||||
return False
|
return False
|
||||||
response = json.loads(r.content)['runtime_services']
|
self.response = r.json()
|
||||||
keys_to_preserve = {'left_seats', 'table_availabilities', 'closed', 'start_time', 'end_time', 'last_booking'}
|
|
||||||
response = map(lambda x: self.get_certain_keys(x, keys_to_preserve), response)
|
|
||||||
self.response = response
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def commit_booking(self, payload):
|
def commit_booking(self, payload, stripe_token = None):
|
||||||
url = f'{self.url}v1/pending_bookings/{payload}/commit'
|
url = f'{self.url}v1/pending_bookings/{payload}/commit'
|
||||||
|
if stripe_token:
|
||||||
|
r = requests.put(url, headers=self.get_common_headers(),
|
||||||
|
data=json.dumps({'stripe_token': stripe_token}))
|
||||||
|
else:
|
||||||
r = requests.put(url, headers=self.get_common_headers())
|
r = requests.put(url, headers=self.get_common_headers())
|
||||||
self.response = json.loads(r.content)
|
self.response = json.loads(r.content)
|
||||||
if status.is_success(r.status_code) and self.response is None:
|
if status.is_success(r.status_code) and self.response is None:
|
||||||
|
|
@ -93,8 +102,13 @@ class GuestonlineService(AbstractBookingService):
|
||||||
payload['lastname'] = payload.pop('last_name')
|
payload['lastname'] = payload.pop('last_name')
|
||||||
payload['firstname'] = payload.pop('first_name')
|
payload['firstname'] = payload.pop('first_name')
|
||||||
payload['mobile_phone'] = payload.pop('phone')
|
payload['mobile_phone'] = payload.pop('phone')
|
||||||
|
payload['user_locale'] = payload.pop('country_code')
|
||||||
headers = self.get_common_headers()
|
headers = self.get_common_headers()
|
||||||
r = requests.put(url, headers=headers, data=json.dumps({'contact_info': payload}))
|
r = requests.put(url, headers=headers, data=json.dumps({'contact_info': payload}))
|
||||||
|
response = r.json()
|
||||||
|
self.response = response.get('prepayment')
|
||||||
|
if not status.is_success(r.status_code):
|
||||||
|
return Response(status=r.status_code, data=response)
|
||||||
return status.is_success(r.status_code)
|
return status.is_success(r.status_code)
|
||||||
|
|
||||||
def create_booking(self, payload):
|
def create_booking(self, payload):
|
||||||
|
|
@ -103,7 +117,10 @@ class GuestonlineService(AbstractBookingService):
|
||||||
payload['persons'] = payload.pop('booked_persons_number')
|
payload['persons'] = payload.pop('booked_persons_number')
|
||||||
payload['date'] = payload.pop('booking_date')
|
payload['date'] = payload.pop('booking_date')
|
||||||
r = requests.post(url, headers=self.get_common_headers(), data=json.dumps(payload))
|
r = requests.post(url, headers=self.get_common_headers(), data=json.dumps(payload))
|
||||||
return json.loads(r.content)['id'] if status.is_success(r.status_code) else False
|
if status.is_success(r.status_code):
|
||||||
|
return json.loads(r.content)['id']
|
||||||
|
else:
|
||||||
|
return Response(status=r.status_code, data=r.json())
|
||||||
|
|
||||||
def cancel_booking(self, payload):
|
def cancel_booking(self, payload):
|
||||||
url = f'{self.url}v1/pending_bookings/{payload}'
|
url = f'{self.url}v1/pending_bookings/{payload}'
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,29 @@ class PendingBookingSerializer(serializers.ModelSerializer):
|
||||||
'user',
|
'user',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class CommitBookingSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Booking
|
||||||
|
fields = (
|
||||||
|
'stripe_token',
|
||||||
|
)
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
"""Override update method"""
|
||||||
|
# Update user password from instance
|
||||||
|
service = instance.get_service_by_type(instance.type)
|
||||||
|
service.commit_booking(instance.pending_booking_id, validated_data.get('stripe_token'))
|
||||||
|
instance.stripe_token = validated_data.get('stripe_token')
|
||||||
|
instance.save()
|
||||||
|
return instance
|
||||||
|
|
||||||
class UpdateBookingSerializer(serializers.ModelSerializer):
|
class UpdateBookingSerializer(serializers.ModelSerializer):
|
||||||
id = serializers.ReadOnlyField()
|
id = serializers.ReadOnlyField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Booking
|
model = models.Booking
|
||||||
fields = ('booking_id', 'id')
|
fields = ('booking_id', 'id', 'stripe_key', 'amount')
|
||||||
|
|
||||||
|
|
||||||
class GetBookingSerializer(serializers.ModelSerializer):
|
class GetBookingSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ urlpatterns = [
|
||||||
path('<int:establishment_id>/check/', views.CheckWhetherBookingAvailable.as_view(), name='booking-check'),
|
path('<int:establishment_id>/check/', views.CheckWhetherBookingAvailable.as_view(), name='booking-check'),
|
||||||
path('<int:establishment_id>/create/', views.CreatePendingBooking.as_view(), name='create-pending-booking'),
|
path('<int:establishment_id>/create/', views.CreatePendingBooking.as_view(), name='create-pending-booking'),
|
||||||
path('<int:pk>/', views.UpdatePendingBooking.as_view(), name='update-pending-booking'),
|
path('<int:pk>/', views.UpdatePendingBooking.as_view(), name='update-pending-booking'),
|
||||||
|
path('<int:pk>/commit/', views.CommitPendingBooking.as_view(), name='update-pending-booking'),
|
||||||
path('<int:pk>/cancel/', views.CancelBooking.as_view(), name='cancel-existing-booking'),
|
path('<int:pk>/cancel/', views.CancelBooking.as_view(), name='cancel-existing-booking'),
|
||||||
path('last/', views.LastBooking.as_view(), name='last_booking-for-authorizer-user'),
|
path('last/', views.LastBooking.as_view(), name='last_booking-for-authorizer-user'),
|
||||||
path('retrieve/<int:pk>/', views.GetBookingById.as_view(), name='retrieves-booking-by-id'),
|
path('retrieve/<int:pk>/', views.GetBookingById.as_view(), name='retrieves-booking-by-id'),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
from rest_framework import generics, permissions, status, serializers
|
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from establishment.models import Establishment
|
from rest_framework import generics, permissions, status, serializers
|
||||||
from booking.models.models import Booking, GuestonlineService, LastableService
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from booking.serializers.web import (PendingBookingSerializer,
|
|
||||||
UpdateBookingSerializer, GetBookingSerializer, CheckBookingSerializer)
|
from booking.models.models import Booking, GuestonlineService, LastableService
|
||||||
|
from booking.serializers.web import (PendingBookingSerializer, UpdateBookingSerializer, GetBookingSerializer,
|
||||||
|
CheckBookingSerializer, CommitBookingSerializer)
|
||||||
|
from establishment.models import Establishment
|
||||||
|
from notification.models import Subscriber
|
||||||
|
from utils.methods import get_user_ip
|
||||||
|
|
||||||
|
|
||||||
class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
||||||
|
|
@ -28,7 +30,9 @@ class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
||||||
service = l_service
|
service = l_service
|
||||||
service.service_id = establishment.lastable_id
|
service.service_id = establishment.lastable_id
|
||||||
elif (not establishment.guestonline_id is None) and g_service \
|
elif (not establishment.guestonline_id is None) and g_service \
|
||||||
.check_whether_booking_available(establishment.guestonline_id, date):
|
.check_whether_booking_available(establishment.guestonline_id,
|
||||||
|
**g_service.get_certain_keys(request.query_params,
|
||||||
|
{'date', 'persons'})):
|
||||||
is_booking_available = True
|
is_booking_available = True
|
||||||
service = g_service
|
service = g_service
|
||||||
service.service_id = establishment.guestonline_id
|
service.service_id = establishment.guestonline_id
|
||||||
|
|
@ -61,7 +65,9 @@ class CreatePendingBooking(generics.CreateAPIView):
|
||||||
}
|
}
|
||||||
data['pending_booking_id'] = service.create_booking(
|
data['pending_booking_id'] = service.create_booking(
|
||||||
service.get_certain_keys(data.copy(), service_to_keys[data.get('type')]))
|
service.get_certain_keys(data.copy(), service_to_keys[data.get('type')]))
|
||||||
if not data['pending_booking_id']:
|
if isinstance(data['pending_booking_id'], Response):
|
||||||
|
return data['pending_booking_id']
|
||||||
|
elif not data['pending_booking_id']:
|
||||||
return Response(status=status.HTTP_403_FORBIDDEN, data='Unable to create booking')
|
return Response(status=status.HTTP_403_FORBIDDEN, data='Unable to create booking')
|
||||||
data['booking_id'] = data['pending_booking_id'] if data.get('type') == Booking.LASTABLE else None
|
data['booking_id'] = data['pending_booking_id'] if data.get('type') == Booking.LASTABLE else None
|
||||||
serializer = self.get_serializer(data=data)
|
serializer = self.get_serializer(data=data)
|
||||||
|
|
@ -70,6 +76,13 @@ class CreatePendingBooking(generics.CreateAPIView):
|
||||||
return Response(status=status.HTTP_201_CREATED, data=serializer.data)
|
return Response(status=status.HTTP_201_CREATED, data=serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
class CommitPendingBooking(generics.UpdateAPIView):
|
||||||
|
""" Commit pending booking """
|
||||||
|
queryset = Booking.objects.all()
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
serializer_class = CommitBookingSerializer
|
||||||
|
|
||||||
|
|
||||||
class UpdatePendingBooking(generics.UpdateAPIView):
|
class UpdatePendingBooking(generics.UpdateAPIView):
|
||||||
""" Update pending booking with contacts """
|
""" Update pending booking with contacts """
|
||||||
queryset = Booking.objects.all()
|
queryset = Booking.objects.all()
|
||||||
|
|
@ -81,9 +94,31 @@ class UpdatePendingBooking(generics.UpdateAPIView):
|
||||||
data = request.data.copy()
|
data = request.data.copy()
|
||||||
service = Booking.get_service_by_type(instance.type)
|
service = Booking.get_service_by_type(instance.type)
|
||||||
data['pending_booking_id'] = instance.pending_booking_id
|
data['pending_booking_id'] = instance.pending_booking_id
|
||||||
service.update_booking(service.get_certain_keys(data, {
|
r = service.update_booking(service.get_certain_keys(data, {
|
||||||
|
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id', 'note',
|
||||||
|
}, {
|
||||||
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id',
|
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id',
|
||||||
}))
|
}))
|
||||||
|
if isinstance(r, Response):
|
||||||
|
return r
|
||||||
|
if data.get('newsletter'):
|
||||||
|
Subscriber.objects.make_subscriber(email=data['email'], country_code=data['country_code'],
|
||||||
|
locale=request.locale, ip_address=get_user_ip(request),
|
||||||
|
user=None if request.user.is_anonymous else request.user)
|
||||||
|
if service.response:
|
||||||
|
# если есть предоплата, возвращаем фронту страйп-ключ для совершения оплаты и цену
|
||||||
|
amount = service.response.get('amount')
|
||||||
|
stripe_key = service.response.get('stripe_key')
|
||||||
|
data = {
|
||||||
|
'id': instance.pk,
|
||||||
|
'amount': amount,
|
||||||
|
'stripe_key': stripe_key,
|
||||||
|
'type': instance.type,
|
||||||
|
}
|
||||||
|
serializer = self.get_serializer(data=data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
serializer.update(instance, data)
|
||||||
|
return Response(status=status.HTTP_200_OK, data=data)
|
||||||
service.commit_booking(data['pending_booking_id'])
|
service.commit_booking(data['pending_booking_id'])
|
||||||
data = {
|
data = {
|
||||||
'booking_id': service.response.get('id'),
|
'booking_id': service.response.get('id'),
|
||||||
|
|
|
||||||
0
apps/collection/management/__init__.py
Normal file
0
apps/collection/management/__init__.py
Normal file
0
apps/collection/management/commands/__init__.py
Normal file
0
apps/collection/management/commands/__init__.py
Normal file
169
apps/collection/management/commands/import_collection.py
Normal file
169
apps/collection/management/commands/import_collection.py
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from establishment.models import Establishment
|
||||||
|
from location.models import Country, Language
|
||||||
|
from transfer.models import Collections
|
||||||
|
from collection.models import Collection
|
||||||
|
from news.models import News
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Import collection'
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
raw_qs = Collections.objects.raw('''
|
||||||
|
select
|
||||||
|
distinct
|
||||||
|
a.id,
|
||||||
|
a.collection_id,
|
||||||
|
-- a.establishment_id,
|
||||||
|
a.title,
|
||||||
|
a.tag_name,
|
||||||
|
a.slug,
|
||||||
|
-- a.attachment_file_name,
|
||||||
|
-- a.attachment_content_type,
|
||||||
|
-- a.attachment_file_size,
|
||||||
|
a.attachment_suffix_url,
|
||||||
|
-- active as is_publish,
|
||||||
|
a.country_code,
|
||||||
|
-- a.geometries,
|
||||||
|
a.description,
|
||||||
|
min(a.start) AS start
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select distinct
|
||||||
|
c.id,
|
||||||
|
c.id as collection_id,
|
||||||
|
m.establishment_id,
|
||||||
|
c.title, c.tag_name,
|
||||||
|
c.slug, c.attachment_file_name,
|
||||||
|
c.attachment_content_type, c.attachment_file_size,
|
||||||
|
c.attachment_suffix_url,
|
||||||
|
active,
|
||||||
|
s.country_code_2 as country_code,
|
||||||
|
c.geometries,
|
||||||
|
c.title as description,
|
||||||
|
m.created_at as start
|
||||||
|
from collections as c
|
||||||
|
join metadata m on m.value = c.tag_name
|
||||||
|
join establishments e on e.id = m.establishment_id
|
||||||
|
join sites s on s.id = c.site_id
|
||||||
|
where m.`key` = 'collection'
|
||||||
|
|
||||||
|
union
|
||||||
|
|
||||||
|
select distinct
|
||||||
|
c.id,
|
||||||
|
c.id as collection_id,
|
||||||
|
m.establishment_id,
|
||||||
|
c.title, c.tag_name,
|
||||||
|
c.slug, c.attachment_file_name,
|
||||||
|
c.attachment_content_type, c.attachment_file_size,
|
||||||
|
c.attachment_suffix_url,
|
||||||
|
active,
|
||||||
|
s.country_code_2 as country_code,
|
||||||
|
c.geometries,
|
||||||
|
c.title as description,
|
||||||
|
m.created_at as start
|
||||||
|
from collections as c
|
||||||
|
join metadata m on m.value = c.slug
|
||||||
|
join establishments e on e.id = m.establishment_id
|
||||||
|
join sites s on s.id = c.site_id
|
||||||
|
where m.`key` = 'collection'
|
||||||
|
) a
|
||||||
|
group by
|
||||||
|
a.id,
|
||||||
|
a.collection_id,
|
||||||
|
-- a.establishment_id,
|
||||||
|
a.title,
|
||||||
|
a.tag_name,
|
||||||
|
a.slug,
|
||||||
|
-- a.attachment_file_name,
|
||||||
|
-- a.attachment_content_type,
|
||||||
|
-- a.attachment_file_size,
|
||||||
|
a.attachment_suffix_url,
|
||||||
|
-- active as is_publish,
|
||||||
|
a.country_code,
|
||||||
|
a.description
|
||||||
|
''')
|
||||||
|
objects = []
|
||||||
|
queryset = [vars(query) for query in raw_qs]
|
||||||
|
for obj in queryset:
|
||||||
|
# establishment = Establishment.objects.filter(old_id=obj['establishment_id']).first()
|
||||||
|
# lang = Language.objects.filter(locale=obj['country_code'])
|
||||||
|
country = Country.objects.filter(code=obj['country_code']).first()
|
||||||
|
if country:
|
||||||
|
objects.append(
|
||||||
|
Collection(name={"en-GB": obj['title']}, collection_type=Collection.ORDINARY,
|
||||||
|
country=country,
|
||||||
|
description=obj['description'],
|
||||||
|
slug=obj['slug'], old_id=obj['collection_id'],
|
||||||
|
start=obj['start'],
|
||||||
|
image_url='https://s3.eu-central-1.amazonaws.com/gm-test.com/media/'+obj['attachment_suffix_url']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Collection.objects.bulk_create(objects)
|
||||||
|
|
||||||
|
raw_qs = Collections.objects.raw('''
|
||||||
|
select
|
||||||
|
distinct
|
||||||
|
a.id,
|
||||||
|
a.collection_id,
|
||||||
|
a.establishment_id,
|
||||||
|
a.active
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select distinct
|
||||||
|
c.id,
|
||||||
|
c.id as collection_id,
|
||||||
|
m.establishment_id,
|
||||||
|
c.title, c.tag_name,
|
||||||
|
c.slug, c.attachment_file_name,
|
||||||
|
c.attachment_content_type, c.attachment_file_size,
|
||||||
|
c.attachment_suffix_url,
|
||||||
|
active,
|
||||||
|
s.country_code_2 as country_code,
|
||||||
|
c.geometries,
|
||||||
|
c.title as description,
|
||||||
|
m.created_at as start
|
||||||
|
from collections as c
|
||||||
|
join metadata m on m.value = c.tag_name
|
||||||
|
join establishments e on e.id = m.establishment_id
|
||||||
|
join sites s on s.id = c.site_id
|
||||||
|
where m.`key` = 'collection'
|
||||||
|
|
||||||
|
union
|
||||||
|
|
||||||
|
select distinct
|
||||||
|
c.id,
|
||||||
|
c.id as collection_id,
|
||||||
|
m.establishment_id,
|
||||||
|
c.title, c.tag_name,
|
||||||
|
c.slug, c.attachment_file_name,
|
||||||
|
c.attachment_content_type, c.attachment_file_size,
|
||||||
|
c.attachment_suffix_url,
|
||||||
|
active,
|
||||||
|
s.country_code_2 as country_code,
|
||||||
|
c.geometries,
|
||||||
|
c.title as description,
|
||||||
|
m.created_at as start
|
||||||
|
from collections as c
|
||||||
|
join metadata m on m.value = c.slug
|
||||||
|
join establishments e on e.id = m.establishment_id
|
||||||
|
join sites s on s.id = c.site_id
|
||||||
|
where m.`key` = 'collection'
|
||||||
|
) a
|
||||||
|
''')
|
||||||
|
|
||||||
|
queryset = [vars(query) for query in raw_qs]
|
||||||
|
for obj in queryset:
|
||||||
|
print('COLLECT_ID: {}'.format(obj['collection_id']))
|
||||||
|
est = Establishment.objects.filter(old_id=obj['establishment_id'])
|
||||||
|
if est.exists():
|
||||||
|
inst = est.first()
|
||||||
|
collect = Collection.objects.filter(old_id=obj['collection_id'])
|
||||||
|
collect.update(is_publish=obj['active'])
|
||||||
|
print(f'COLLECT COUNT {collect.count()}')
|
||||||
|
inst.collections.add(*list(collect))
|
||||||
|
# for c in collect:
|
||||||
|
# inst.collections.add(c)
|
||||||
|
inst.save()
|
||||||
18
apps/collection/migrations/0017_collection_old_id.py
Normal file
18
apps/collection/migrations/0017_collection_old_id.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 13:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('collection', '0016_auto_20191024_1334'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='collection',
|
||||||
|
name='old_id',
|
||||||
|
field=models.IntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -76,6 +76,7 @@ class Collection(ProjectBaseMixin, CollectionDateMixin,
|
||||||
slug = models.SlugField(max_length=50, unique=True,
|
slug = models.SlugField(max_length=50, unique=True,
|
||||||
verbose_name=_('Collection slug'), editable=True, null=True)
|
verbose_name=_('Collection slug'), editable=True, null=True)
|
||||||
|
|
||||||
|
old_id=models.IntegerField(null=True, blank=True)
|
||||||
objects = CollectionQuerySet.as_manager()
|
objects = CollectionQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
import json
|
|
||||||
import pytz
|
|
||||||
from datetime import datetime
|
|
||||||
from http.cookies import SimpleCookie
|
|
||||||
|
|
||||||
from rest_framework import status
|
|
||||||
from rest_framework.test import APITestCase
|
|
||||||
|
|
||||||
from account.models import User
|
|
||||||
from collection.models import Collection, Guide
|
|
||||||
from establishment.models import Establishment, EstablishmentType
|
|
||||||
from location.models import Country
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(APITestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.username = 'sedragurda'
|
|
||||||
self.password = 'sedragurdaredips19'
|
|
||||||
self.email = 'sedragurda@desoz.com'
|
|
||||||
self.newsletter = True
|
|
||||||
self.user = User.objects.create_user(
|
|
||||||
username=self.username, email=self.email, password=self.password)
|
|
||||||
# get tokens
|
|
||||||
tokens = User.create_jwt_tokens(self.user)
|
|
||||||
self.client.cookies = SimpleCookie(
|
|
||||||
{'access_token': tokens.get('access_token'),
|
|
||||||
'refresh_token': tokens.get('refresh_token'),
|
|
||||||
'country_code': 'en'})
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionListTests(BaseTestCase):
|
|
||||||
def test_collection_list_Read(self):
|
|
||||||
response = self.client.get('/api/web/collections/', format='json')
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionDetailTests(BaseTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
|
|
||||||
# country = Country.objects.first()
|
|
||||||
# if not country:
|
|
||||||
country = Country.objects.create(
|
|
||||||
name=json.dumps({"en-GB": "Test country"}),
|
|
||||||
code="en"
|
|
||||||
)
|
|
||||||
country.save()
|
|
||||||
|
|
||||||
self.collection = Collection.objects.create(
|
|
||||||
name='Test collection',
|
|
||||||
is_publish=True,
|
|
||||||
start=datetime.now(pytz.utc),
|
|
||||||
end=datetime.now(pytz.utc),
|
|
||||||
country=country,
|
|
||||||
slug='test-collection-slug',
|
|
||||||
)
|
|
||||||
|
|
||||||
self.collection.save()
|
|
||||||
|
|
||||||
def test_collection_detail_Read(self):
|
|
||||||
response = self.client.get(f'/api/web/collections/{self.collection.slug}/establishments/?country_code=en',
|
|
||||||
format='json')
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionGuideTests(CollectionDetailTests):
|
|
||||||
|
|
||||||
def test_guide_list_Read(self):
|
|
||||||
response = self.client.get('/api/web/collections/guides/', format='json')
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionGuideDetailTests(CollectionDetailTests):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
self.guide = Guide.objects.create(
|
|
||||||
collection=self.collection,
|
|
||||||
start=datetime.now(pytz.utc),
|
|
||||||
end=datetime.now(pytz.utc)
|
|
||||||
)
|
|
||||||
self.guide.save()
|
|
||||||
|
|
||||||
def test_guide_detail_Read(self):
|
|
||||||
response = self.client.get(f'/api/web/collections/guides/{self.guide.id}/', format='json')
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionWebHomeTests(CollectionDetailTests):
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
self.establishment_type = EstablishmentType.objects.create(name="Test establishment type")
|
|
||||||
|
|
||||||
for i in range(1, 5):
|
|
||||||
setattr(self, f"establishment{i}",
|
|
||||||
Establishment.objects.create(
|
|
||||||
name=f"Test establishment {i}",
|
|
||||||
establishment_type_id=self.establishment_type.id,
|
|
||||||
is_publish=True,
|
|
||||||
slug=f"test-establishment-{i}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
getattr(self, f"establishment{i}").collections.add(self.collection)
|
|
||||||
|
|
||||||
def test_collection_list_filter(self):
|
|
||||||
response = self.client.get('/api/web/collections/?country_code=en', format='json')
|
|
||||||
data = response.json()
|
|
||||||
self.assertIn('count', data)
|
|
||||||
self.assertGreater(data['count'], 0)
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
"""
|
|
||||||
Структура fields:
|
|
||||||
key - поле в таблице postgres
|
|
||||||
value - поле или группа полей в таблице legacy
|
|
||||||
|
|
||||||
В случае передачи группы полей каждое поле представляет собой кортеж, где:
|
|
||||||
field[0] - название аргумента
|
|
||||||
field[1] - название поля в таблице legacy
|
|
||||||
Опционально: field[2] - тип данных для преобразования
|
|
||||||
|
|
||||||
"""
|
|
||||||
card = {
|
|
||||||
"Collection": {
|
|
||||||
"data_type": "objects",
|
|
||||||
"dependencies": ("Country", ),
|
|
||||||
"fields": {
|
|
||||||
"Collections": {
|
|
||||||
# нету аналогов для полей description, start и end
|
|
||||||
"name": "title",
|
|
||||||
"slug": "slug",
|
|
||||||
"block_size": ("geometries", "django.db.models.JSONField"),
|
|
||||||
"is_publish": ("active", "django.db.models.BooleanField"),
|
|
||||||
"image_url": ("attachment_file_name", "django.db.models.URLField")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"relations": {
|
|
||||||
# "country": "Country",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Guide": {
|
|
||||||
# как работать с ForeignKey на самого себя(self), поле "parent"
|
|
||||||
"data_type": "objects",
|
|
||||||
"dependencies": ("Collection", "self"),
|
|
||||||
"fields": {
|
|
||||||
"Guides": {
|
|
||||||
# нету аналогов для полей start и end
|
|
||||||
"name": "title"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"relations": {
|
|
||||||
# аналалог для поля "collection" не найдено
|
|
||||||
# "parent": "Guide",
|
|
||||||
# "collection": "Collection"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
used_apps = ("location", )
|
|
||||||
|
|
@ -57,9 +57,10 @@ class ProductInline(admin.TabularInline):
|
||||||
class EstablishmentAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
class EstablishmentAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
||||||
"""Establishment admin."""
|
"""Establishment admin."""
|
||||||
list_display = ['id', '__str__', 'image_tag', ]
|
list_display = ['id', '__str__', 'image_tag', ]
|
||||||
inlines = [
|
|
||||||
AwardInline, ContactPhoneInline, ContactEmailInline,
|
# inlines = [
|
||||||
ReviewInline, CommentInline, ProductInline]
|
# AwardInline, ContactPhoneInline, ContactEmailInline,
|
||||||
|
# ReviewInline, CommentInline, ProductInline]
|
||||||
raw_id_fields = ('address',)
|
raw_id_fields = ('address',)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -78,6 +79,7 @@ class PlateInline(admin.TabularInline):
|
||||||
class MenuAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
class MenuAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
||||||
"""Menu admin."""
|
"""Menu admin."""
|
||||||
list_display = ['id', 'category_translated']
|
list_display = ['id', 'category_translated']
|
||||||
|
raw_id_fields = ['establishment']
|
||||||
inlines = [
|
inlines = [
|
||||||
PlateInline,
|
PlateInline,
|
||||||
]
|
]
|
||||||
|
|
@ -87,3 +89,8 @@ class MenuAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
||||||
return obj.category_translated
|
return obj.category_translated
|
||||||
|
|
||||||
category_translated.short_description = _('category')
|
category_translated.short_description = _('category')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(models.RatingStrategy)
|
||||||
|
class RatingStrategyAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
||||||
|
"""Admin conf for Rating Strategy model."""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
import requests
|
||||||
|
from establishment.models import Establishment
|
||||||
|
from main.models import Currency
|
||||||
|
from location.models import Country
|
||||||
|
from django.template.defaultfilters import slugify
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Add currency to new db'
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
url = 'https://restcountries.eu/rest/v2/name/{country}'
|
||||||
|
|
||||||
|
countries = Country.objects.all()
|
||||||
|
for country in countries:
|
||||||
|
|
||||||
|
country_name = country.name["en-GB"]
|
||||||
|
resp = requests.get(url=url.format(country=country_name))
|
||||||
|
if resp.status_code == requests.codes.ok:
|
||||||
|
country_list = resp.json()
|
||||||
|
if isinstance(country_list, list):
|
||||||
|
currency_dict = country_list[0].get("currencies")[0]
|
||||||
|
if currency_dict:
|
||||||
|
name = currency_dict['name']
|
||||||
|
if name:
|
||||||
|
slug = slugify(name)
|
||||||
|
currency, _ = Currency.objects.get_or_create(
|
||||||
|
slug=slug,
|
||||||
|
)
|
||||||
|
currency.name = {"en-GB": name}
|
||||||
|
currency.sign = currency_dict["symbol"]
|
||||||
|
currency.save()
|
||||||
|
establishments = Establishment.objects.filter(address__city__country=country)
|
||||||
|
establishments.update(currency=currency)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
self.stdout.write(self.style.WARNING(f'Created/updated {count} objects.'))
|
||||||
|
|
@ -1,31 +1,67 @@
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
from establishment.models import Establishment
|
from establishment.models import Establishment
|
||||||
from transfer.models import Descriptions
|
from transfer.models import Reviews, ReviewTexts
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Add description values from old db to new db'
|
help = 'Add description values from old db reviews to new db'
|
||||||
|
|
||||||
def handle(self, *args, **kwargs):
|
def handle(self, *args, **kwargs):
|
||||||
count = 0
|
count = 0
|
||||||
|
update_locale = 0
|
||||||
|
valid_reviews = {}
|
||||||
|
|
||||||
queryset = Descriptions.objects.all()
|
queryset = Reviews.objects.exclude(
|
||||||
for obj in queryset:
|
establishment_id__isnull=True
|
||||||
|
).filter(
|
||||||
|
aasm_state='published'
|
||||||
|
).values_list(
|
||||||
|
'id',
|
||||||
|
'establishment_id',
|
||||||
|
'updated_at',
|
||||||
|
)
|
||||||
|
|
||||||
|
for r_id, establishment_id, new_date in queryset:
|
||||||
try:
|
try:
|
||||||
establishment = Establishment.objects.get(old_id=obj.establishment.id)
|
review_id, date = valid_reviews[establishment_id]
|
||||||
except Establishment.DoesNotExist:
|
except KeyError:
|
||||||
continue
|
valid_reviews[establishment_id] = (r_id, new_date)
|
||||||
except Establishment.MultipleObjectsReturned:
|
|
||||||
establishment = Establishment.objects.filter(old_id=obj.establishment.id).first()
|
|
||||||
else:
|
else:
|
||||||
|
if new_date > date:
|
||||||
|
valid_reviews[establishment_id] = (r_id, new_date)
|
||||||
|
|
||||||
|
text_qs = ReviewTexts.objects.exclude(
|
||||||
|
locale__isnull=True
|
||||||
|
).filter(
|
||||||
|
review_id__in=(value[0] for value in valid_reviews.values()),
|
||||||
|
).values_list(
|
||||||
|
'review__establishment_id',
|
||||||
|
'locale',
|
||||||
|
'text',
|
||||||
|
)
|
||||||
|
|
||||||
|
for es_id, locale, text in text_qs:
|
||||||
|
establishment = Establishment.objects.filter(old_id=es_id).first()
|
||||||
|
if establishment:
|
||||||
description = establishment.description
|
description = establishment.description
|
||||||
description.update({
|
description.update({
|
||||||
obj.locale: obj.text
|
locale: text
|
||||||
})
|
})
|
||||||
establishment.description = description
|
establishment.description = description
|
||||||
establishment.save()
|
establishment.save()
|
||||||
count += 1
|
count += 1
|
||||||
break
|
|
||||||
|
# Если нет en-GB в поле
|
||||||
|
for establishment in Establishment.objects.filter(old_id__isnull=False):
|
||||||
|
description = establishment.description
|
||||||
|
if len(description) and 'en-GB' not in description:
|
||||||
|
description.update({
|
||||||
|
'en-GB': next(iter(description.values()))
|
||||||
|
})
|
||||||
|
establishment.description = description
|
||||||
|
establishment.save()
|
||||||
|
update_locale += 1
|
||||||
|
|
||||||
self.stdout.write(self.style.WARNING(f'Updated {count} objects.'))
|
self.stdout.write(self.style.WARNING(f'Updated {count} objects.'))
|
||||||
|
self.stdout.write(self.style.WARNING(f'Updated en-GB locale - {count}'))
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,16 @@ class Command(BaseCommand):
|
||||||
AND scope = 'public'
|
AND scope = 'public'
|
||||||
AND type = 'Photo'
|
AND type = 'Photo'
|
||||||
AND menu_id IS NULL
|
AND menu_id IS NULL
|
||||||
GROUP BY establishment_id;'''
|
GROUP BY establishment_assets.id, establishment_id, attachment_suffix_url;'''
|
||||||
)
|
)
|
||||||
queryset = [vars(query) for query in raw_qs]
|
queryset = [vars(query) for query in raw_qs]
|
||||||
for obj in queryset:
|
for obj in queryset:
|
||||||
establishment = Establishment.objects.filter(old_id=obj['establishment_id']).first()
|
establishment = Establishment.objects.filter(old_id=obj['establishment_id'], image_url__isnull=True).first()
|
||||||
if establishment:
|
if establishment:
|
||||||
img = url + obj['attachment_suffix_url']
|
img = url + obj['attachment_suffix_url']
|
||||||
establishment.preview_image_url = img
|
img_url = img[:-12]
|
||||||
|
extension = img.split('.')[-1:][0] # JPG
|
||||||
|
establishment.preview_image_url = f'{img_url}xlarge.{extension}'
|
||||||
establishment.image_url = img
|
establishment.image_url = img
|
||||||
establishment.save()
|
establishment.save()
|
||||||
count += 1
|
count += 1
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from establishment.models import Establishment, SocialNetwork
|
||||||
|
from transfer.models import EstablishmentInfos
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Add social links values from old db to new db'
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
queryset = EstablishmentInfos.objects.exclude(
|
||||||
|
establishment_id__isnull=True
|
||||||
|
).values_list('id', 'establishment_id', 'facebook', 'twitter', 'instagram')
|
||||||
|
|
||||||
|
for id, es_id, facebook, twitter, instagram in queryset:
|
||||||
|
try:
|
||||||
|
establishment = Establishment.objects.get(old_id=es_id)
|
||||||
|
except Establishment.DoesNotExist:
|
||||||
|
continue
|
||||||
|
except Establishment.MultipleObjectsReturned:
|
||||||
|
establishment = Establishment.objects.filter(old_id=es_id).first()
|
||||||
|
else:
|
||||||
|
if facebook:
|
||||||
|
if 'facebook.com/' not in facebook:
|
||||||
|
facebook = 'https://www.facebook.com/' + facebook
|
||||||
|
obj, _ = SocialNetwork.objects.get_or_create(
|
||||||
|
old_id=id,
|
||||||
|
establishment=establishment,
|
||||||
|
title='facebook',
|
||||||
|
url=facebook,
|
||||||
|
)
|
||||||
|
count += 1
|
||||||
|
if twitter:
|
||||||
|
if 'twitter.com/' not in twitter:
|
||||||
|
twitter = 'https://www.twitter.com/' + twitter
|
||||||
|
obj, _ = SocialNetwork.objects.get_or_create(
|
||||||
|
old_id=id,
|
||||||
|
establishment=establishment,
|
||||||
|
title='twitter',
|
||||||
|
url=twitter,
|
||||||
|
)
|
||||||
|
count += 1
|
||||||
|
if instagram:
|
||||||
|
if 'instagram.com/' not in instagram:
|
||||||
|
instagram = 'https://www.instagram.com/' + instagram
|
||||||
|
obj, _ = SocialNetwork.objects.get_or_create(
|
||||||
|
old_id=id,
|
||||||
|
establishment=establishment,
|
||||||
|
title='instagram',
|
||||||
|
url=instagram,
|
||||||
|
)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
self.stdout.write(self.style.WARNING(f'Created/updated {count} objects.'))
|
||||||
33
apps/establishment/management/commands/add_menus.py
Normal file
33
apps/establishment/management/commands/add_menus.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from establishment.models import Establishment, Menu, Plate
|
||||||
|
from transfer.models import Menus
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Add menus from old db to new db'
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
count = 0
|
||||||
|
menus = Menus.objects.filter(name__isnull=False).exclude(name='')
|
||||||
|
for old_menu in menus:
|
||||||
|
est = Establishment.objects.filter(
|
||||||
|
old_id=old_menu.establishment_id).first()
|
||||||
|
if est:
|
||||||
|
|
||||||
|
menu, _ = Menu.objects.get_or_create(
|
||||||
|
category={'en-GB': 'formulas'},
|
||||||
|
establishment=est
|
||||||
|
)
|
||||||
|
plate, created = Plate.objects.get_or_create(
|
||||||
|
name={"en-GB": old_menu.name},
|
||||||
|
menu=menu,
|
||||||
|
price=old_menu.price or 0
|
||||||
|
)
|
||||||
|
if created:
|
||||||
|
plate.currency_code = old_menu.currency
|
||||||
|
plate.currency = est.currency
|
||||||
|
plate.save()
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
self.stdout.write(self.style.WARNING(f'Updated/created {count} objects.'))
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
"""Run recalculating toque number for establishments."""
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from establishment.models import Establishment
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
help = 'Recalculation toque number for all establishments.'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
for establishment in Establishment.objects.select_related('address__city__country'):
|
||||||
|
print(f'Recalculate for {establishment.name} ({establishment.id})')
|
||||||
|
establishment.recalculate_toque_number()
|
||||||
30
apps/establishment/management/commands/upd_transportation.py
Normal file
30
apps/establishment/management/commands/upd_transportation.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from establishment.models import Establishment
|
||||||
|
from transfer.models import Establishments as OldEst
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Update transportation column in establishment'
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
count = 0
|
||||||
|
raw_qs = OldEst.objects.raw(
|
||||||
|
'''
|
||||||
|
select
|
||||||
|
e.id,
|
||||||
|
l.transportation
|
||||||
|
from establishments e
|
||||||
|
join locations l on l.id = e.location_id
|
||||||
|
where trim(l.transportation) is not null
|
||||||
|
and length(trim(l.transportation)) >1;
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
queryset = [vars(query) for query in raw_qs]
|
||||||
|
for obj in queryset:
|
||||||
|
establishment = Establishment.objects.filter(old_id=obj['id']).first()
|
||||||
|
if establishment:
|
||||||
|
establishment.transportation = obj['transportation']
|
||||||
|
count += 1
|
||||||
|
establishment.save()
|
||||||
|
self.stdout.write(self.style.WARNING(f'Updated {count} objects.'))
|
||||||
33
apps/establishment/migrations/0048_ratingstrategy.py
Normal file
33
apps/establishment/migrations/0048_ratingstrategy.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 15:55
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('location', '0020_merge_20191030_1714'),
|
||||||
|
('establishment', '0047_merge_20191030_1714'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RatingStrategy',
|
||||||
|
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')),
|
||||||
|
('toque_number', models.IntegerField(choices=[(1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five')])),
|
||||||
|
('public_mark_min_value', models.IntegerField()),
|
||||||
|
('public_mark_max_value', models.IntegerField()),
|
||||||
|
('country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='Country')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Rating strategy',
|
||||||
|
'verbose_name_plural': 'Rating strategy',
|
||||||
|
'unique_together': {('country', 'toque_number')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
19
apps/establishment/migrations/0049_auto_20191031_1616.py
Normal file
19
apps/establishment/migrations/0049_auto_20191031_1616.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 16:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0048_ratingstrategy'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ratingstrategy',
|
||||||
|
name='country',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='Country'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/establishment/migrations/0050_socialnetwork_old_id.py
Normal file
18
apps/establishment/migrations/0050_socialnetwork_old_id.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-01 07:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0049_auto_20191031_1616'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='socialnetwork',
|
||||||
|
name='old_id',
|
||||||
|
field=models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='old id'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/establishment/migrations/0051_auto_20191101_0732.py
Normal file
18
apps/establishment/migrations/0051_auto_20191101_0732.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-01 07:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0050_socialnetwork_old_id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='socialnetwork',
|
||||||
|
name='url',
|
||||||
|
field=models.URLField(max_length=255, verbose_name='URL'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/establishment/migrations/0052_plate_currency_code.py
Normal file
18
apps/establishment/migrations/0052_plate_currency_code.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-03 20:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0051_auto_20191101_0732'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='plate',
|
||||||
|
name='currency_code',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=250, null=True, verbose_name='currency code'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
apps/establishment/migrations/0053_auto_20191103_2051.py
Normal file
19
apps/establishment/migrations/0053_auto_20191103_2051.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-03 20:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0052_plate_currency_code'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='plate',
|
||||||
|
name='currency',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='main.Currency', verbose_name='currency'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/establishment/migrations/0054_auto_20191103_2117.py
Normal file
18
apps/establishment/migrations/0054_auto_20191103_2117.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-03 21:17
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0053_auto_20191103_2051'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='plate',
|
||||||
|
name='is_signature_plate',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='is signature plate'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -14,7 +14,6 @@ from django.db.models import When, Case, F, ExpressionWrapper, Subquery, Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
from phonenumber_field.modelfields import PhoneNumberField
|
||||||
from pytz import timezone as ptz
|
|
||||||
from timezone_field import TimeZoneField
|
from timezone_field import TimeZoneField
|
||||||
|
|
||||||
from collection.models import Collection
|
from collection.models import Collection
|
||||||
|
|
@ -310,6 +309,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
||||||
public_mark = models.PositiveIntegerField(blank=True, null=True,
|
public_mark = models.PositiveIntegerField(blank=True, null=True,
|
||||||
default=None,
|
default=None,
|
||||||
verbose_name=_('public mark'),)
|
verbose_name=_('public mark'),)
|
||||||
|
# todo: set default 0
|
||||||
toque_number = models.PositiveIntegerField(blank=True, null=True,
|
toque_number = models.PositiveIntegerField(blank=True, null=True,
|
||||||
default=None,
|
default=None,
|
||||||
verbose_name=_('toque number'),)
|
verbose_name=_('toque number'),)
|
||||||
|
|
@ -384,7 +384,13 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
||||||
|
|
||||||
# todo: recalculate toque_number
|
# todo: recalculate toque_number
|
||||||
def recalculate_toque_number(self):
|
def recalculate_toque_number(self):
|
||||||
self.toque_number = 4
|
toque_number = 0
|
||||||
|
if self.address and self.public_mark:
|
||||||
|
toque_number = RatingStrategy.objects. \
|
||||||
|
get_toque_number(country=self.address.city.country,
|
||||||
|
public_mark=self.public_mark)
|
||||||
|
self.toque_number = toque_number
|
||||||
|
self.save()
|
||||||
|
|
||||||
def recalculate_price_level(self, low_price=None, high_price=None):
|
def recalculate_price_level(self, low_price=None, high_price=None):
|
||||||
if low_price is None or high_price is None:
|
if low_price is None or high_price is None:
|
||||||
|
|
@ -428,6 +434,27 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
||||||
def best_price_carte(self):
|
def best_price_carte(self):
|
||||||
return 200
|
return 200
|
||||||
|
|
||||||
|
@property
|
||||||
|
def range_price_menu(self):
|
||||||
|
plates = self.menu_set.filter(
|
||||||
|
models.Q(category={'en-GB': 'formulas'})
|
||||||
|
).aggregate(
|
||||||
|
max=models.Max('plate__price', output_field=models.FloatField()),
|
||||||
|
min=models.Min('plate__price', output_field=models.FloatField()))
|
||||||
|
return plates
|
||||||
|
|
||||||
|
@property
|
||||||
|
def range_price_carte(self):
|
||||||
|
plates = self.menu_set.filter(
|
||||||
|
models.Q(category={'en-GB': 'starter'}) |
|
||||||
|
models.Q(category={'en-GB': 'main_course'}) |
|
||||||
|
models.Q(category={'en-GB': 'dessert'})
|
||||||
|
).aggregate(
|
||||||
|
max=models.Max('plate__price', output_field=models.FloatField()),
|
||||||
|
min=models.Min('plate__price', output_field=models.FloatField()),
|
||||||
|
)
|
||||||
|
return plates
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def works_noon(self):
|
def works_noon(self):
|
||||||
""" Used for indexing working by day """
|
""" Used for indexing working by day """
|
||||||
|
|
@ -622,9 +649,12 @@ class Plate(TranslatedFieldsMixin, models.Model):
|
||||||
help_text='{"en-GB":"some text"}')
|
help_text='{"en-GB":"some text"}')
|
||||||
price = models.DecimalField(
|
price = models.DecimalField(
|
||||||
_('price'), max_digits=14, decimal_places=2)
|
_('price'), max_digits=14, decimal_places=2)
|
||||||
is_signature_plate = models.BooleanField(_('is signature plate'))
|
is_signature_plate = models.BooleanField(_('is signature plate'), default=False)
|
||||||
currency = models.ForeignKey(
|
currency = models.ForeignKey(
|
||||||
'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE)
|
'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE,
|
||||||
|
blank=True, null=True, default=None)
|
||||||
|
currency_code = models.CharField(
|
||||||
|
_('currency code'), max_length=250, blank=True, null=True, default=None)
|
||||||
|
|
||||||
menu = models.ForeignKey(
|
menu = models.ForeignKey(
|
||||||
'establishment.Menu', verbose_name=_('menu'), on_delete=models.CASCADE)
|
'establishment.Menu', verbose_name=_('menu'), on_delete=models.CASCADE)
|
||||||
|
|
@ -656,11 +686,12 @@ class Menu(TranslatedFieldsMixin, BaseAttributes):
|
||||||
|
|
||||||
|
|
||||||
class SocialNetwork(models.Model):
|
class SocialNetwork(models.Model):
|
||||||
|
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
|
||||||
establishment = models.ForeignKey(
|
establishment = models.ForeignKey(
|
||||||
'Establishment', verbose_name=_('establishment'),
|
'Establishment', verbose_name=_('establishment'),
|
||||||
related_name='socials', on_delete=models.CASCADE)
|
related_name='socials', on_delete=models.CASCADE)
|
||||||
title = models.CharField(_('title'), max_length=255)
|
title = models.CharField(_('title'), max_length=255)
|
||||||
url = models.URLField(_('URL'))
|
url = models.URLField(_('URL'), max_length=255)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('social network')
|
verbose_name = _('social network')
|
||||||
|
|
@ -669,3 +700,62 @@ class SocialNetwork(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
|
class RatingStrategyManager(models.Manager):
|
||||||
|
"""Extended manager for RatingStrategy."""
|
||||||
|
|
||||||
|
def get_toque_number(self, country, public_mark):
|
||||||
|
"""Get toque number for country and public_mark."""
|
||||||
|
qs = self.model.objects.by_country(country)
|
||||||
|
if not qs.exists():
|
||||||
|
qs = self.model.objects.by_country(None)
|
||||||
|
obj = qs.for_public_mark(public_mark).first()
|
||||||
|
if obj:
|
||||||
|
return obj.toque_number
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
class RatingStrategyQuerySet(models.QuerySet):
|
||||||
|
"""Extended queryset for RatingStrategy."""
|
||||||
|
|
||||||
|
def by_country(self, country):
|
||||||
|
"""Filter by country."""
|
||||||
|
return self.filter(country=country)
|
||||||
|
|
||||||
|
def for_public_mark(self, public_mark):
|
||||||
|
"""Filter for value."""
|
||||||
|
return self.filter(public_mark_min_value__lte=public_mark,
|
||||||
|
public_mark_max_value__gte=public_mark)
|
||||||
|
|
||||||
|
|
||||||
|
class RatingStrategy(ProjectBaseMixin):
|
||||||
|
"""Rating Strategy model."""
|
||||||
|
|
||||||
|
TOQUE_NUMBER_CHOICES = (
|
||||||
|
(1, _('One')),
|
||||||
|
(2, _('Two')),
|
||||||
|
(3, _('Three')),
|
||||||
|
(4, _('Four')),
|
||||||
|
(5, _('Five')),
|
||||||
|
)
|
||||||
|
|
||||||
|
country = models.ForeignKey('location.Country', null=True, blank=True,
|
||||||
|
default=None, on_delete=models.CASCADE,
|
||||||
|
verbose_name=_('Country'))
|
||||||
|
toque_number = models.IntegerField(choices=TOQUE_NUMBER_CHOICES)
|
||||||
|
public_mark_min_value = models.IntegerField()
|
||||||
|
public_mark_max_value = models.IntegerField()
|
||||||
|
|
||||||
|
objects = RatingStrategyManager.from_queryset(RatingStrategyQuerySet)()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class."""
|
||||||
|
|
||||||
|
verbose_name = _('Rating strategy')
|
||||||
|
verbose_name_plural = _('Rating strategy')
|
||||||
|
unique_together = ('country', 'toque_number')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.country.code if self.country else "Other country"}. ' \
|
||||||
|
f'"{self.toque_number}": {self.public_mark_min_value}-' \
|
||||||
|
f'{self.public_mark_max_value}'
|
||||||
|
|
@ -149,6 +149,7 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
'establishment_type': {'write_only': True}
|
'establishment_type': {'write_only': True}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentSubTypeGeoSerializer(EstablishmentSubTypeBaseSerializer):
|
class EstablishmentSubTypeGeoSerializer(EstablishmentSubTypeBaseSerializer):
|
||||||
"""Serializer for EstablishmentSuType model w/ index_name."""
|
"""Serializer for EstablishmentSuType model w/ index_name."""
|
||||||
|
|
||||||
|
|
@ -223,6 +224,11 @@ class EstablishmentGeoSerializer(EstablishmentBaseSerializer):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class RangePriceSerializer(serializers.Serializer):
|
||||||
|
max = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True, default=0)
|
||||||
|
min = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True, default=0)
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
||||||
"""Serializer for Establishment model."""
|
"""Serializer for Establishment model."""
|
||||||
|
|
||||||
|
|
@ -240,6 +246,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
||||||
menu = MenuSerializers(source='menu_set', many=True, read_only=True)
|
menu = MenuSerializers(source='menu_set', many=True, read_only=True)
|
||||||
best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
|
best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
|
||||||
best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
|
best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
|
||||||
|
range_price_menu = RangePriceSerializer(read_only=True)
|
||||||
|
range_price_carte = RangePriceSerializer(read_only=True)
|
||||||
vintage_year = serializers.ReadOnlyField()
|
vintage_year = serializers.ReadOnlyField()
|
||||||
|
|
||||||
class Meta(EstablishmentBaseSerializer.Meta):
|
class Meta(EstablishmentBaseSerializer.Meta):
|
||||||
|
|
@ -264,6 +272,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
||||||
'menu',
|
'menu',
|
||||||
'best_price_menu',
|
'best_price_menu',
|
||||||
'best_price_carte',
|
'best_price_carte',
|
||||||
|
'range_price_menu',
|
||||||
|
'range_price_carte',
|
||||||
'transportation',
|
'transportation',
|
||||||
'vintage_year',
|
'vintage_year',
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,24 @@
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
|
import requests
|
||||||
from django.db.models import Q, F
|
from django.db.models import Q, F
|
||||||
|
|
||||||
from transfer.models import Establishments, Dishes
|
|
||||||
from transfer.serializers.establishment import EstablishmentSerializer
|
|
||||||
from establishment.models import Establishment
|
from establishment.models import Establishment
|
||||||
from location.models import Address
|
from location.models import Address
|
||||||
|
from transfer.models import Establishments, Dishes
|
||||||
|
from transfer.serializers.establishment import EstablishmentSerializer
|
||||||
from transfer.serializers.plate import PlateSerializer
|
from transfer.serializers.plate import PlateSerializer
|
||||||
|
|
||||||
|
|
||||||
def transfer_establishment():
|
def transfer_establishment():
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
old_establishments = Establishments.objects.filter(
|
# todo: filter(location__city__name__icontains='paris')
|
||||||
location__city__name__icontains='paris',
|
old_establishments = Establishments.objects.exclude(
|
||||||
|
id__in=list(Establishment.objects.all().values_list('old_id', flat=True))
|
||||||
).exclude(
|
).exclude(
|
||||||
Q(type='Wineyard') |
|
Q(type='Wineyard') |
|
||||||
Q(location__timezone__isnull=True)
|
Q(location__timezone__isnull=True),
|
||||||
).prefetch_related(
|
).prefetch_related(
|
||||||
'establishmentinfos_set',
|
'establishmentinfos_set',
|
||||||
'schedules_set',
|
'schedules_set',
|
||||||
|
|
@ -133,6 +135,5 @@ data_types = {
|
||||||
"location_establishment": [
|
"location_establishment": [
|
||||||
transfer_establishment_addresses
|
transfer_establishment_addresses
|
||||||
],
|
],
|
||||||
|
|
||||||
"menu": [transfer_menu],
|
"menu": [transfer_menu],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ from django.dispatch import receiver
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from translation.models import Language
|
from translation.models import Language
|
||||||
from utils.models import ProjectBaseMixin, SVGImageMixin, TranslatedFieldsMixin, TJSONField
|
from utils.models import (ProjectBaseMixin, SVGImageMixin, TJSONField,
|
||||||
|
TranslatedFieldsMixin, get_current_locale)
|
||||||
|
|
||||||
|
|
||||||
class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
||||||
|
|
@ -15,6 +16,13 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
||||||
|
|
||||||
STR_FIELD_NAME = 'name'
|
STR_FIELD_NAME = 'name'
|
||||||
|
|
||||||
|
TWELVE_HOURS_FORMAT_COUNTRIES = [
|
||||||
|
'ca', # Canada
|
||||||
|
'au', # Australia
|
||||||
|
'us', # USA
|
||||||
|
'nz', # New Zealand
|
||||||
|
]
|
||||||
|
|
||||||
name = TJSONField(null=True, blank=True, default=None,
|
name = TJSONField(null=True, blank=True, default=None,
|
||||||
verbose_name=_('Name'), help_text='{"en-GB":"some text"}')
|
verbose_name=_('Name'), help_text='{"en-GB":"some text"}')
|
||||||
code = models.CharField(max_length=255, unique=True, verbose_name=_('Code'))
|
code = models.CharField(max_length=255, unique=True, verbose_name=_('Code'))
|
||||||
|
|
@ -23,6 +31,12 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
||||||
languages = models.ManyToManyField(Language, verbose_name=_('Languages'))
|
languages = models.ManyToManyField(Language, verbose_name=_('Languages'))
|
||||||
old_id = models.IntegerField(null=True, blank=True, default=None)
|
old_id = models.IntegerField(null=True, blank=True, default=None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def time_format(self):
|
||||||
|
if self.code.lower() not in self.TWELVE_HOURS_FORMAT_COUNTRIES:
|
||||||
|
return 'HH:mm'
|
||||||
|
return 'hh:mmA'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def country_id(self):
|
def country_id(self):
|
||||||
return self.id
|
return self.id
|
||||||
|
|
@ -33,6 +47,14 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
||||||
verbose_name_plural = _('Countries')
|
verbose_name_plural = _('Countries')
|
||||||
verbose_name = _('Country')
|
verbose_name = _('Country')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
str_name = self.code
|
||||||
|
if isinstance(self.name, dict):
|
||||||
|
translated_name = self.name.get(get_current_locale())
|
||||||
|
if translated_name:
|
||||||
|
str_name = translated_name
|
||||||
|
return str_name
|
||||||
|
|
||||||
|
|
||||||
class Region(models.Model):
|
class Region(models.Model):
|
||||||
"""Region model."""
|
"""Region model."""
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
from django.db.models import Q, QuerySet
|
from transfer.serializers.location import CountrySerializer, RegionSerializer, \
|
||||||
|
CitySerializer, AddressSerializer, \
|
||||||
from transfer.serializers.location import CountrySerializer, RegionSerializer, CitySerializer, AddressSerializer
|
Country
|
||||||
from transfer.models import Cities, Locations
|
from transfer.models import Cities, Locations
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
|
from requests import get
|
||||||
|
|
||||||
|
|
||||||
def transfer_countries():
|
def transfer_countries():
|
||||||
queryset = Cities.objects.raw("""SELECT cities.id, cities.country_code_2
|
queryset = Cities.objects.raw("""
|
||||||
FROM cities WHERE
|
SELECT cities.id, cities.country_code_2
|
||||||
country_code_2 IS NOT NULL AND
|
FROM cities
|
||||||
|
WHERE country_code_2 IS NOT NULL AND
|
||||||
country_code_2 != ""
|
country_code_2 != ""
|
||||||
GROUP BY cities.country_code_2""")
|
GROUP BY cities.id, cities.country_code_2
|
||||||
|
""")
|
||||||
|
|
||||||
queryset = [vars(query) for query in queryset]
|
queryset = [vars(query) for query in queryset]
|
||||||
|
|
||||||
|
|
@ -22,16 +26,24 @@ def transfer_countries():
|
||||||
|
|
||||||
|
|
||||||
def transfer_regions():
|
def transfer_regions():
|
||||||
regions_without_subregion_queryset = Cities.objects.raw("""SELECT cities.id, cities.region_code,
|
regions_without_subregion_queryset = Cities.objects.raw("""
|
||||||
cities.country_code_2, cities.subregion_code
|
SELECT cities.id,
|
||||||
FROM cities WHERE
|
cities.region_code,
|
||||||
(subregion_code IS NULL OR
|
cities.country_code_2,
|
||||||
subregion_code = "") AND
|
cities.subregion_code
|
||||||
region_code IS NOT NULL AND
|
FROM cities
|
||||||
region_code != "" AND
|
WHERE (subregion_code IS NULL
|
||||||
country_code_2 IS NOT NULL AND
|
OR subregion_code = ""
|
||||||
country_code_2 != ""
|
)
|
||||||
GROUP BY region_code""")
|
AND region_code IS NOT NULL
|
||||||
|
AND region_code != ""
|
||||||
|
AND country_code_2 IS NOT NULL
|
||||||
|
AND country_code_2 != ""
|
||||||
|
GROUP BY cities.id,
|
||||||
|
cities.region_code,
|
||||||
|
cities.country_code_2,
|
||||||
|
cities.subregion_code
|
||||||
|
""")
|
||||||
|
|
||||||
regions_without_subregion_queryset = [vars(query) for query in regions_without_subregion_queryset]
|
regions_without_subregion_queryset = [vars(query) for query in regions_without_subregion_queryset]
|
||||||
|
|
||||||
|
|
@ -41,16 +53,21 @@ def transfer_regions():
|
||||||
else:
|
else:
|
||||||
pprint(f"Parent regions serializer errors: {serialized_without_subregion.errors}")
|
pprint(f"Parent regions serializer errors: {serialized_without_subregion.errors}")
|
||||||
|
|
||||||
regions_with_subregion_queryset = Cities.objects.raw("""SELECT cities.id, cities.region_code,
|
regions_with_subregion_queryset = Cities.objects.raw("""
|
||||||
cities.country_code_2, cities.subregion_code
|
SELECT
|
||||||
FROM cities WHERE
|
cities.id,
|
||||||
subregion_code IS NOT NULL AND
|
cities.region_code,
|
||||||
|
cities.country_code_2,
|
||||||
|
cities.subregion_code
|
||||||
|
FROM cities
|
||||||
|
WHERE subregion_code IS NOT NULL AND
|
||||||
subregion_code != "" AND
|
subregion_code != "" AND
|
||||||
region_code IS NOT NULL AND
|
region_code IS NOT NULL AND
|
||||||
region_code != "" AND
|
region_code != "" AND
|
||||||
country_code_2 IS NOT NULL AND
|
country_code_2 IS NOT NULL AND
|
||||||
country_code_2 != ""
|
country_code_2 != ""
|
||||||
AND cities.subregion_code in (
|
AND cities.subregion_code in
|
||||||
|
(
|
||||||
SELECT region_code FROM cities WHERE
|
SELECT region_code FROM cities WHERE
|
||||||
(subregion_code IS NULL OR
|
(subregion_code IS NULL OR
|
||||||
subregion_code = "") AND
|
subregion_code = "") AND
|
||||||
|
|
@ -59,7 +76,11 @@ def transfer_regions():
|
||||||
country_code_2 IS NOT NULL AND
|
country_code_2 IS NOT NULL AND
|
||||||
country_code_2 != ""
|
country_code_2 != ""
|
||||||
)
|
)
|
||||||
GROUP BY region_code""")
|
GROUP BY cities.id,
|
||||||
|
cities.region_code,
|
||||||
|
cities.country_code_2,
|
||||||
|
cities.subregion_code
|
||||||
|
""")
|
||||||
|
|
||||||
regions_with_subregion_queryset = [vars(query) for query in regions_with_subregion_queryset]
|
regions_with_subregion_queryset = [vars(query) for query in regions_with_subregion_queryset]
|
||||||
|
|
||||||
|
|
@ -112,6 +133,17 @@ def transfer_addresses():
|
||||||
pprint(f"Address serializer errors: {serialized_data.errors}")
|
pprint(f"Address serializer errors: {serialized_data.errors}")
|
||||||
|
|
||||||
|
|
||||||
|
def update_flags():
|
||||||
|
queryset = Country.objects.only("id", "code", "svg_image").filter(old_id__isnull=False)
|
||||||
|
link_to_request = "https://s3.eu-central-1.amazonaws.com/gm-test.com/media"
|
||||||
|
|
||||||
|
for query in queryset:
|
||||||
|
svg_link = f"/svg/country/10-31-2019/{query.code}.svg"
|
||||||
|
resp = get(f"{link_to_request}{svg_link}")
|
||||||
|
if resp.status_code == 200:
|
||||||
|
query.svg_image = svg_link
|
||||||
|
query.save()
|
||||||
|
|
||||||
|
|
||||||
data_types = {
|
data_types = {
|
||||||
"dictionaries": [
|
"dictionaries": [
|
||||||
|
|
@ -119,5 +151,8 @@ data_types = {
|
||||||
transfer_regions,
|
transfer_regions,
|
||||||
transfer_cities,
|
transfer_cities,
|
||||||
transfer_addresses
|
transfer_addresses
|
||||||
|
],
|
||||||
|
"update_country_flag": [
|
||||||
|
update_flags
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,10 @@ class AwardAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Currency)
|
@admin.register(models.Currency)
|
||||||
class CurrencContentAdmin(admin.ModelAdmin):
|
class CurrencyContentAdmin(admin.ModelAdmin):
|
||||||
"""CurrencContent admin"""
|
"""Currency Content admin"""
|
||||||
|
list_display = ['id', 'slug', 'code']
|
||||||
|
list_display_links = ['slug']
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Carousel)
|
@admin.register(models.Carousel)
|
||||||
|
|
|
||||||
48
apps/main/migrations/0024_auto_20191031_1439.py
Normal file
48
apps/main/migrations/0024_auto_20191031_1439.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 14:39
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0023_merge_20191028_0725'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='active',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='old active'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='attachment_suffix_url',
|
||||||
|
field=models.TextField(blank=True, default=None, null=True, verbose_name='old attachment_suffix_url'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old description'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='link',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old link'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='link_title',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old link_title'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='old_id',
|
||||||
|
field=models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='old id'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old title'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/main/migrations/0025_carousel_is_parse.py
Normal file
18
apps/main/migrations/0025_carousel_is_parse.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 15:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0024_auto_20191031_1439'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='is_parse',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='is parse'),
|
||||||
|
),
|
||||||
|
]
|
||||||
24
apps/main/migrations/0026_auto_20191101_0500.py
Normal file
24
apps/main/migrations/0026_auto_20191101_0500.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-01 05:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0025_carousel_is_parse'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='content_type',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='object_id',
|
||||||
|
field=models.PositiveIntegerField(blank=True, default=None, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
20
apps/main/migrations/0027_carousel_country.py
Normal file
20
apps/main/migrations/0027_carousel_country.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-01 14:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('location', '0020_merge_20191030_1714'),
|
||||||
|
('main', '0026_auto_20191101_0500'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='carousel',
|
||||||
|
name='country',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='location.Country', verbose_name='country'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/main/migrations/0028_auto_20191103_1237.py
Normal file
18
apps/main/migrations/0028_auto_20191103_1237.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-03 12:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0027_carousel_country'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='currency',
|
||||||
|
name='sign',
|
||||||
|
field=models.CharField(max_length=3, verbose_name='sign'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/main/migrations/0029_auto_20191103_1344.py
Normal file
18
apps/main/migrations/0029_auto_20191103_1344.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-03 13:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0028_auto_20191103_1237'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='currency',
|
||||||
|
name='sign',
|
||||||
|
field=models.CharField(max_length=5, verbose_name='sign'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/main/migrations/0030_auto_20191103_1350.py
Normal file
18
apps/main/migrations/0030_auto_20191103_1350.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-03 13:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0029_auto_20191103_1344'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='currency',
|
||||||
|
name='sign',
|
||||||
|
field=models.CharField(max_length=255, verbose_name='sign'),
|
||||||
|
),
|
||||||
|
]
|
||||||
23
apps/main/migrations/0031_auto_20191103_2037.py
Normal file
23
apps/main/migrations/0031_auto_20191103_2037.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-03 20:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0030_auto_20191103_1350'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='currency',
|
||||||
|
name='code',
|
||||||
|
field=models.CharField(default=None, max_length=5, null=True, unique=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='currency',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(max_length=5, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -5,6 +5,7 @@ from django.conf import settings
|
||||||
from django.contrib.contenttypes import fields as generic
|
from django.contrib.contenttypes import fields as generic
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.postgres.fields import JSONField
|
from django.contrib.postgres.fields import JSONField
|
||||||
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
@ -14,96 +15,8 @@ from configuration.models import TranslationSettings
|
||||||
from location.models import Country
|
from location.models import Country
|
||||||
from main import methods
|
from main import methods
|
||||||
from review.models import Review
|
from review.models import Review
|
||||||
from utils.models import (ProjectBaseMixin, TJSONField,
|
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
|
||||||
TranslatedFieldsMixin, ImageMixin,
|
TranslatedFieldsMixin, PlatformMixin)
|
||||||
PlatformMixin, URLImageMixin)
|
|
||||||
from utils.querysets import ContentTypeQuerySetMixin
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class Tag(models.Model):
|
|
||||||
# """Tag model."""
|
|
||||||
# name = models.CharField(max_length=250)
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class MediaAsset(models.Model):
|
|
||||||
# """Assets model."""
|
|
||||||
# PHOTO = 0
|
|
||||||
# VIDEO = 1
|
|
||||||
# VIDEO_URL = 2
|
|
||||||
# PDF = 3
|
|
||||||
# DOCUMENT = 4
|
|
||||||
#
|
|
||||||
# ASSET_TYPE_CHOICES = (
|
|
||||||
# (PHOTO, _('photo')),
|
|
||||||
# (VIDEO, _('video')),
|
|
||||||
# (VIDEO_URL, _('video url')),
|
|
||||||
# (PDF, _('pdf')),
|
|
||||||
# (DOCUMENT, _('document'))
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# AMAZON_S3 = 0
|
|
||||||
#
|
|
||||||
# STORAGE_TYPE_CHOICES = (
|
|
||||||
# (AMAZON_S3, _('amazon s3')),
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# PUBLIC = 0
|
|
||||||
# PRIVATE = 1
|
|
||||||
# ROLE = 2
|
|
||||||
#
|
|
||||||
# ACCESS_TYPE_CHOICES = (
|
|
||||||
# (PUBLIC, _('public')),
|
|
||||||
# (PRIVATE, _('private')),
|
|
||||||
# (ROLE, _('role')),
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# asset_type = models.PositiveSmallIntegerField(
|
|
||||||
# _('asset type'), choices=ASSET_TYPE_CHOICES, default=PHOTO
|
|
||||||
# )
|
|
||||||
# storage_type = models.PositiveSmallIntegerField(
|
|
||||||
# _('storage type'), choices=STORAGE_TYPE_CHOICES, default=AMAZON_S3
|
|
||||||
# )
|
|
||||||
# storage_unit = models.CharField(_('storage unit'), blank=True, default='')
|
|
||||||
# path = models.CharField(_('path'))
|
|
||||||
# access_type = models.PositiveSmallIntegerField(
|
|
||||||
# _('access type'), choices=ACCESS_TYPE_CHOICES, default=PUBLIC)
|
|
||||||
# asset_text = JSONField(_('asset_text'))
|
|
||||||
# size = models.IntegerField(_('size'))
|
|
||||||
# version = models.CharField(_('version'), max_length=250)
|
|
||||||
# text = JSONField(_('text'))
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class Contacts(models.Model):
|
|
||||||
# """Contacts model."""
|
|
||||||
# address = models.ForeignKey(
|
|
||||||
# 'location.Address', verbose_name=_('address'), on_delete=models.CASCADE
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class Social(models.Model):
|
|
||||||
# """Social model."""
|
|
||||||
# WEBSITE = 0
|
|
||||||
# SOCIAL = 1
|
|
||||||
#
|
|
||||||
# SOCIAL_TYPE_CHOICES = (
|
|
||||||
# (WEBSITE, _('website')),
|
|
||||||
# (SOCIAL, _('social')),
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# social_type = models.PositiveSmallIntegerField(
|
|
||||||
# _('social type'), choices=SOCIAL_TYPE_CHOICES
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class Note(models.Model):
|
|
||||||
# """Note model."""
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class Ad(models.Model):
|
|
||||||
# """Ad model."""
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
class Currency(TranslatedFieldsMixin, models.Model):
|
class Currency(TranslatedFieldsMixin, models.Model):
|
||||||
|
|
@ -111,8 +24,9 @@ class Currency(TranslatedFieldsMixin, models.Model):
|
||||||
name = TJSONField(
|
name = TJSONField(
|
||||||
_('name'), null=True, blank=True,
|
_('name'), null=True, blank=True,
|
||||||
default=None, help_text='{"en-GB":"some text"}')
|
default=None, help_text='{"en-GB":"some text"}')
|
||||||
sign = models.CharField(_('sign'), max_length=1)
|
sign = models.CharField(_('sign'), max_length=255)
|
||||||
slug = models.SlugField(max_length=255, unique=True)
|
slug = models.SlugField(max_length=5, unique=True)
|
||||||
|
code = models.CharField(max_length=5, unique=True, null=True, default=None)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('currency')
|
verbose_name = _('currency')
|
||||||
|
|
@ -130,7 +44,6 @@ class SiteSettingsQuerySet(models.QuerySet):
|
||||||
|
|
||||||
|
|
||||||
class SiteSettings(ProjectBaseMixin):
|
class SiteSettings(ProjectBaseMixin):
|
||||||
|
|
||||||
subdomain = models.CharField(max_length=255, db_index=True, unique=True,
|
subdomain = models.CharField(max_length=255, db_index=True, unique=True,
|
||||||
verbose_name=_('Subdomain'))
|
verbose_name=_('Subdomain'))
|
||||||
country = models.OneToOneField(Country, on_delete=models.PROTECT,
|
country = models.OneToOneField(Country, on_delete=models.PROTECT,
|
||||||
|
|
@ -279,13 +192,41 @@ class AwardType(models.Model):
|
||||||
class CarouselQuerySet(models.QuerySet):
|
class CarouselQuerySet(models.QuerySet):
|
||||||
"""Carousel QuerySet."""
|
"""Carousel QuerySet."""
|
||||||
|
|
||||||
|
def is_parsed(self):
|
||||||
|
"""Parsed carousel objects."""
|
||||||
|
return self.filter(is_parse=True)
|
||||||
|
|
||||||
|
def active(self):
|
||||||
|
"""Active carousel objects."""
|
||||||
|
return self.filter(active=True)
|
||||||
|
|
||||||
|
def by_country_code(self, code):
|
||||||
|
"""Filter collection by country code."""
|
||||||
|
return self.filter(country__code=code)
|
||||||
|
|
||||||
|
|
||||||
class Carousel(models.Model):
|
class Carousel(models.Model):
|
||||||
"""Carousel model."""
|
"""Carousel model."""
|
||||||
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True, default=None)
|
||||||
object_id = models.PositiveIntegerField()
|
object_id = models.PositiveIntegerField(blank=True, null=True, default=None)
|
||||||
content_object = generic.GenericForeignKey('content_type', 'object_id')
|
content_object = generic.GenericForeignKey('content_type', 'object_id')
|
||||||
|
|
||||||
|
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
|
||||||
|
title = models.CharField(_('old title'), max_length=255, blank=True, null=True, default=None)
|
||||||
|
link = models.CharField(_('old link'), max_length=255, blank=True, null=True, default=None)
|
||||||
|
attachment_suffix_url = models.TextField(_('old attachment_suffix_url'), blank=True, null=True, default=None)
|
||||||
|
description = models.CharField(_('old description'), max_length=255, blank=True, null=True, default=None)
|
||||||
|
link_title = models.CharField(_('old link_title'), max_length=255, blank=True, null=True, default=None)
|
||||||
|
country = models.ForeignKey(
|
||||||
|
Country,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
verbose_name=_('country')
|
||||||
|
)
|
||||||
|
active = models.BooleanField(_('old active'), default=False)
|
||||||
|
is_parse = models.BooleanField(_('is parse'), default=False)
|
||||||
|
|
||||||
objects = CarouselQuerySet.as_manager()
|
objects = CarouselQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -325,6 +266,8 @@ class Carousel(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def image_url(self):
|
def image_url(self):
|
||||||
|
if self.attachment_suffix_url:
|
||||||
|
return f'https://s3.eu-central-1.amazonaws.com/gm-test.com/media/{self.attachment_suffix_url}'
|
||||||
if hasattr(self.content_object, 'image_url'):
|
if hasattr(self.content_object, 'image_url'):
|
||||||
return self.content_object.image_url
|
return self.content_object.image_url
|
||||||
|
|
||||||
|
|
@ -340,5 +283,12 @@ class Carousel(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model_name(self):
|
def model_name(self):
|
||||||
if hasattr(self.content_object, 'establishment_type'):
|
from establishment.models import Establishment
|
||||||
return self.content_object.establishment_type.name_translated
|
from news.models import News
|
||||||
|
if isinstance(self.content_object, Establishment):
|
||||||
|
return self.content_object.establishment_type.index_name
|
||||||
|
elif isinstance(self.content_object, News):
|
||||||
|
return self.content_type.model
|
||||||
|
elif self.link not in EMPTY_VALUES:
|
||||||
|
return 'external'
|
||||||
|
return None
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
||||||
country_code = serializers.CharField(source='subdomain', read_only=True)
|
country_code = serializers.CharField(source='subdomain', read_only=True)
|
||||||
|
|
||||||
country_name = serializers.CharField(source='country.name_translated', read_only=True)
|
country_name = serializers.CharField(source='country.name_translated', read_only=True)
|
||||||
|
time_format = serializers.CharField(source='country.time_format', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -71,6 +72,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
||||||
model = models.SiteSettings
|
model = models.SiteSettings
|
||||||
fields = (
|
fields = (
|
||||||
'country_code',
|
'country_code',
|
||||||
|
'time_format',
|
||||||
'subdomain',
|
'subdomain',
|
||||||
'pinterest_page_url',
|
'pinterest_page_url',
|
||||||
'twitter_page_url',
|
'twitter_page_url',
|
||||||
|
|
@ -81,7 +83,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
||||||
'ad_config',
|
'ad_config',
|
||||||
'published_features',
|
'published_features',
|
||||||
'currency',
|
'currency',
|
||||||
'country_name'
|
'country_name',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -135,6 +137,7 @@ class AwardSerializer(AwardBaseSerializer):
|
||||||
|
|
||||||
class CarouselListSerializer(serializers.ModelSerializer):
|
class CarouselListSerializer(serializers.ModelSerializer):
|
||||||
"""Serializer for retrieving list of carousel items."""
|
"""Serializer for retrieving list of carousel items."""
|
||||||
|
|
||||||
model_name = serializers.CharField()
|
model_name = serializers.CharField()
|
||||||
name = serializers.CharField()
|
name = serializers.CharField()
|
||||||
toque_number = serializers.IntegerField()
|
toque_number = serializers.IntegerField()
|
||||||
|
|
@ -158,6 +161,7 @@ class CarouselListSerializer(serializers.ModelSerializer):
|
||||||
'vintage_year',
|
'vintage_year',
|
||||||
'last_award',
|
'last_award',
|
||||||
'slug',
|
'slug',
|
||||||
|
'link',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,8 @@ card = {
|
||||||
"facebook_page_url": "facebook_page_url",
|
"facebook_page_url": "facebook_page_url",
|
||||||
"instagram_page_url": "instagram_page_url",
|
"instagram_page_url": "instagram_page_url",
|
||||||
"contact_email": "contact_email",
|
"contact_email": "contact_email",
|
||||||
"config": ("config", "django.db.models.JSONField") #TODO в качесте ключа использовать country_code_2 из legacy - ?
|
"config": ("config", "django.db.models.JSONField")
|
||||||
|
# TODO в качесте ключа использовать country_code_2 из legacy - ?
|
||||||
},
|
},
|
||||||
# "relations": {
|
# "relations": {
|
||||||
# # Как работать c отношение OneToOneField
|
# # Как работать c отношение OneToOneField
|
||||||
|
|
|
||||||
23
apps/main/transfer_data.py
Normal file
23
apps/main/transfer_data.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
from django.db.models import F
|
||||||
|
|
||||||
|
from transfer.models import CarouselElements
|
||||||
|
from transfer.serializers.carousel import CarouselSerializer
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_carousel():
|
||||||
|
queryset = CarouselElements.objects.all().annotate(
|
||||||
|
country=F('home_page__site__country_code_2'),
|
||||||
|
)
|
||||||
|
|
||||||
|
serialized_data = CarouselSerializer(data=list(queryset.values()), many=True)
|
||||||
|
if serialized_data.is_valid():
|
||||||
|
serialized_data.save()
|
||||||
|
else:
|
||||||
|
pprint(f'Carousel serializer errors: {serialized_data.errors}')
|
||||||
|
|
||||||
|
|
||||||
|
data_types = {
|
||||||
|
'whirligig': [transfer_carousel]
|
||||||
|
}
|
||||||
|
|
@ -61,11 +61,19 @@ class AwardRetrieveView(generics.RetrieveAPIView):
|
||||||
|
|
||||||
class CarouselListView(generics.ListAPIView):
|
class CarouselListView(generics.ListAPIView):
|
||||||
"""Return list of carousel items."""
|
"""Return list of carousel items."""
|
||||||
queryset = models.Carousel.objects.all()
|
|
||||||
|
queryset = models.Carousel.objects.is_parsed().active()
|
||||||
serializer_class = serializers.CarouselListSerializer
|
serializer_class = serializers.CarouselListSerializer
|
||||||
permission_classes = (permissions.AllowAny,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
pagination_class = None
|
pagination_class = None
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
country_code = self.request.country_code
|
||||||
|
qs = models.Carousel.objects.is_parsed().active()
|
||||||
|
if country_code:
|
||||||
|
qs = qs.by_country_code(country_code)
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class DetermineLocation(generics.GenericAPIView):
|
class DetermineLocation(generics.GenericAPIView):
|
||||||
"""Determine user's location."""
|
"""Determine user's location."""
|
||||||
|
|
|
||||||
35
apps/news/management/commands/add_news_tags.py
Normal file
35
apps/news/management/commands/add_news_tags.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from news.models import News, NewsType
|
||||||
|
from tag.models import Tag, TagCategory
|
||||||
|
from transfer.models import PageMetadata, Pages, PageTexts
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Remove old news from new bd'
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
count = 0
|
||||||
|
news_type, _ = NewsType.objects.get_or_create(name='News')
|
||||||
|
tag_cat, _ = TagCategory.objects.get_or_create(index_name='category')
|
||||||
|
news_type.tag_categories.add(tag_cat)
|
||||||
|
news_type.save()
|
||||||
|
|
||||||
|
old_news_tag = PageMetadata.objects.filter(key='category', page__pagetexts__isnull=False)
|
||||||
|
for old_tag in old_news_tag:
|
||||||
|
old_id_list = old_tag.page.pagetexts_set.all().values_list('id', flat=True)
|
||||||
|
|
||||||
|
# Make Tag
|
||||||
|
new_tag, created = Tag.objects.get_or_create(category=tag_cat, value=old_tag.value)
|
||||||
|
if created:
|
||||||
|
new_tag.label = {'en-GB': new_tag.value}
|
||||||
|
new_tag.save()
|
||||||
|
for id in old_id_list:
|
||||||
|
if isinstance(id, int):
|
||||||
|
news = News.objects.filter(old_id=id).first()
|
||||||
|
if news:
|
||||||
|
news.tags.add(new_tag)
|
||||||
|
news.save()
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
self.stdout.write(self.style.WARNING(f'Create or update {count} objects.'))
|
||||||
|
|
@ -7,6 +7,7 @@ from rest_framework.reverse import reverse
|
||||||
|
|
||||||
from rating.models import Rating
|
from rating.models import Rating
|
||||||
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin, ProjectBaseMixin
|
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin, ProjectBaseMixin
|
||||||
|
from utils.querysets import TranslationQuerysetMixin
|
||||||
|
|
||||||
|
|
||||||
class NewsType(models.Model):
|
class NewsType(models.Model):
|
||||||
|
|
@ -27,7 +28,7 @@ class NewsType(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class NewsQuerySet(models.QuerySet):
|
class NewsQuerySet(TranslationQuerysetMixin):
|
||||||
"""QuerySet for model News"""
|
"""QuerySet for model News"""
|
||||||
|
|
||||||
def rating_value(self):
|
def rating_value(self):
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ class NewsDetailWebSerializer(NewsDetailSerializer):
|
||||||
'same_theme',
|
'same_theme',
|
||||||
'should_read',
|
'should_read',
|
||||||
'agenda',
|
'agenda',
|
||||||
'banner'
|
'banner',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ class NewsMixinView:
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
"""Override get_queryset method."""
|
"""Override get_queryset method."""
|
||||||
|
|
||||||
qs = models.News.objects.published().with_base_related() \
|
qs = models.News.objects.published() \
|
||||||
|
.with_base_related() \
|
||||||
.order_by('-is_highlighted', '-created')
|
.order_by('-is_highlighted', '-created')
|
||||||
country_code = self.request.country_code
|
country_code = self.request.country_code
|
||||||
if country_code:
|
if country_code:
|
||||||
|
|
@ -36,7 +37,7 @@ class NewsMixinView:
|
||||||
qs = qs.by_country_code(country_code)
|
qs = qs.by_country_code(country_code)
|
||||||
else:
|
else:
|
||||||
qs = models.News.objects.filter(
|
qs = models.News.objects.filter(
|
||||||
id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS)
|
old_id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS)
|
||||||
return qs
|
return qs
|
||||||
# temp code
|
# temp code
|
||||||
|
|
||||||
|
|
|
||||||
18
apps/partner/migrations/0002_auto_20191101_0939.py
Normal file
18
apps/partner/migrations/0002_auto_20191101_0939.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-01 09:39
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('partner', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='partner',
|
||||||
|
name='image',
|
||||||
|
field=models.URLField(null=True, verbose_name='Partner image URL'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -4,9 +4,10 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from utils.models import ImageMixin, ProjectBaseMixin
|
from utils.models import ImageMixin, ProjectBaseMixin
|
||||||
|
|
||||||
|
|
||||||
class Partner(ProjectBaseMixin, ImageMixin):
|
class Partner(ProjectBaseMixin):
|
||||||
"""Partner model."""
|
"""Partner model."""
|
||||||
url = models.URLField(verbose_name=_('Partner URL'))
|
url = models.URLField(verbose_name=_('Partner URL'))
|
||||||
|
image = models.URLField(verbose_name=_('Partner image URL'), null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('partner')
|
verbose_name = _('partner')
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ from transfer.serializers.partner import PartnerSerializer
|
||||||
def transfer_partner():
|
def transfer_partner():
|
||||||
queryset = EstablishmentBacklinks.objects.filter(type="Partner")
|
queryset = EstablishmentBacklinks.objects.filter(type="Partner")
|
||||||
|
|
||||||
|
# queryset = EstablishmentBacklinks.objects.all() # Partner and Sponsor
|
||||||
|
|
||||||
serialized_data = PartnerSerializer(data=list(queryset.values()), many=True)
|
serialized_data = PartnerSerializer(data=list(queryset.values()), many=True)
|
||||||
if serialized_data.is_valid():
|
if serialized_data.is_valid():
|
||||||
serialized_data.save()
|
serialized_data.save()
|
||||||
|
|
|
||||||
29
apps/product/migrations/0003_auto_20191030_1315.py
Normal file
29
apps/product/migrations/0003_auto_20191030_1315.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-30 13:15
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0002_product_slug'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='product',
|
||||||
|
name='old_id',
|
||||||
|
field=models.IntegerField(blank=True, null=True, verbose_name='Product old id'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='product',
|
||||||
|
name='old_id_establishment',
|
||||||
|
field=models.IntegerField(blank=True, null=True, verbose_name='Establishment old id'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='establishment',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
|
||||||
|
),
|
||||||
|
]
|
||||||
33
apps/product/migrations/0004_auto_20191031_0923.py
Normal file
33
apps/product/migrations/0004_auto_20191031_0923.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 09:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0003_auto_20191030_1315'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='product',
|
||||||
|
name='old_id_establishment',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='establishment',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='old_id',
|
||||||
|
field=models.IntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='productsubtype',
|
||||||
|
name='index_name',
|
||||||
|
field=models.CharField(choices=[('rum', 'Rum'), ('other', 'Other'), ('extra brut', 'extra brut'), ('brut', 'brut'), ('brut nature', 'brut nature'), ('demi-sec', 'demi-sec'), ('Extra Dry', 'Extra Dry'), ('dosage zero', 'dosage zero'), ('sec', 'sec'), ('doux', 'doux'), ('moelleux', 'moelleux')], db_index=True, max_length=50, unique=True, verbose_name='Index name'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
apps/product/migrations/0005_auto_20191031_0929.py
Normal file
19
apps/product/migrations/0005_auto_20191031_0929.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 09:29
|
||||||
|
|
||||||
|
import django.contrib.postgres.fields.jsonb
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0004_auto_20191031_0923'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='characteristics',
|
||||||
|
field=django.contrib.postgres.fields.jsonb.JSONField(null=True, verbose_name='Characteristics'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
apps/product/migrations/0006_auto_20191031_0930.py
Normal file
19
apps/product/migrations/0006_auto_20191031_0930.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 09:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0005_auto_20191031_0929'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='establishment',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
|
||||||
|
),
|
||||||
|
]
|
||||||
29
apps/product/migrations/0007_auto_20191031_1408.py
Normal file
29
apps/product/migrations/0007_auto_20191031_1408.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 14:08
|
||||||
|
|
||||||
|
import django.contrib.postgres.fields.jsonb
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0006_auto_20191031_0930'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='product',
|
||||||
|
name='old_id',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='characteristics',
|
||||||
|
field=django.contrib.postgres.fields.jsonb.JSONField(verbose_name='Characteristics', null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='establishment',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
apps/product/migrations/0008_auto_20191031_1410.py
Normal file
19
apps/product/migrations/0008_auto_20191031_1410.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-10-31 14:10
|
||||||
|
|
||||||
|
import django.contrib.postgres.fields.jsonb
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('product', '0007_auto_20191031_1408'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='product',
|
||||||
|
name='characteristics',
|
||||||
|
field=django.contrib.postgres.fields.jsonb.JSONField(null=True, verbose_name='Characteristics'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -71,8 +71,10 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
|
||||||
]
|
]
|
||||||
|
|
||||||
search_fields = {
|
search_fields = {
|
||||||
'name': {'fuzziness': 'auto:3,4'},
|
'name': {'fuzziness': 'auto:3,4',
|
||||||
'name_translated': {'fuzziness': 'auto:3,4'},
|
'boost': '2'},
|
||||||
|
'name_translated': {'fuzziness': 'auto:3,4',
|
||||||
|
'boost': '2'},
|
||||||
'description': {'fuzziness': 'auto'},
|
'description': {'fuzziness': 'auto'},
|
||||||
}
|
}
|
||||||
translated_search_fields = (
|
translated_search_fields = (
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,13 @@ from .models import Tag, TagCategory
|
||||||
@admin.register(Tag)
|
@admin.register(Tag)
|
||||||
class TagAdmin(admin.ModelAdmin):
|
class TagAdmin(admin.ModelAdmin):
|
||||||
"""Admin model for model Tag."""
|
"""Admin model for model Tag."""
|
||||||
|
list_display = ['id', 'value', 'category']
|
||||||
|
list_display_links = ['id', 'value',]
|
||||||
|
list_filter = ['value']
|
||||||
|
|
||||||
|
|
||||||
@admin.register(TagCategory)
|
@admin.register(TagCategory)
|
||||||
class TagCategoryAdmin(admin.ModelAdmin):
|
class TagCategoryAdmin(admin.ModelAdmin):
|
||||||
"""Admin model for model TagCategory."""
|
"""Admin model for model TagCategory."""
|
||||||
|
list_display = ['id', 'index_name', ]
|
||||||
|
list_display_links = ['id', 'index_name', ]
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
"""Tag app filters."""
|
"""Tag app filters."""
|
||||||
from django_filters import rest_framework as filters
|
from django_filters import rest_framework as filters
|
||||||
from establishment.models import EstablishmentType
|
from establishment.models import EstablishmentType
|
||||||
|
from django.conf import settings
|
||||||
from tag import models
|
from tag import models
|
||||||
|
|
||||||
|
class TagsBaseFilterSet(filters.FilterSet):
|
||||||
class TagCategoryFilterSet(filters.FilterSet):
|
|
||||||
"""TagCategory filterset."""
|
|
||||||
|
|
||||||
# Object type choices
|
# Object type choices
|
||||||
NEWS = 'news'
|
NEWS = 'news'
|
||||||
|
|
@ -19,6 +18,18 @@ class TagCategoryFilterSet(filters.FilterSet):
|
||||||
type = filters.MultipleChoiceFilter(choices=TYPE_CHOICES,
|
type = filters.MultipleChoiceFilter(choices=TYPE_CHOICES,
|
||||||
method='filter_by_type')
|
method='filter_by_type')
|
||||||
|
|
||||||
|
|
||||||
|
def filter_by_type(self, queryset, name, value):
|
||||||
|
if self.NEWS in value:
|
||||||
|
queryset = queryset.for_news()
|
||||||
|
if self.ESTABLISHMENT in value:
|
||||||
|
queryset = queryset.for_establishments()
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class TagCategoryFilterSet(TagsBaseFilterSet):
|
||||||
|
"""TagCategory filterset."""
|
||||||
|
|
||||||
establishment_type = filters.ChoiceFilter(
|
establishment_type = filters.ChoiceFilter(
|
||||||
choices=EstablishmentType.INDEX_NAME_TYPES,
|
choices=EstablishmentType.INDEX_NAME_TYPES,
|
||||||
method='by_establishment_type')
|
method='by_establishment_type')
|
||||||
|
|
@ -30,13 +41,31 @@ class TagCategoryFilterSet(filters.FilterSet):
|
||||||
fields = ('type',
|
fields = ('type',
|
||||||
'establishment_type', )
|
'establishment_type', )
|
||||||
|
|
||||||
def filter_by_type(self, queryset, name, value):
|
|
||||||
if self.NEWS in value:
|
|
||||||
queryset = queryset.for_news()
|
|
||||||
if self.ESTABLISHMENT in value:
|
|
||||||
queryset = queryset.for_establishments()
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
# todo: filter by establishment type
|
# todo: filter by establishment type
|
||||||
def by_establishment_type(self, queryset, name, value):
|
def by_establishment_type(self, queryset, name, value):
|
||||||
return queryset.by_establishment_type(value)
|
return queryset.by_establishment_type(value)
|
||||||
|
|
||||||
|
|
||||||
|
class TagsFilterSet(TagsBaseFilterSet):
|
||||||
|
"""Chosen tags filterset."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class."""
|
||||||
|
|
||||||
|
model = models.Tag
|
||||||
|
fields = ('type',)
|
||||||
|
|
||||||
|
|
||||||
|
# TMP TODO remove it later
|
||||||
|
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
||||||
|
def filter_by_type(self, queryset, name, value):
|
||||||
|
""" Overrides base filter. Temporary decision"""
|
||||||
|
if not (settings.NEWS_CHOSEN_TAGS and settings.ESTABLISHMENT_CHOSEN_TAGS):
|
||||||
|
return super().filter_by_type(queryset, name, value)
|
||||||
|
queryset = models.Tag.objects
|
||||||
|
if self.NEWS in value:
|
||||||
|
queryset = queryset.for_news().filter(value__in=settings.NEWS_CHOSEN_TAGS).distinct('value')
|
||||||
|
if self.ESTABLISHMENT in value:
|
||||||
|
queryset = queryset.for_establishments().filter(value__in=settings.ESTABLISHMENT_CHOSEN_TAGS).distinct(
|
||||||
|
'value')
|
||||||
|
return queryset
|
||||||
|
|
@ -10,7 +10,9 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
def handle(self, *args, **kwargs):
|
def handle(self, *args, **kwargs):
|
||||||
|
|
||||||
existing_establishment = Establishment.objects.filter(old_id__isnull=False)
|
existing_establishment = Establishment.objects.filter(
|
||||||
|
old_id__isnull=False, tags__isnull=True
|
||||||
|
)
|
||||||
ESTABLISHMENT = 1
|
ESTABLISHMENT = 1
|
||||||
SHOP = 2
|
SHOP = 2
|
||||||
RESTAURANT = 3
|
RESTAURANT = 3
|
||||||
|
|
@ -52,18 +54,35 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
# create Tag
|
# create Tag
|
||||||
for tag in key_value.metadata_set.filter(
|
for tag in key_value.metadata_set.filter(
|
||||||
establishment__id__in=list(existing_establishment.values_list('old_id', flat=True))):
|
establishment__id__in=list(
|
||||||
|
existing_establishment.values_list('old_id', flat=True)
|
||||||
|
)):
|
||||||
|
|
||||||
new_tag, _ = Tag.objects.get_or_create(
|
new_tag, created = Tag.objects.get_or_create(
|
||||||
label={
|
|
||||||
'en-GB': tag.value,
|
|
||||||
'fr-FR': tag.value,
|
|
||||||
'ru-RU': tag.value,
|
|
||||||
},
|
|
||||||
value=tag.value,
|
value=tag.value,
|
||||||
category=tag_category,
|
category=tag_category,
|
||||||
)
|
)
|
||||||
est = existing_establishment.get(old_id=tag.establishment_id)
|
if created:
|
||||||
|
|
||||||
|
sp = tag.value.split('_')
|
||||||
|
value = ' '.join([sp[0].capitalize()] + sp[1:])
|
||||||
|
|
||||||
|
trans = {
|
||||||
|
'en-GB': value,
|
||||||
|
'fr-FR': value,
|
||||||
|
'ru-RU': value,
|
||||||
|
}
|
||||||
|
|
||||||
|
aliases = legacy.MetadatumAliases.objects.filter(value=tag.value)
|
||||||
|
|
||||||
|
for alias in aliases:
|
||||||
|
trans[alias.locale] = alias.meta_alias
|
||||||
|
|
||||||
|
new_tag.label = trans
|
||||||
|
new_tag.save()
|
||||||
|
|
||||||
|
est = existing_establishment.filter(
|
||||||
|
old_id=tag.establishment_id).first()
|
||||||
|
if est:
|
||||||
est.tags.add(new_tag)
|
est.tags.add(new_tag)
|
||||||
est.save()
|
est.save()
|
||||||
|
|
||||||
|
|
|
||||||
30
apps/tag/management/commands/add_tags_translation.py
Normal file
30
apps/tag/management/commands/add_tags_translation.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from establishment.models import Establishment, EstablishmentType
|
||||||
|
from transfer import models as legacy
|
||||||
|
from tag.models import Tag, TagCategory
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Add tags translation from old db to new db'
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
translation = legacy.MetadatumAliases.objects.all()
|
||||||
|
# Humanisation for default values
|
||||||
|
|
||||||
|
tags = Tag.objects.all()
|
||||||
|
for tag in tags:
|
||||||
|
value = tag.label
|
||||||
|
for k, v in value.items():
|
||||||
|
sp = v.split('_')
|
||||||
|
v = ' '.join([sp[0].capitalize()] + sp[1:])
|
||||||
|
tag.label[k] = v
|
||||||
|
tag.save()
|
||||||
|
|
||||||
|
for trans in translation:
|
||||||
|
tag = Tag.objects.filter(value=trans.value).first()
|
||||||
|
if tag:
|
||||||
|
tag.label.update(
|
||||||
|
{trans.locale: trans.meta_alias}
|
||||||
|
)
|
||||||
|
tag.save()
|
||||||
37
apps/tag/migrations/0008_auto_20191101_1244.py
Normal file
37
apps/tag/migrations/0008_auto_20191101_1244.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Generated by Django 2.2.4 on 2019-11-01 12:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('location', '0020_merge_20191030_1714'),
|
||||||
|
('tag', '0007_auto_20191030_1514'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='tag',
|
||||||
|
name='priority',
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ChosenTagSettings',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('priority', models.IntegerField(default=0)),
|
||||||
|
('country', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='location.Country')),
|
||||||
|
('tag', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tag.Tag')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Tag',
|
||||||
|
'verbose_name_plural': 'Tags',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='tag',
|
||||||
|
name='chosen_tag_settings',
|
||||||
|
field=models.ManyToManyField(through='tag.ChosenTagSettings', to='location.Country'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -1,16 +1,26 @@
|
||||||
"""Tag app models."""
|
"""Tag app models."""
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
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 location.models import Country
|
||||||
from utils.models import TJSONField, TranslatedFieldsMixin
|
from utils.models import TJSONField, TranslatedFieldsMixin
|
||||||
|
|
||||||
|
|
||||||
class TagQuerySet(models.QuerySet):
|
class TagQuerySet(models.QuerySet):
|
||||||
def filter_chosen(self):
|
|
||||||
return self.exclude(priority__isnull=True)
|
def for_news(self):
|
||||||
|
"""Select chosen tags for news."""
|
||||||
|
return self.filter(category__news_types__isnull=False)
|
||||||
|
|
||||||
|
def for_establishments(self):
|
||||||
|
"""Select chosen tags for establishments."""
|
||||||
|
return self.filter(models.Q(category__establishment_types__isnull=False) |
|
||||||
|
models.Q(category__establishment_subtypes__isnull=False))
|
||||||
|
|
||||||
def order_by_priority(self):
|
def order_by_priority(self):
|
||||||
return self.order_by('priority')
|
return self.order_by('chosentagsettings__priority')
|
||||||
|
|
||||||
|
|
||||||
class Tag(TranslatedFieldsMixin, models.Model):
|
class Tag(TranslatedFieldsMixin, models.Model):
|
||||||
|
|
@ -24,7 +34,8 @@ class Tag(TranslatedFieldsMixin, models.Model):
|
||||||
category = models.ForeignKey('TagCategory', on_delete=models.CASCADE,
|
category = models.ForeignKey('TagCategory', on_delete=models.CASCADE,
|
||||||
null=True, related_name='tags',
|
null=True, related_name='tags',
|
||||||
verbose_name=_('Category'))
|
verbose_name=_('Category'))
|
||||||
priority = models.IntegerField(unique=True, null=True, default=None)
|
|
||||||
|
chosen_tag_settings = models.ManyToManyField(Country, through='ChosenTagSettings')
|
||||||
|
|
||||||
objects = TagQuerySet.as_manager()
|
objects = TagQuerySet.as_manager()
|
||||||
|
|
||||||
|
|
@ -35,11 +46,29 @@ class Tag(TranslatedFieldsMixin, models.Model):
|
||||||
verbose_name_plural = _('Tags')
|
verbose_name_plural = _('Tags')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
label = 'None'
|
return f'Tag (id = {self.id}, label_translated = {self.label_translated})'
|
||||||
lang = TranslationSettings.get_solo().default_language
|
|
||||||
if self.label and lang in self.label:
|
|
||||||
label = self.label[lang]
|
class ChosenTagSettingsQuerySet(models.QuerySet):
|
||||||
return f'id:{self.id}-{label}'
|
|
||||||
|
def by_country_code(self, country_code):
|
||||||
|
return self.filter(country__code=country_code)
|
||||||
|
|
||||||
|
|
||||||
|
class ChosenTagSettings(models.Model):
|
||||||
|
"""Tag model."""
|
||||||
|
|
||||||
|
tag = models.ForeignKey(Tag, on_delete=models.PROTECT)
|
||||||
|
country = models.ForeignKey(Country, on_delete=models.PROTECT)
|
||||||
|
priority = models.IntegerField(null=False, default=0)
|
||||||
|
|
||||||
|
objects = ChosenTagSettingsQuerySet.as_manager()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class."""
|
||||||
|
|
||||||
|
verbose_name = _('Tag')
|
||||||
|
verbose_name_plural = _('Tags')
|
||||||
|
|
||||||
|
|
||||||
class TagCategoryQuerySet(models.QuerySet):
|
class TagCategoryQuerySet(models.QuerySet):
|
||||||
|
|
@ -55,7 +84,7 @@ class TagCategoryQuerySet(models.QuerySet):
|
||||||
|
|
||||||
def for_news(self):
|
def for_news(self):
|
||||||
"""Select tag categories for news."""
|
"""Select tag categories for news."""
|
||||||
return self.filter(news_types__isnull=True)
|
return self.filter(news_types__isnull=False)
|
||||||
|
|
||||||
def for_establishments(self):
|
def for_establishments(self):
|
||||||
"""Select tag categories for establishments."""
|
"""Select tag categories for establishments."""
|
||||||
|
|
@ -106,8 +135,4 @@ class TagCategory(TranslatedFieldsMixin, models.Model):
|
||||||
verbose_name_plural = _('Tag categories')
|
verbose_name_plural = _('Tag categories')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
label = 'None'
|
return self.index_name
|
||||||
lang = TranslationSettings.get_solo().default_language
|
|
||||||
if self.label and lang in self.label:
|
|
||||||
label = self.label[lang]
|
|
||||||
return f'id:{self.id}-{label}'
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ from utils.serializers import TranslatedField
|
||||||
class TagBaseSerializer(serializers.ModelSerializer):
|
class TagBaseSerializer(serializers.ModelSerializer):
|
||||||
"""Serializer for model Tag."""
|
"""Serializer for model Tag."""
|
||||||
|
|
||||||
# todo: refactor this
|
label_translated = TranslatedField()
|
||||||
# label_translated = TranslatedField()
|
# label_translated = serializers.CharField(source='value', read_only=True, allow_null=True)
|
||||||
label_translated = serializers.CharField(source='value', read_only=True, allow_null=True)
|
index_name = serializers.CharField(source='value', read_only=True, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -23,6 +23,7 @@ class TagBaseSerializer(serializers.ModelSerializer):
|
||||||
fields = (
|
fields = (
|
||||||
'id',
|
'id',
|
||||||
'label_translated',
|
'label_translated',
|
||||||
|
'index_name',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ app_name = 'tag'
|
||||||
|
|
||||||
router = SimpleRouter()
|
router = SimpleRouter()
|
||||||
router.register(r'categories', views.TagCategoryViewSet)
|
router.register(r'categories', views.TagCategoryViewSet)
|
||||||
router.register(r'chosen_tags', views.ChosenTagsView, basename='Tag')
|
router.register(r'chosen_tags', views.ChosenTagsView)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,45 @@
|
||||||
"""Tag views."""
|
"""Tag views."""
|
||||||
|
from django.conf import settings
|
||||||
|
from rest_framework import permissions
|
||||||
from rest_framework import viewsets, mixins, status, generics
|
from rest_framework import viewsets, mixins, status, generics
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from tag import filters, models, serializers
|
from tag import filters, models, serializers
|
||||||
from rest_framework import permissions
|
|
||||||
|
|
||||||
|
|
||||||
class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet):
|
class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet):
|
||||||
pagination_class = None
|
pagination_class = None
|
||||||
permission_classes = (permissions.AllowAny,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
serializer_class = serializers.TagBaseSerializer
|
serializer_class = serializers.TagBaseSerializer
|
||||||
|
filterset_class = filters.TagsFilterSet
|
||||||
|
queryset = models.Tag.objects.all()
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
result_tags_ids = models.ChosenTagSettings.objects \
|
||||||
|
.by_country_code(self.request.country_code) \
|
||||||
|
.values('tag_id')
|
||||||
return models.Tag.objects \
|
return models.Tag.objects \
|
||||||
.filter_chosen() \
|
.filter(id__in=result_tags_ids) \
|
||||||
.order_by_priority()
|
.order_by_priority()
|
||||||
|
|
||||||
|
def list(self, request, *args, **kwargs):
|
||||||
|
# TMP TODO remove it later
|
||||||
|
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
||||||
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
|
|
||||||
|
page = self.paginate_queryset(queryset)
|
||||||
|
if page is not None:
|
||||||
|
serializer = self.get_serializer(page, many=True)
|
||||||
|
return self.get_paginated_response(serializer.data)
|
||||||
|
|
||||||
|
serializer = self.get_serializer(queryset, many=True)
|
||||||
|
result_list = serializer.data
|
||||||
|
if request.query_params.get('type') and (settings.ESTABLISHMENT_CHOSEN_TAGS or settings.NEWS_CHOSEN_TAGS):
|
||||||
|
ordered_list = settings.ESTABLISHMENT_CHOSEN_TAGS if request.query_params.get('type') == 'establishment' else settings.NEWS_CHOSEN_TAGS
|
||||||
|
result_list = sorted(result_list, key=lambda x: ordered_list.index(x['index_name']))
|
||||||
|
return Response(result_list)
|
||||||
|
|
||||||
|
|
||||||
# User`s views & viewsets
|
# User`s views & viewsets
|
||||||
class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ class Command(BaseCommand):
|
||||||
"""Типы данных для трансфера
|
"""Типы данных для трансфера
|
||||||
ВНИМАНИЕ: первые буквы типов данных должны быть уникальны!
|
ВНИМАНИЕ: первые буквы типов данных должны быть уникальны!
|
||||||
"""
|
"""
|
||||||
DATA_TYPES = [
|
SHORT_DATA_TYPES = [
|
||||||
'dictionaries',
|
'dictionaries',
|
||||||
'news',
|
'news',
|
||||||
'account',
|
'account',
|
||||||
|
|
@ -22,20 +22,39 @@ class Command(BaseCommand):
|
||||||
'tmp',
|
'tmp',
|
||||||
'menu',
|
'menu',
|
||||||
'location_establishment',
|
'location_establishment',
|
||||||
'wine_color',
|
'whirligig',
|
||||||
|
]
|
||||||
|
|
||||||
|
LONG_DATA_TYPES = [
|
||||||
|
'update_country_flag',
|
||||||
]
|
]
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
"""Находим включённую опцию путём пересечения множества типов данных и множества включённых опций"""
|
"""Находим включённую опцию путём пересечения множества типов данных и множества включённых опций"""
|
||||||
data_type = list(set(option for option in options.keys() if options[option]) & set(self.DATA_TYPES))
|
data_type = list(set(option for option in options.keys() if options[option]) & set(self.LONG_DATA_TYPES))
|
||||||
|
if len(data_type) != 1:
|
||||||
|
data_type = list(set(option for option in options.keys() if options[option]) & set(self.SHORT_DATA_TYPES))
|
||||||
if len(data_type) != 1:
|
if len(data_type) != 1:
|
||||||
print("You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n")
|
print("You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n")
|
||||||
exit(1)
|
exit(1)
|
||||||
transfer_objects(data_type[0])
|
else:
|
||||||
|
data_type = data_type[0]
|
||||||
|
else:
|
||||||
|
data_type = data_type[0]
|
||||||
|
|
||||||
|
transfer_objects(data_type)
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
|
for option_type in self.LONG_DATA_TYPES:
|
||||||
|
parser.add_argument(
|
||||||
|
f'--{option_type}',
|
||||||
|
action='store_true',
|
||||||
|
default=False,
|
||||||
|
help=f'Transfer {option_type} objects'
|
||||||
|
)
|
||||||
|
|
||||||
"""Добавляем опции к команде, основываясь на типах данных, определённых в DATA_TYPES"""
|
"""Добавляем опции к команде, основываясь на типах данных, определённых в DATA_TYPES"""
|
||||||
for option_type in self.DATA_TYPES:
|
for option_type in self.SHORT_DATA_TYPES:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
f'-{option_type[:1]}',
|
f'-{option_type[:1]}',
|
||||||
f'--{option_type}',
|
f'--{option_type}',
|
||||||
|
|
|
||||||
|
|
@ -553,6 +553,7 @@ class EstablishmentInfos(MigrateMixin):
|
||||||
website = models.CharField(max_length=255, blank=True, null=True)
|
website = models.CharField(max_length=255, blank=True, null=True)
|
||||||
facebook = models.CharField(max_length=255, blank=True, null=True)
|
facebook = models.CharField(max_length=255, blank=True, null=True)
|
||||||
twitter = models.CharField(max_length=255, blank=True, null=True)
|
twitter = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
instagram = models.TextField(blank=True, null=True)
|
||||||
lafourchette = models.CharField(max_length=255, blank=True, null=True)
|
lafourchette = models.CharField(max_length=255, blank=True, null=True)
|
||||||
pub = models.IntegerField(blank=True, null=True)
|
pub = models.IntegerField(blank=True, null=True)
|
||||||
created_at = models.DateTimeField()
|
created_at = models.DateTimeField()
|
||||||
|
|
@ -967,3 +968,51 @@ class WineTypes(MigrateMixin):
|
||||||
# class Meta:
|
# class Meta:
|
||||||
# managed = False
|
# managed = False
|
||||||
# db_table = 'products'
|
# db_table = 'products'
|
||||||
|
|
||||||
|
class HomePages(models.Model):
|
||||||
|
using = 'legacy'
|
||||||
|
|
||||||
|
site = models.ForeignKey(Sites, models.DO_NOTHING, blank=True, null=True)
|
||||||
|
selection_of_week = models.IntegerField(blank=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'home_pages'
|
||||||
|
|
||||||
|
|
||||||
|
class CarouselElements(MigrateMixin):
|
||||||
|
using = 'legacy'
|
||||||
|
|
||||||
|
title = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
link = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
home_page = models.ForeignKey(HomePages, models.DO_NOTHING, blank=True, null=True)
|
||||||
|
created_at = models.DateTimeField()
|
||||||
|
updated_at = models.DateTimeField()
|
||||||
|
attachment_file_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
attachment_content_type = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
attachment_file_size = models.IntegerField(blank=True, null=True)
|
||||||
|
attachment_updated_at = models.DateTimeField(blank=True, null=True)
|
||||||
|
attachment_suffix_url = models.TextField(blank=True, null=True)
|
||||||
|
geometries = models.CharField(max_length=1024, blank=True, null=True)
|
||||||
|
active = models.IntegerField(blank=True, null=True)
|
||||||
|
description = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
link_title = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'carousel_elements'
|
||||||
|
|
||||||
|
|
||||||
|
class MetadatumAliases(MigrateMixin):
|
||||||
|
"""MetadatumAliases model."""
|
||||||
|
using = 'legacy'
|
||||||
|
|
||||||
|
meta_alias = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
value = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
locale = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
created_at = models.DateTimeField()
|
||||||
|
updated_at = models.DateTimeField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'metadatum_aliases'
|
||||||
|
|
|
||||||
68
apps/transfer/serializers/carousel.py
Normal file
68
apps/transfer/serializers/carousel.py
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from establishment.models import Establishment
|
||||||
|
from location.models import Country
|
||||||
|
from main.models import Carousel
|
||||||
|
from news.models import News
|
||||||
|
|
||||||
|
|
||||||
|
def get_obj_data(model, slug):
|
||||||
|
try:
|
||||||
|
obj = model.objects.get(slug=slug)
|
||||||
|
except model.DoesNotExist:
|
||||||
|
return None, None
|
||||||
|
else:
|
||||||
|
content_type = ContentType.objects.get_for_model(obj)
|
||||||
|
return obj.id, content_type.id
|
||||||
|
|
||||||
|
|
||||||
|
class CarouselSerializer(serializers.Serializer):
|
||||||
|
id = serializers.IntegerField()
|
||||||
|
title = serializers.CharField(allow_null=True, allow_blank=True)
|
||||||
|
link = serializers.CharField(allow_null=True)
|
||||||
|
link_title = serializers.CharField(allow_null=True, allow_blank=True)
|
||||||
|
description = serializers.CharField(allow_null=True, allow_blank=True)
|
||||||
|
attachment_suffix_url = serializers.CharField(allow_null=True)
|
||||||
|
active = serializers.IntegerField()
|
||||||
|
country = serializers.CharField(allow_null=True)
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
object_id, content_type_id = self.get_content_type(validated_data)
|
||||||
|
validated_data.update({
|
||||||
|
'old_id': validated_data['id'],
|
||||||
|
'country': self.get_country(validated_data),
|
||||||
|
'active': bool(int(validated_data['active'])),
|
||||||
|
'content_type_id': content_type_id,
|
||||||
|
'object_id': object_id,
|
||||||
|
'is_parse': bool(object_id),
|
||||||
|
})
|
||||||
|
validated_data.pop('id')
|
||||||
|
obj, _ = Carousel.objects.update_or_create(**validated_data)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_country(data):
|
||||||
|
return Country.objects.filter(code__iexact=data['country']).first()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_content_type(data):
|
||||||
|
link = data['link']
|
||||||
|
if not link:
|
||||||
|
return None
|
||||||
|
|
||||||
|
obj_data = None, None
|
||||||
|
site = 'gaultmillau.com'
|
||||||
|
if site in link:
|
||||||
|
data = link.split('/')
|
||||||
|
|
||||||
|
try:
|
||||||
|
_type = data[3]
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if _type in ('news', 'pages'):
|
||||||
|
obj_data = get_obj_data(News, data[4])
|
||||||
|
elif _type == 'restaurant':
|
||||||
|
obj_data = get_obj_data(Establishment, data[4])
|
||||||
|
return obj_data
|
||||||
|
|
@ -95,7 +95,6 @@ class EstablishmentSerializer(serializers.ModelSerializer):
|
||||||
if address:
|
if address:
|
||||||
return address.id
|
return address.id
|
||||||
return None
|
return None
|
||||||
# return None
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_type(data):
|
def get_type(data):
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ class RegionSerializer(serializers.ModelSerializer):
|
||||||
print(data)
|
print(data)
|
||||||
if "subregion_code" in data and data["subregion_code"] is not None and data["subregion_code"].strip() != "":
|
if "subregion_code" in data and data["subregion_code"] is not None and data["subregion_code"].strip() != "":
|
||||||
try:
|
try:
|
||||||
parent_region = Region.objects.get(code=str(data['region_code']))
|
parent_region = Region.objects.filter(code=str(data['region_code'])).first()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError(f"Parent region error with {data}: {e}")
|
raise ValueError(f"Parent region error with {data}: {e}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,80 @@ from partner.models import Partner
|
||||||
|
|
||||||
class PartnerSerializer(serializers.ModelSerializer):
|
class PartnerSerializer(serializers.ModelSerializer):
|
||||||
backlink_url = serializers.CharField(source="url")
|
backlink_url = serializers.CharField(source="url")
|
||||||
|
partnership_icon = serializers.CharField()
|
||||||
|
partnership_name = serializers.CharField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Partner
|
model = Partner
|
||||||
fields = (
|
fields = (
|
||||||
"backlink_url",
|
"backlink_url",
|
||||||
|
"partnership_icon",
|
||||||
|
"partnership_name"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
data["image"] = partnership_to_image_url.get(data["partnership_name"]).get(data["partnership_icon"])
|
||||||
|
data.pop("partnership_name")
|
||||||
|
data.pop("partnership_icon")
|
||||||
|
return data
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
return Partner.objects.create(**validated_data)
|
return Partner.objects.create(**validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
partnership_to_image_url = {
|
||||||
|
# partnership_name
|
||||||
|
"tables-auberges": {
|
||||||
|
# partnership_icon
|
||||||
|
"Table Gastronomique":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Table Gastronomique-c1908231742bc0d0909c03cdac723c1daa3ee620134e8a6fbfae78efdaab8263.png",
|
||||||
|
"Bistrot Gourmand":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Bistrot Gourmand-fdf0527d8ed05d9c7d26456e531301325582f04e1f8e5d4c283ee4eac367dba1.png",
|
||||||
|
"Auberges de Village":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Auberges de Village-39aab1bbc678a6a5f7e0a2c9b8565bb6d21b01294371533580cdff0d9aa80da0.png",
|
||||||
|
"Table de Prestige":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Table de Prestige-6bf4ab0fcc56d89ffc97cc71553f0b1d21b92f4b5ef7656b832ab03e5c6ff31c.png",
|
||||||
|
"Table de Terroir":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Table de Terroir-e72a35a60c4a4575c162398d7355fc77787f368ff240ff8725dc24a37a497be7.png"
|
||||||
|
},
|
||||||
|
"riedel": {
|
||||||
|
"riedel":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/riedel/riedel-1fe0fa8298ae76d0a2de6e00316d2dd4357cace659cc0398629ae4c117bd114e.png"
|
||||||
|
},
|
||||||
|
"lavazza": {
|
||||||
|
"lavazza":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/lavazza/lavazza-9a013b9f954dd63ba871019a1fcd55ea5cb84b38ab2dbff47ee9464f671195bb.png"
|
||||||
|
},
|
||||||
|
"kaviari": {
|
||||||
|
"Kaviari Paris":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/kaviari/Kaviari Paris-e6c4fe81a1d5257854f9b8e28cb244b01a9129ed01056cb98e809f70ec7b5fcf.png"
|
||||||
|
},
|
||||||
|
"mutti": {
|
||||||
|
"mutti":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mutti/mutti-86f8514b03e096b8e6843e8885756d311486c461a5b8c4f2f10f75995b146814.png"
|
||||||
|
},
|
||||||
|
"nespresso": {
|
||||||
|
"nespresso":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/nespresso/nespresso-c401e553731c68a364754fe512f25889398d42f98bf8edbe1233695b546d1c5d.png"
|
||||||
|
},
|
||||||
|
"le-manoir": {
|
||||||
|
"le-manoir":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/le-manoir/le-manoir-d6a616bebca2948c147ed7c58d9883682ee2d4a3779dea98e9d1a94f17e14771.png"
|
||||||
|
},
|
||||||
|
"discovery-cheque": {
|
||||||
|
"discovery-cheque":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/discovery-cheque/discovery-cheque-665a3c60d3d6302897863b90245f405979760a27bea06c98aa4130b2c61276fb.png"
|
||||||
|
},
|
||||||
|
"mineralwater-selters": {
|
||||||
|
"Mineral Water Selters":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mineralwater-selters/Mineral Water Selters-2bac82327955c4357b51feff50bd6a2466705f85cb8e59875cb0192a161fd1d4.png"
|
||||||
|
},
|
||||||
|
"mineral-water-acquamorelli": {
|
||||||
|
"Mineral Water Acqua Morelli":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mineral-water-acquamorelli/Mineral Water Acqua Morelli-4032ba6b4da7f79dcf005809423fc663cfb49199d6ce95f3cfe99a7705359ac4.png"
|
||||||
|
},
|
||||||
|
"mastercard-maestro": {
|
||||||
|
"MastercardMaestro":
|
||||||
|
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mastercard-maestro/MastercardMaestro-718680bc48d98c4a7417a14a62e4ba2d3af980361256739d980e7b453552b5d8.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ def transfer_objects(data_type):
|
||||||
for app in apps.get_app_configs():
|
for app in apps.get_app_configs():
|
||||||
if exists(f"{app.path}/transfer_data.py"):
|
if exists(f"{app.path}/transfer_data.py"):
|
||||||
card_module = SourceFileLoader("transfer", f"{app.path}/transfer_data.py").load_module()
|
card_module = SourceFileLoader("transfer", f"{app.path}/transfer_data.py").load_module()
|
||||||
if not hasattr(card_module, "data_types") or not isinstance(card_module.data_types, dict) or len(card_module.data_types) < 1:
|
if not hasattr(card_module, "data_types") \
|
||||||
|
or not isinstance(card_module.data_types, dict) \
|
||||||
|
or len(card_module.data_types) < 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for module_data_type, transfer_funcs in card_module.data_types.items():
|
for module_data_type, transfer_funcs in card_module.data_types.items():
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ from django.http.request import HttpRequest
|
||||||
from django.utils.timezone import datetime
|
from django.utils.timezone import datetime
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from os.path import exists
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -64,7 +63,7 @@ def image_path(instance, filename):
|
||||||
def svg_image_path(instance, filename):
|
def svg_image_path(instance, filename):
|
||||||
"""Determine SVG path method."""
|
"""Determine SVG path method."""
|
||||||
filename = '%s.svg' % generate_code()
|
filename = '%s.svg' % generate_code()
|
||||||
return 'image/svg/%s/%s/%s' % (
|
return 'svg/%s/%s/%s' % (
|
||||||
instance._meta.model_name,
|
instance._meta.model_name,
|
||||||
datetime.now().strftime(settings.REST_DATE_FORMAT),
|
datetime.now().strftime(settings.REST_DATE_FORMAT),
|
||||||
filename)
|
filename)
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,8 @@ def translate_field(self, field_name):
|
||||||
# fallback
|
# fallback
|
||||||
if value is None:
|
if value is None:
|
||||||
value = field.get(get_default_locale())
|
value = field.get(get_default_locale())
|
||||||
|
if value is None:
|
||||||
|
value = field.get(next(iter(field.keys()), None))
|
||||||
return value
|
return value
|
||||||
return None
|
return None
|
||||||
return translate
|
return translate
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from django.db import models
|
||||||
from django.db.models import Q, F
|
from django.db.models import Q, F
|
||||||
|
|
||||||
from utils.methods import get_contenttype
|
from utils.methods import get_contenttype
|
||||||
|
from utils.models import TJSONField
|
||||||
|
|
||||||
|
|
||||||
class ContentTypeQuerySetMixin(models.QuerySet):
|
class ContentTypeQuerySetMixin(models.QuerySet):
|
||||||
|
|
@ -56,3 +57,24 @@ class RelatedObjectsCountMixin(models.QuerySet):
|
||||||
return self._annotate_related_objects_count()\
|
return self._annotate_related_objects_count()\
|
||||||
.annotate(all_related_count=exp)\
|
.annotate(all_related_count=exp)\
|
||||||
.filter(all_related_count__gt=count)
|
.filter(all_related_count__gt=count)
|
||||||
|
|
||||||
|
|
||||||
|
class TranslationQuerysetMixin(models.QuerySet):
|
||||||
|
|
||||||
|
def _get_translatable_fields(self):
|
||||||
|
"""Get translatable fields from model."""
|
||||||
|
translatable_fields = []
|
||||||
|
model = self.model
|
||||||
|
for field in model._meta.fields:
|
||||||
|
field_name = field.name
|
||||||
|
if isinstance(field, TJSONField):
|
||||||
|
translatable_fields.append(field_name)
|
||||||
|
return translatable_fields
|
||||||
|
|
||||||
|
def _get_translatable_field_filters(self, locale: str):
|
||||||
|
"""Generate filters for filtering TJSON objects that has necessary locale."""
|
||||||
|
return {f'{field}__has_key': locale for field in self._get_translatable_fields()}
|
||||||
|
|
||||||
|
def has_translation(self, locale: str):
|
||||||
|
"""Filter objects by locale from request."""
|
||||||
|
return self.filter(**self._get_translatable_field_filters(locale))
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ PROJECT_APPS = [
|
||||||
'comment.apps.CommentConfig',
|
'comment.apps.CommentConfig',
|
||||||
'favorites.apps.FavoritesConfig',
|
'favorites.apps.FavoritesConfig',
|
||||||
'rating.apps.RatingConfig',
|
'rating.apps.RatingConfig',
|
||||||
'transfer.apps.TransferConfig',
|
# 'transfer.apps.TransferConfig',
|
||||||
'tag.apps.TagConfig',
|
'tag.apps.TagConfig',
|
||||||
'product.apps.ProductConfig',
|
'product.apps.ProductConfig',
|
||||||
]
|
]
|
||||||
|
|
@ -157,16 +157,16 @@ DATABASES = {
|
||||||
'HOST': os.environ.get('DB_HOSTNAME'),
|
'HOST': os.environ.get('DB_HOSTNAME'),
|
||||||
'PORT': os.environ.get('DB_PORT'),
|
'PORT': os.environ.get('DB_PORT'),
|
||||||
},
|
},
|
||||||
'legacy': {
|
# 'legacy': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
# 'ENGINE': 'django.db.backends.mysql',
|
||||||
'HOST': '172.17.0.1',
|
# # 'HOST': '172.17.0.1',
|
||||||
# 'HOST': '172.23.0.1',
|
# # 'HOST': '172.23.0.1',
|
||||||
# 'HOST': 'mysql_db',
|
# 'HOST': 'mysql_db',
|
||||||
'PORT': 3306,
|
# 'PORT': 3306,
|
||||||
'NAME': 'dev',
|
# 'NAME': 'dev',
|
||||||
'USER': 'dev',
|
# 'USER': 'dev',
|
||||||
'PASSWORD': 'octosecret123'
|
# 'PASSWORD': 'octosecret123'
|
||||||
}
|
# }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -262,8 +262,8 @@ OAUTH2_SOCIAL_AUTH_GRANT_TYPE = 'convert_token'
|
||||||
OAUTH2_PROVIDER_APPLICATION_MODEL = 'authorization.Application'
|
OAUTH2_PROVIDER_APPLICATION_MODEL = 'authorization.Application'
|
||||||
|
|
||||||
# Facebook configuration
|
# Facebook configuration
|
||||||
SOCIAL_AUTH_FACEBOOK_KEY = '386843648701452'
|
SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get('FB_APPLICATION_ID')
|
||||||
SOCIAL_AUTH_FACEBOOK_SECRET = 'a71cf0bf3980843a8f1ea74c6d805fd7'
|
SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get('FB_PRIVATE_KEY')
|
||||||
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', ]
|
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', ]
|
||||||
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
|
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
|
||||||
'fields': 'id, name, email',
|
'fields': 'id, name, email',
|
||||||
|
|
@ -490,3 +490,8 @@ PHONENUMBER_DB_FORMAT = 'NATIONAL'
|
||||||
PHONENUMBER_DEFAULT_REGION = "FR"
|
PHONENUMBER_DEFAULT_REGION = "FR"
|
||||||
|
|
||||||
FALLBACK_LOCALE = 'en-GB'
|
FALLBACK_LOCALE = 'en-GB'
|
||||||
|
|
||||||
|
# TMP TODO remove it later
|
||||||
|
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
||||||
|
ESTABLISHMENT_CHOSEN_TAGS = ['gastronomic', 'en_vogue', 'terrace', 'streetfood', 'business', 'bar_cocktail', 'brunch', 'pop']
|
||||||
|
NEWS_CHOSEN_TAGS = ['eat', 'drink', 'cook', 'style', 'international', 'event', 'partnership']
|
||||||
|
|
@ -6,6 +6,8 @@ from sentry_sdk.integrations.django import DjangoIntegration
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['gm.id-east.ru', '95.213.204.126', '0.0.0.0']
|
ALLOWED_HOSTS = ['gm.id-east.ru', '95.213.204.126', '0.0.0.0']
|
||||||
|
|
||||||
|
CSRF_TRUSTED_ORIGINS = ['.gm.id-east.ru', ]
|
||||||
|
|
||||||
SEND_SMS = False
|
SEND_SMS = False
|
||||||
SMS_CODE_SHOW = True
|
SMS_CODE_SHOW = True
|
||||||
USE_CELERY = True
|
USE_CELERY = True
|
||||||
|
|
@ -38,7 +40,7 @@ sentry_sdk.init(
|
||||||
|
|
||||||
# TMP ( TODO remove it later)
|
# TMP ( TODO remove it later)
|
||||||
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
||||||
HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17]
|
HARDCODED_INTERNATIONAL_NEWS_IDS = [1460, 1471, 1482, 1484, 1611, 1612]
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||||
|
|
@ -52,12 +54,16 @@ DATABASES = {
|
||||||
'HOST': os.environ.get('DB_HOSTNAME'),
|
'HOST': os.environ.get('DB_HOSTNAME'),
|
||||||
'PORT': os.environ.get('DB_PORT'),
|
'PORT': os.environ.get('DB_PORT'),
|
||||||
},
|
},
|
||||||
'legacy': {
|
# 'legacy': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
# 'ENGINE': 'django.db.backends.mysql',
|
||||||
'HOST': os.environ.get('MYSQL_HOSTNAME'),
|
# 'HOST': os.environ.get('MYSQL_HOSTNAME'),
|
||||||
'PORT': os.environ.get('MYSQL_PORT'),
|
# 'PORT': os.environ.get('MYSQL_PORT'),
|
||||||
'NAME': os.environ.get('MYSQL_DATABASE'),
|
# 'NAME': os.environ.get('MYSQL_DATABASE'),
|
||||||
'USER': os.environ.get('MYSQL_USER'),
|
# 'USER': os.environ.get('MYSQL_USER'),
|
||||||
'PASSWORD': os.environ.get('MYSQL_PASSWORD')
|
# 'PASSWORD': os.environ.get('MYSQL_PASSWORD')
|
||||||
}
|
# }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BROKER_URL = 'redis://localhost:6379/1'
|
||||||
|
CELERY_RESULT_BACKEND = BROKER_URL
|
||||||
|
CELERY_BROKER_URL = BROKER_URL
|
||||||
|
|
@ -1,6 +1,63 @@
|
||||||
"""Production settings."""
|
"""Production settings."""
|
||||||
from .base import *
|
from .base import *
|
||||||
from .amazon_s3 import *
|
from .amazon_s3 import *
|
||||||
|
import sentry_sdk
|
||||||
|
from sentry_sdk.integrations.django import DjangoIntegration
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['*.next.gaultmillau.com', 'api.gaultmillau.com']
|
||||||
|
|
||||||
|
CSRF_TRUSTED_ORIGINS = ['.next.gaultmillau.com', ]
|
||||||
|
|
||||||
|
SEND_SMS = False
|
||||||
|
SMS_CODE_SHOW = True
|
||||||
|
USE_CELERY = True
|
||||||
|
|
||||||
|
SCHEMA_URI = 'http'
|
||||||
|
DEFAULT_SUBDOMAIN = 'www'
|
||||||
|
SITE_DOMAIN_URI = 'gaultmillau.com'
|
||||||
|
DOMAIN_URI = 'next.gaultmillau.com'
|
||||||
|
|
||||||
|
|
||||||
|
# ELASTICSEARCH SETTINGS
|
||||||
|
ELASTICSEARCH_DSL = {
|
||||||
|
'default': {
|
||||||
|
'hosts': 'elasticsearch:9200'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ELASTICSEARCH_INDEX_NAMES = {
|
||||||
|
'search_indexes.documents.news': 'development_news', # temporarily disabled
|
||||||
|
'search_indexes.documents.establishment': 'development_establishment',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn="https://35d9bb789677410ab84a822831c6314f@sentry.io/1729093",
|
||||||
|
integrations=[DjangoIntegration()]
|
||||||
|
)
|
||||||
|
|
||||||
|
# TMP ( TODO remove it later)
|
||||||
|
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
||||||
|
HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17]
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.contrib.gis.db.backends.postgis',
|
||||||
|
'NAME': os.environ.get('DB_NAME'),
|
||||||
|
'USER': os.environ.get('DB_USERNAME'),
|
||||||
|
'PASSWORD': os.environ.get('DB_PASSWORD'),
|
||||||
|
'HOST': os.environ.get('DB_HOSTNAME'),
|
||||||
|
'PORT': os.environ.get('DB_PORT'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
BROKER_URL = 'redis://localhost:6379/1'
|
||||||
|
CELERY_RESULT_BACKEND = BROKER_URL
|
||||||
|
CELERY_BROKER_URL = BROKER_URL
|
||||||
|
|
||||||
# Booking API configuration
|
# Booking API configuration
|
||||||
GUESTONLINE_SERVICE = 'https://api.guestonline.fr/'
|
GUESTONLINE_SERVICE = 'https://api.guestonline.fr/'
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,4 @@ ELASTICSEARCH_INDEX_NAMES = {
|
||||||
|
|
||||||
# TMP ( TODO remove it later)
|
# TMP ( TODO remove it later)
|
||||||
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
||||||
HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17]
|
HARDCODED_INTERNATIONAL_NEWS_IDS = [1460, 1471, 1482, 1484, 1611, 1612]
|
||||||
|
|
@ -42,7 +42,7 @@ django-storages==1.7.2
|
||||||
sorl-thumbnail==12.5.0
|
sorl-thumbnail==12.5.0
|
||||||
|
|
||||||
|
|
||||||
mysqlclient==1.4.4
|
# mysqlclient==1.4.4
|
||||||
PyYAML==5.1.2
|
PyYAML==5.1.2
|
||||||
|
|
||||||
# temp solution
|
# temp solution
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user