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
|
||||
if oauth2_status != status.HTTP_200_OK:
|
||||
raise utils_exceptions.OAuth2Error()
|
||||
raise utils_exceptions.OAuth2Error(detail=body)
|
||||
|
||||
# Get authenticated user
|
||||
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)
|
||||
booking_id = models.TextField(verbose_name=_('external service booking id'), default=None, null=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(
|
||||
'account.User', verbose_name=_('booking owner'), null=True,
|
||||
related_name='bookings',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
from abc import ABC, abstractmethod
|
||||
import json
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
import requests
|
||||
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
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class AbstractBookingService(ABC):
|
||||
|
|
@ -24,8 +27,14 @@ class AbstractBookingService(ABC):
|
|||
self.url = settings.LASTABLE_SERVICE
|
||||
|
||||
@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 """
|
||||
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}
|
||||
|
||||
@abstractmethod
|
||||
|
|
@ -66,22 +75,22 @@ class GuestonlineService(AbstractBookingService):
|
|||
def get_common_headers(self):
|
||||
return {'X-Token': self.token, 'Content-type': 'application/json', 'Accept': 'application/json'}
|
||||
|
||||
def check_whether_booking_available(self, restaurant_id, date: str):
|
||||
super().check_whether_booking_available(restaurant_id, date)
|
||||
url = f'{self.url}v1/runtime_services'
|
||||
params = {'restaurant_id': restaurant_id, 'date': date, 'expands[]': 'table_availabilities'}
|
||||
def check_whether_booking_available(self, restaurant_id, *args, **kwargs):
|
||||
url = f'{self.url}v1/periods'
|
||||
params = {'restaurant_id': restaurant_id, **kwargs}
|
||||
r = requests.get(url, headers=self.get_common_headers(), params=params)
|
||||
if not status.is_success(r.status_code):
|
||||
return False
|
||||
response = json.loads(r.content)['runtime_services']
|
||||
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
|
||||
self.response = r.json()
|
||||
return True
|
||||
|
||||
def commit_booking(self, payload):
|
||||
def commit_booking(self, payload, stripe_token = None):
|
||||
url = f'{self.url}v1/pending_bookings/{payload}/commit'
|
||||
r = requests.put(url, headers=self.get_common_headers())
|
||||
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())
|
||||
self.response = json.loads(r.content)
|
||||
if status.is_success(r.status_code) and self.response is None:
|
||||
raise serializers.ValidationError(detail='Booking already committed.')
|
||||
|
|
@ -93,8 +102,13 @@ class GuestonlineService(AbstractBookingService):
|
|||
payload['lastname'] = payload.pop('last_name')
|
||||
payload['firstname'] = payload.pop('first_name')
|
||||
payload['mobile_phone'] = payload.pop('phone')
|
||||
payload['user_locale'] = payload.pop('country_code')
|
||||
headers = self.get_common_headers()
|
||||
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)
|
||||
|
||||
def create_booking(self, payload):
|
||||
|
|
@ -103,7 +117,10 @@ class GuestonlineService(AbstractBookingService):
|
|||
payload['persons'] = payload.pop('booked_persons_number')
|
||||
payload['date'] = payload.pop('booking_date')
|
||||
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):
|
||||
url = f'{self.url}v1/pending_bookings/{payload}'
|
||||
|
|
|
|||
|
|
@ -42,13 +42,29 @@ class PendingBookingSerializer(serializers.ModelSerializer):
|
|||
'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):
|
||||
id = serializers.ReadOnlyField()
|
||||
|
||||
class Meta:
|
||||
model = models.Booking
|
||||
fields = ('booking_id', 'id')
|
||||
fields = ('booking_id', 'id', 'stripe_key', 'amount')
|
||||
|
||||
|
||||
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>/create/', views.CreatePendingBooking.as_view(), name='create-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('last/', views.LastBooking.as_view(), name='last_booking-for-authorizer-user'),
|
||||
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 establishment.models import Establishment
|
||||
from booking.models.models import Booking, GuestonlineService, LastableService
|
||||
from rest_framework import generics, permissions, status, serializers
|
||||
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):
|
||||
|
|
@ -28,7 +30,9 @@ class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
|||
service = l_service
|
||||
service.service_id = establishment.lastable_id
|
||||
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
|
||||
service = g_service
|
||||
service.service_id = establishment.guestonline_id
|
||||
|
|
@ -61,7 +65,9 @@ class CreatePendingBooking(generics.CreateAPIView):
|
|||
}
|
||||
data['pending_booking_id'] = service.create_booking(
|
||||
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')
|
||||
data['booking_id'] = data['pending_booking_id'] if data.get('type') == Booking.LASTABLE else None
|
||||
serializer = self.get_serializer(data=data)
|
||||
|
|
@ -70,6 +76,13 @@ class CreatePendingBooking(generics.CreateAPIView):
|
|||
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):
|
||||
""" Update pending booking with contacts """
|
||||
queryset = Booking.objects.all()
|
||||
|
|
@ -81,9 +94,31 @@ class UpdatePendingBooking(generics.UpdateAPIView):
|
|||
data = request.data.copy()
|
||||
service = Booking.get_service_by_type(instance.type)
|
||||
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',
|
||||
}))
|
||||
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'])
|
||||
data = {
|
||||
'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,
|
||||
verbose_name=_('Collection slug'), editable=True, null=True)
|
||||
|
||||
old_id=models.IntegerField(null=True, blank=True)
|
||||
objects = CollectionQuerySet.as_manager()
|
||||
|
||||
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):
|
||||
"""Establishment admin."""
|
||||
list_display = ['id', '__str__', 'image_tag', ]
|
||||
inlines = [
|
||||
AwardInline, ContactPhoneInline, ContactEmailInline,
|
||||
ReviewInline, CommentInline, ProductInline]
|
||||
|
||||
# inlines = [
|
||||
# AwardInline, ContactPhoneInline, ContactEmailInline,
|
||||
# ReviewInline, CommentInline, ProductInline]
|
||||
raw_id_fields = ('address',)
|
||||
|
||||
|
||||
|
|
@ -78,6 +79,7 @@ class PlateInline(admin.TabularInline):
|
|||
class MenuAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
||||
"""Menu admin."""
|
||||
list_display = ['id', 'category_translated']
|
||||
raw_id_fields = ['establishment']
|
||||
inlines = [
|
||||
PlateInline,
|
||||
]
|
||||
|
|
@ -87,3 +89,8 @@ class MenuAdmin(BaseModelAdminMixin, admin.ModelAdmin):
|
|||
return obj.category_translated
|
||||
|
||||
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 establishment.models import Establishment
|
||||
from transfer.models import Descriptions
|
||||
from transfer.models import Reviews, ReviewTexts
|
||||
|
||||
|
||||
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):
|
||||
count = 0
|
||||
update_locale = 0
|
||||
valid_reviews = {}
|
||||
|
||||
queryset = Descriptions.objects.all()
|
||||
for obj in queryset:
|
||||
queryset = Reviews.objects.exclude(
|
||||
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:
|
||||
establishment = Establishment.objects.get(old_id=obj.establishment.id)
|
||||
except Establishment.DoesNotExist:
|
||||
continue
|
||||
except Establishment.MultipleObjectsReturned:
|
||||
establishment = Establishment.objects.filter(old_id=obj.establishment.id).first()
|
||||
review_id, date = valid_reviews[establishment_id]
|
||||
except KeyError:
|
||||
valid_reviews[establishment_id] = (r_id, new_date)
|
||||
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.update({
|
||||
obj.locale: obj.text
|
||||
locale: text
|
||||
})
|
||||
establishment.description = description
|
||||
establishment.save()
|
||||
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 en-GB locale - {count}'))
|
||||
|
|
|
|||
|
|
@ -18,14 +18,16 @@ class Command(BaseCommand):
|
|||
AND scope = 'public'
|
||||
AND type = 'Photo'
|
||||
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]
|
||||
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:
|
||||
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.save()
|
||||
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.translation import gettext_lazy as _
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
from pytz import timezone as ptz
|
||||
from timezone_field import TimeZoneField
|
||||
|
||||
from collection.models import Collection
|
||||
|
|
@ -310,6 +309,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
|||
public_mark = models.PositiveIntegerField(blank=True, null=True,
|
||||
default=None,
|
||||
verbose_name=_('public mark'),)
|
||||
# todo: set default 0
|
||||
toque_number = models.PositiveIntegerField(blank=True, null=True,
|
||||
default=None,
|
||||
verbose_name=_('toque number'),)
|
||||
|
|
@ -384,7 +384,13 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
|||
|
||||
# todo: recalculate toque_number
|
||||
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):
|
||||
if low_price is None or high_price is None:
|
||||
|
|
@ -428,6 +434,27 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
|
|||
def best_price_carte(self):
|
||||
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
|
||||
def works_noon(self):
|
||||
""" Used for indexing working by day """
|
||||
|
|
@ -622,9 +649,12 @@ class Plate(TranslatedFieldsMixin, models.Model):
|
|||
help_text='{"en-GB":"some text"}')
|
||||
price = models.DecimalField(
|
||||
_('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(
|
||||
'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(
|
||||
'establishment.Menu', verbose_name=_('menu'), on_delete=models.CASCADE)
|
||||
|
|
@ -656,11 +686,12 @@ class Menu(TranslatedFieldsMixin, BaseAttributes):
|
|||
|
||||
|
||||
class SocialNetwork(models.Model):
|
||||
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
|
||||
establishment = models.ForeignKey(
|
||||
'Establishment', verbose_name=_('establishment'),
|
||||
related_name='socials', on_delete=models.CASCADE)
|
||||
title = models.CharField(_('title'), max_length=255)
|
||||
url = models.URLField(_('URL'))
|
||||
url = models.URLField(_('URL'), max_length=255)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('social network')
|
||||
|
|
@ -669,3 +700,62 @@ class SocialNetwork(models.Model):
|
|||
def __str__(self):
|
||||
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}
|
||||
}
|
||||
|
||||
|
||||
class EstablishmentSubTypeGeoSerializer(EstablishmentSubTypeBaseSerializer):
|
||||
"""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):
|
||||
"""Serializer for Establishment model."""
|
||||
|
||||
|
|
@ -240,6 +246,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
|||
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_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()
|
||||
|
||||
class Meta(EstablishmentBaseSerializer.Meta):
|
||||
|
|
@ -264,6 +272,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
|||
'menu',
|
||||
'best_price_menu',
|
||||
'best_price_carte',
|
||||
'range_price_menu',
|
||||
'range_price_carte',
|
||||
'transportation',
|
||||
'vintage_year',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
from pprint import pprint
|
||||
|
||||
import requests
|
||||
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 location.models import Address
|
||||
from transfer.models import Establishments, Dishes
|
||||
from transfer.serializers.establishment import EstablishmentSerializer
|
||||
from transfer.serializers.plate import PlateSerializer
|
||||
|
||||
|
||||
def transfer_establishment():
|
||||
result = []
|
||||
|
||||
old_establishments = Establishments.objects.filter(
|
||||
location__city__name__icontains='paris',
|
||||
# todo: filter(location__city__name__icontains='paris')
|
||||
old_establishments = Establishments.objects.exclude(
|
||||
id__in=list(Establishment.objects.all().values_list('old_id', flat=True))
|
||||
).exclude(
|
||||
Q(type='Wineyard') |
|
||||
Q(location__timezone__isnull=True)
|
||||
Q(location__timezone__isnull=True),
|
||||
).prefetch_related(
|
||||
'establishmentinfos_set',
|
||||
'schedules_set',
|
||||
|
|
@ -133,6 +135,5 @@ data_types = {
|
|||
"location_establishment": [
|
||||
transfer_establishment_addresses
|
||||
],
|
||||
|
||||
"menu": [transfer_menu],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ from django.dispatch import receiver
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
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):
|
||||
|
|
@ -15,6 +16,13 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
|||
|
||||
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,
|
||||
verbose_name=_('Name'), help_text='{"en-GB":"some text"}')
|
||||
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'))
|
||||
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
|
||||
def country_id(self):
|
||||
return self.id
|
||||
|
|
@ -33,6 +47,14 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
|
|||
verbose_name_plural = _('Countries')
|
||||
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):
|
||||
"""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 pprint import pprint
|
||||
|
||||
from requests import get
|
||||
|
||||
|
||||
def transfer_countries():
|
||||
queryset = Cities.objects.raw("""SELECT cities.id, cities.country_code_2
|
||||
FROM cities WHERE
|
||||
country_code_2 IS NOT NULL AND
|
||||
country_code_2 != ""
|
||||
GROUP BY cities.country_code_2""")
|
||||
queryset = Cities.objects.raw("""
|
||||
SELECT cities.id, cities.country_code_2
|
||||
FROM cities
|
||||
WHERE country_code_2 IS NOT NULL AND
|
||||
country_code_2 != ""
|
||||
GROUP BY cities.id, cities.country_code_2
|
||||
""")
|
||||
|
||||
queryset = [vars(query) for query in queryset]
|
||||
|
||||
|
|
@ -22,16 +26,24 @@ def transfer_countries():
|
|||
|
||||
|
||||
def transfer_regions():
|
||||
regions_without_subregion_queryset = Cities.objects.raw("""SELECT cities.id, cities.region_code,
|
||||
cities.country_code_2, cities.subregion_code
|
||||
FROM cities WHERE
|
||||
(subregion_code IS NULL OR
|
||||
subregion_code = "") AND
|
||||
region_code IS NOT NULL AND
|
||||
region_code != "" AND
|
||||
country_code_2 IS NOT NULL AND
|
||||
country_code_2 != ""
|
||||
GROUP BY region_code""")
|
||||
regions_without_subregion_queryset = Cities.objects.raw("""
|
||||
SELECT cities.id,
|
||||
cities.region_code,
|
||||
cities.country_code_2,
|
||||
cities.subregion_code
|
||||
FROM cities
|
||||
WHERE (subregion_code IS NULL
|
||||
OR subregion_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]
|
||||
|
||||
|
|
@ -41,25 +53,34 @@ def transfer_regions():
|
|||
else:
|
||||
pprint(f"Parent regions serializer errors: {serialized_without_subregion.errors}")
|
||||
|
||||
regions_with_subregion_queryset = Cities.objects.raw("""SELECT cities.id, cities.region_code,
|
||||
cities.country_code_2, cities.subregion_code
|
||||
FROM cities WHERE
|
||||
subregion_code IS NOT NULL AND
|
||||
subregion_code != "" AND
|
||||
region_code IS NOT NULL AND
|
||||
region_code != "" AND
|
||||
country_code_2 IS NOT NULL AND
|
||||
country_code_2 != ""
|
||||
AND cities.subregion_code in (
|
||||
SELECT region_code FROM cities WHERE
|
||||
(subregion_code IS NULL OR
|
||||
subregion_code = "") AND
|
||||
region_code IS NOT NULL AND
|
||||
region_code != "" AND
|
||||
country_code_2 IS NOT NULL AND
|
||||
country_code_2 != ""
|
||||
)
|
||||
GROUP BY region_code""")
|
||||
regions_with_subregion_queryset = Cities.objects.raw("""
|
||||
SELECT
|
||||
cities.id,
|
||||
cities.region_code,
|
||||
cities.country_code_2,
|
||||
cities.subregion_code
|
||||
FROM cities
|
||||
WHERE subregion_code IS NOT NULL AND
|
||||
subregion_code != "" AND
|
||||
region_code IS NOT NULL AND
|
||||
region_code != "" AND
|
||||
country_code_2 IS NOT NULL AND
|
||||
country_code_2 != ""
|
||||
AND cities.subregion_code in
|
||||
(
|
||||
SELECT region_code FROM cities WHERE
|
||||
(subregion_code IS NULL OR
|
||||
subregion_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_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}")
|
||||
|
||||
|
||||
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 = {
|
||||
"dictionaries": [
|
||||
|
|
@ -119,5 +151,8 @@ data_types = {
|
|||
transfer_regions,
|
||||
transfer_cities,
|
||||
transfer_addresses
|
||||
],
|
||||
"update_country_flag": [
|
||||
update_flags
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,10 @@ class AwardAdmin(admin.ModelAdmin):
|
|||
|
||||
|
||||
@admin.register(models.Currency)
|
||||
class CurrencContentAdmin(admin.ModelAdmin):
|
||||
"""CurrencContent admin"""
|
||||
class CurrencyContentAdmin(admin.ModelAdmin):
|
||||
"""Currency Content admin"""
|
||||
list_display = ['id', 'slug', 'code']
|
||||
list_display_links = ['slug']
|
||||
|
||||
|
||||
@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.models import ContentType
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from django.core.validators import EMPTY_VALUES
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
|
@ -14,96 +15,8 @@ from configuration.models import TranslationSettings
|
|||
from location.models import Country
|
||||
from main import methods
|
||||
from review.models import Review
|
||||
from utils.models import (ProjectBaseMixin, TJSONField,
|
||||
TranslatedFieldsMixin, ImageMixin,
|
||||
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."""
|
||||
#
|
||||
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
|
||||
TranslatedFieldsMixin, PlatformMixin)
|
||||
|
||||
|
||||
class Currency(TranslatedFieldsMixin, models.Model):
|
||||
|
|
@ -111,8 +24,9 @@ class Currency(TranslatedFieldsMixin, models.Model):
|
|||
name = TJSONField(
|
||||
_('name'), null=True, blank=True,
|
||||
default=None, help_text='{"en-GB":"some text"}')
|
||||
sign = models.CharField(_('sign'), max_length=1)
|
||||
slug = models.SlugField(max_length=255, unique=True)
|
||||
sign = models.CharField(_('sign'), max_length=255)
|
||||
slug = models.SlugField(max_length=5, unique=True)
|
||||
code = models.CharField(max_length=5, unique=True, null=True, default=None)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('currency')
|
||||
|
|
@ -130,7 +44,6 @@ class SiteSettingsQuerySet(models.QuerySet):
|
|||
|
||||
|
||||
class SiteSettings(ProjectBaseMixin):
|
||||
|
||||
subdomain = models.CharField(max_length=255, db_index=True, unique=True,
|
||||
verbose_name=_('Subdomain'))
|
||||
country = models.OneToOneField(Country, on_delete=models.PROTECT,
|
||||
|
|
@ -279,13 +192,41 @@ class AwardType(models.Model):
|
|||
class CarouselQuerySet(models.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):
|
||||
"""Carousel model."""
|
||||
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
||||
object_id = models.PositiveIntegerField()
|
||||
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True, default=None)
|
||||
object_id = models.PositiveIntegerField(blank=True, null=True, default=None)
|
||||
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()
|
||||
|
||||
class Meta:
|
||||
|
|
@ -325,6 +266,8 @@ class Carousel(models.Model):
|
|||
|
||||
@property
|
||||
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'):
|
||||
return self.content_object.image_url
|
||||
|
||||
|
|
@ -340,5 +283,12 @@ class Carousel(models.Model):
|
|||
|
||||
@property
|
||||
def model_name(self):
|
||||
if hasattr(self.content_object, 'establishment_type'):
|
||||
return self.content_object.establishment_type.name_translated
|
||||
from establishment.models import Establishment
|
||||
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_name = serializers.CharField(source='country.name_translated', read_only=True)
|
||||
time_format = serializers.CharField(source='country.time_format', read_only=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -71,6 +72,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
|||
model = models.SiteSettings
|
||||
fields = (
|
||||
'country_code',
|
||||
'time_format',
|
||||
'subdomain',
|
||||
'pinterest_page_url',
|
||||
'twitter_page_url',
|
||||
|
|
@ -81,7 +83,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
|
|||
'ad_config',
|
||||
'published_features',
|
||||
'currency',
|
||||
'country_name'
|
||||
'country_name',
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -135,6 +137,7 @@ class AwardSerializer(AwardBaseSerializer):
|
|||
|
||||
class CarouselListSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for retrieving list of carousel items."""
|
||||
|
||||
model_name = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
toque_number = serializers.IntegerField()
|
||||
|
|
@ -158,6 +161,7 @@ class CarouselListSerializer(serializers.ModelSerializer):
|
|||
'vintage_year',
|
||||
'last_award',
|
||||
'slug',
|
||||
'link',
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ card = {
|
|||
"facebook_page_url": "facebook_page_url",
|
||||
"instagram_page_url": "instagram_page_url",
|
||||
"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": {
|
||||
# # Как работать c отношение OneToOneField
|
||||
|
|
@ -133,7 +134,7 @@ card = {
|
|||
"vintage_year": "year",
|
||||
}
|
||||
},
|
||||
#TODO вопрос с content_type
|
||||
# TODO вопрос с content_type
|
||||
"relations": {
|
||||
"AwardTypes": [(
|
||||
("award_type", None),
|
||||
|
|
@ -143,4 +144,4 @@ card = {
|
|||
}
|
||||
}
|
||||
|
||||
used_apps = ("locations", )
|
||||
used_apps = ("locations",)
|
||||
|
|
|
|||
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]
|
||||
}
|
||||
|
|
@ -8,5 +8,5 @@ common_urlpatterns = [
|
|||
path('awards/', AwardView.as_view(), name='awards_list'),
|
||||
path('awards/<int:pk>/', AwardRetrieveView.as_view(), name='awards_retrieve'),
|
||||
path('carousel/', CarouselListView.as_view(), name='carousel-list'),
|
||||
path('determine-location/', DetermineLocation.as_view(), name='determine-location')
|
||||
path('determine-location/', DetermineLocation.as_view(), name='determine-location')
|
||||
]
|
||||
|
|
|
|||
|
|
@ -61,11 +61,19 @@ class AwardRetrieveView(generics.RetrieveAPIView):
|
|||
|
||||
class CarouselListView(generics.ListAPIView):
|
||||
"""Return list of carousel items."""
|
||||
queryset = models.Carousel.objects.all()
|
||||
|
||||
queryset = models.Carousel.objects.is_parsed().active()
|
||||
serializer_class = serializers.CarouselListSerializer
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
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):
|
||||
"""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 utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin, ProjectBaseMixin
|
||||
from utils.querysets import TranslationQuerysetMixin
|
||||
|
||||
|
||||
class NewsType(models.Model):
|
||||
|
|
@ -27,7 +28,7 @@ class NewsType(models.Model):
|
|||
return self.name
|
||||
|
||||
|
||||
class NewsQuerySet(models.QuerySet):
|
||||
class NewsQuerySet(TranslationQuerysetMixin):
|
||||
"""QuerySet for model News"""
|
||||
|
||||
def rating_value(self):
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ class NewsDetailWebSerializer(NewsDetailSerializer):
|
|||
'same_theme',
|
||||
'should_read',
|
||||
'agenda',
|
||||
'banner'
|
||||
'banner',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ class NewsMixinView:
|
|||
from django.conf import settings
|
||||
"""Override get_queryset method."""
|
||||
|
||||
qs = models.News.objects.published().with_base_related() \
|
||||
.order_by('-is_highlighted', '-created')
|
||||
qs = models.News.objects.published() \
|
||||
.with_base_related() \
|
||||
.order_by('-is_highlighted', '-created')
|
||||
country_code = self.request.country_code
|
||||
if country_code:
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ class NewsMixinView:
|
|||
qs = qs.by_country_code(country_code)
|
||||
else:
|
||||
qs = models.News.objects.filter(
|
||||
id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS)
|
||||
old_id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS)
|
||||
return qs
|
||||
# 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
|
||||
|
||||
|
||||
class Partner(ProjectBaseMixin, ImageMixin):
|
||||
class Partner(ProjectBaseMixin):
|
||||
"""Partner model."""
|
||||
url = models.URLField(verbose_name=_('Partner URL'))
|
||||
image = models.URLField(verbose_name=_('Partner image URL'), null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('partner')
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ from transfer.serializers.partner import PartnerSerializer
|
|||
def transfer_partner():
|
||||
queryset = EstablishmentBacklinks.objects.filter(type="Partner")
|
||||
|
||||
# queryset = EstablishmentBacklinks.objects.all() # Partner and Sponsor
|
||||
|
||||
serialized_data = PartnerSerializer(data=list(queryset.values()), many=True)
|
||||
if serialized_data.is_valid():
|
||||
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 = {
|
||||
'name': {'fuzziness': 'auto:3,4'},
|
||||
'name_translated': {'fuzziness': 'auto:3,4'},
|
||||
'name': {'fuzziness': 'auto:3,4',
|
||||
'boost': '2'},
|
||||
'name_translated': {'fuzziness': 'auto:3,4',
|
||||
'boost': '2'},
|
||||
'description': {'fuzziness': 'auto'},
|
||||
}
|
||||
translated_search_fields = (
|
||||
|
|
|
|||
|
|
@ -5,8 +5,13 @@ from .models import Tag, TagCategory
|
|||
@admin.register(Tag)
|
||||
class TagAdmin(admin.ModelAdmin):
|
||||
"""Admin model for model Tag."""
|
||||
list_display = ['id', 'value', 'category']
|
||||
list_display_links = ['id', 'value',]
|
||||
list_filter = ['value']
|
||||
|
||||
|
||||
@admin.register(TagCategory)
|
||||
class TagCategoryAdmin(admin.ModelAdmin):
|
||||
"""Admin model for model TagCategory."""
|
||||
list_display = ['id', 'index_name', ]
|
||||
list_display_links = ['id', 'index_name', ]
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
"""Tag app filters."""
|
||||
from django_filters import rest_framework as filters
|
||||
from establishment.models import EstablishmentType
|
||||
from django.conf import settings
|
||||
from tag import models
|
||||
|
||||
|
||||
class TagCategoryFilterSet(filters.FilterSet):
|
||||
"""TagCategory filterset."""
|
||||
class TagsBaseFilterSet(filters.FilterSet):
|
||||
|
||||
# Object type choices
|
||||
NEWS = 'news'
|
||||
|
|
@ -19,6 +18,18 @@ class TagCategoryFilterSet(filters.FilterSet):
|
|||
type = filters.MultipleChoiceFilter(choices=TYPE_CHOICES,
|
||||
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(
|
||||
choices=EstablishmentType.INDEX_NAME_TYPES,
|
||||
method='by_establishment_type')
|
||||
|
|
@ -30,13 +41,31 @@ class TagCategoryFilterSet(filters.FilterSet):
|
|||
fields = ('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
|
||||
def by_establishment_type(self, queryset, name, 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):
|
||||
|
||||
existing_establishment = Establishment.objects.filter(old_id__isnull=False)
|
||||
existing_establishment = Establishment.objects.filter(
|
||||
old_id__isnull=False, tags__isnull=True
|
||||
)
|
||||
ESTABLISHMENT = 1
|
||||
SHOP = 2
|
||||
RESTAURANT = 3
|
||||
|
|
@ -52,18 +54,35 @@ class Command(BaseCommand):
|
|||
|
||||
# create Tag
|
||||
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(
|
||||
label={
|
||||
'en-GB': tag.value,
|
||||
'fr-FR': tag.value,
|
||||
'ru-RU': tag.value,
|
||||
},
|
||||
new_tag, created = Tag.objects.get_or_create(
|
||||
value=tag.value,
|
||||
category=tag_category,
|
||||
)
|
||||
est = existing_establishment.get(old_id=tag.establishment_id)
|
||||
est.tags.add(new_tag)
|
||||
est.save()
|
||||
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.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."""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from configuration.models import TranslationSettings
|
||||
from location.models import Country
|
||||
from utils.models import TJSONField, TranslatedFieldsMixin
|
||||
|
||||
|
||||
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):
|
||||
return self.order_by('priority')
|
||||
return self.order_by('chosentagsettings__priority')
|
||||
|
||||
|
||||
class Tag(TranslatedFieldsMixin, models.Model):
|
||||
|
|
@ -24,7 +34,8 @@ class Tag(TranslatedFieldsMixin, models.Model):
|
|||
category = models.ForeignKey('TagCategory', on_delete=models.CASCADE,
|
||||
null=True, related_name='tags',
|
||||
verbose_name=_('Category'))
|
||||
priority = models.IntegerField(unique=True, null=True, default=None)
|
||||
|
||||
chosen_tag_settings = models.ManyToManyField(Country, through='ChosenTagSettings')
|
||||
|
||||
objects = TagQuerySet.as_manager()
|
||||
|
||||
|
|
@ -35,11 +46,29 @@ class Tag(TranslatedFieldsMixin, models.Model):
|
|||
verbose_name_plural = _('Tags')
|
||||
|
||||
def __str__(self):
|
||||
label = 'None'
|
||||
lang = TranslationSettings.get_solo().default_language
|
||||
if self.label and lang in self.label:
|
||||
label = self.label[lang]
|
||||
return f'id:{self.id}-{label}'
|
||||
return f'Tag (id = {self.id}, label_translated = {self.label_translated})'
|
||||
|
||||
|
||||
class ChosenTagSettingsQuerySet(models.QuerySet):
|
||||
|
||||
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):
|
||||
|
|
@ -55,7 +84,7 @@ class TagCategoryQuerySet(models.QuerySet):
|
|||
|
||||
def for_news(self):
|
||||
"""Select tag categories for news."""
|
||||
return self.filter(news_types__isnull=True)
|
||||
return self.filter(news_types__isnull=False)
|
||||
|
||||
def for_establishments(self):
|
||||
"""Select tag categories for establishments."""
|
||||
|
|
@ -106,8 +135,4 @@ class TagCategory(TranslatedFieldsMixin, models.Model):
|
|||
verbose_name_plural = _('Tag categories')
|
||||
|
||||
def __str__(self):
|
||||
label = 'None'
|
||||
lang = TranslationSettings.get_solo().default_language
|
||||
if self.label and lang in self.label:
|
||||
label = self.label[lang]
|
||||
return f'id:{self.id}-{label}'
|
||||
return self.index_name
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ from utils.serializers import TranslatedField
|
|||
class TagBaseSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model Tag."""
|
||||
|
||||
# todo: refactor this
|
||||
# label_translated = TranslatedField()
|
||||
label_translated = serializers.CharField(source='value', read_only=True, allow_null=True)
|
||||
label_translated = TranslatedField()
|
||||
# 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:
|
||||
"""Meta class."""
|
||||
|
|
@ -23,6 +23,7 @@ class TagBaseSerializer(serializers.ModelSerializer):
|
|||
fields = (
|
||||
'id',
|
||||
'label_translated',
|
||||
'index_name',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ app_name = 'tag'
|
|||
|
||||
router = SimpleRouter()
|
||||
router.register(r'categories', views.TagCategoryViewSet)
|
||||
router.register(r'chosen_tags', views.ChosenTagsView, basename='Tag')
|
||||
router.register(r'chosen_tags', views.ChosenTagsView)
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,45 @@
|
|||
"""Tag views."""
|
||||
from django.conf import settings
|
||||
from rest_framework import permissions
|
||||
from rest_framework import viewsets, mixins, status, generics
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from tag import filters, models, serializers
|
||||
from rest_framework import permissions
|
||||
|
||||
|
||||
class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet):
|
||||
pagination_class = None
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
serializer_class = serializers.TagBaseSerializer
|
||||
filterset_class = filters.TagsFilterSet
|
||||
queryset = models.Tag.objects.all()
|
||||
|
||||
def get_queryset(self):
|
||||
return models.Tag.objects\
|
||||
.filter_chosen() \
|
||||
result_tags_ids = models.ChosenTagSettings.objects \
|
||||
.by_country_code(self.request.country_code) \
|
||||
.values('tag_id')
|
||||
return models.Tag.objects \
|
||||
.filter(id__in=result_tags_ids) \
|
||||
.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
|
||||
class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
||||
|
|
@ -23,8 +47,8 @@ class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
|||
|
||||
filterset_class = filters.TagCategoryFilterSet
|
||||
pagination_class = None
|
||||
permission_classes = (permissions.AllowAny, )
|
||||
queryset = models.TagCategory.objects.with_tags().with_base_related().\
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
queryset = models.TagCategory.objects.with_tags().with_base_related(). \
|
||||
distinct()
|
||||
serializer_class = serializers.TagCategoryBaseSerializer
|
||||
|
||||
|
|
@ -62,7 +86,7 @@ class TagBackOfficeViewSet(mixins.ListModelMixin, mixins.CreateModelMixin,
|
|||
"""List/create tag view."""
|
||||
|
||||
pagination_class = None
|
||||
permission_classes = (permissions.IsAuthenticated, )
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
queryset = models.Tag.objects.all()
|
||||
serializer_class = serializers.TagBackOfficeSerializer
|
||||
bind_object_serializer_class = serializers.TagBindObjectSerializer
|
||||
|
|
@ -96,7 +120,7 @@ class TagCategoryBackOfficeViewSet(mixins.CreateModelMixin,
|
|||
TagCategoryViewSet):
|
||||
"""ViewSet for TagCategory model for BackOffice users."""
|
||||
|
||||
permission_classes = (permissions.IsAuthenticated, )
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
queryset = TagCategoryViewSet.queryset.with_extended_related()
|
||||
serializer_class = serializers.TagCategoryBackOfficeDetailSerializer
|
||||
bind_object_serializer_class = serializers.TagCategoryBindObjectSerializer
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class Command(BaseCommand):
|
|||
"""Типы данных для трансфера
|
||||
ВНИМАНИЕ: первые буквы типов данных должны быть уникальны!
|
||||
"""
|
||||
DATA_TYPES = [
|
||||
SHORT_DATA_TYPES = [
|
||||
'dictionaries',
|
||||
'news',
|
||||
'account',
|
||||
|
|
@ -22,20 +22,39 @@ class Command(BaseCommand):
|
|||
'tmp',
|
||||
'menu',
|
||||
'location_establishment',
|
||||
'wine_color',
|
||||
'whirligig',
|
||||
]
|
||||
|
||||
LONG_DATA_TYPES = [
|
||||
'update_country_flag',
|
||||
]
|
||||
|
||||
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:
|
||||
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)
|
||||
transfer_objects(data_type[0])
|
||||
data_type = list(set(option for option in options.keys() if options[option]) & set(self.SHORT_DATA_TYPES))
|
||||
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")
|
||||
exit(1)
|
||||
else:
|
||||
data_type = data_type[0]
|
||||
else:
|
||||
data_type = data_type[0]
|
||||
|
||||
transfer_objects(data_type)
|
||||
|
||||
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"""
|
||||
for option_type in self.DATA_TYPES:
|
||||
for option_type in self.SHORT_DATA_TYPES:
|
||||
parser.add_argument(
|
||||
f'-{option_type[:1]}',
|
||||
f'--{option_type}',
|
||||
|
|
|
|||
|
|
@ -553,6 +553,7 @@ class EstablishmentInfos(MigrateMixin):
|
|||
website = 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)
|
||||
instagram = models.TextField(blank=True, null=True)
|
||||
lafourchette = models.CharField(max_length=255, blank=True, null=True)
|
||||
pub = models.IntegerField(blank=True, null=True)
|
||||
created_at = models.DateTimeField()
|
||||
|
|
@ -967,3 +968,51 @@ class WineTypes(MigrateMixin):
|
|||
# class Meta:
|
||||
# managed = False
|
||||
# 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:
|
||||
return address.id
|
||||
return None
|
||||
# return None
|
||||
|
||||
@staticmethod
|
||||
def get_type(data):
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class RegionSerializer(serializers.ModelSerializer):
|
|||
print(data)
|
||||
if "subregion_code" in data and data["subregion_code"] is not None and data["subregion_code"].strip() != "":
|
||||
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:
|
||||
raise ValueError(f"Parent region error with {data}: {e}")
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,80 @@ from partner.models import Partner
|
|||
|
||||
class PartnerSerializer(serializers.ModelSerializer):
|
||||
backlink_url = serializers.CharField(source="url")
|
||||
partnership_icon = serializers.CharField()
|
||||
partnership_name = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
model = Partner
|
||||
fields = (
|
||||
"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):
|
||||
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():
|
||||
if exists(f"{app.path}/transfer_data.py"):
|
||||
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
|
||||
|
||||
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 rest_framework import status
|
||||
from rest_framework.request import Request
|
||||
from os.path import exists
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -64,7 +63,7 @@ def image_path(instance, filename):
|
|||
def svg_image_path(instance, filename):
|
||||
"""Determine SVG path method."""
|
||||
filename = '%s.svg' % generate_code()
|
||||
return 'image/svg/%s/%s/%s' % (
|
||||
return 'svg/%s/%s/%s' % (
|
||||
instance._meta.model_name,
|
||||
datetime.now().strftime(settings.REST_DATE_FORMAT),
|
||||
filename)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ def translate_field(self, field_name):
|
|||
# fallback
|
||||
if value is None:
|
||||
value = field.get(get_default_locale())
|
||||
if value is None:
|
||||
value = field.get(next(iter(field.keys()), None))
|
||||
return value
|
||||
return None
|
||||
return translate
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from django.db import models
|
|||
from django.db.models import Q, F
|
||||
|
||||
from utils.methods import get_contenttype
|
||||
from utils.models import TJSONField
|
||||
|
||||
|
||||
class ContentTypeQuerySetMixin(models.QuerySet):
|
||||
|
|
@ -56,3 +57,24 @@ class RelatedObjectsCountMixin(models.QuerySet):
|
|||
return self._annotate_related_objects_count()\
|
||||
.annotate(all_related_count=exp)\
|
||||
.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',
|
||||
'favorites.apps.FavoritesConfig',
|
||||
'rating.apps.RatingConfig',
|
||||
'transfer.apps.TransferConfig',
|
||||
# 'transfer.apps.TransferConfig',
|
||||
'tag.apps.TagConfig',
|
||||
'product.apps.ProductConfig',
|
||||
]
|
||||
|
|
@ -157,16 +157,16 @@ DATABASES = {
|
|||
'HOST': os.environ.get('DB_HOSTNAME'),
|
||||
'PORT': os.environ.get('DB_PORT'),
|
||||
},
|
||||
'legacy': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': '172.17.0.1',
|
||||
# 'HOST': '172.23.0.1',
|
||||
# 'HOST': 'mysql_db',
|
||||
'PORT': 3306,
|
||||
'NAME': 'dev',
|
||||
'USER': 'dev',
|
||||
'PASSWORD': 'octosecret123'
|
||||
}
|
||||
# 'legacy': {
|
||||
# 'ENGINE': 'django.db.backends.mysql',
|
||||
# # 'HOST': '172.17.0.1',
|
||||
# # 'HOST': '172.23.0.1',
|
||||
# 'HOST': 'mysql_db',
|
||||
# 'PORT': 3306,
|
||||
# 'NAME': 'dev',
|
||||
# 'USER': 'dev',
|
||||
# 'PASSWORD': 'octosecret123'
|
||||
# }
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -262,8 +262,8 @@ OAUTH2_SOCIAL_AUTH_GRANT_TYPE = 'convert_token'
|
|||
OAUTH2_PROVIDER_APPLICATION_MODEL = 'authorization.Application'
|
||||
|
||||
# Facebook configuration
|
||||
SOCIAL_AUTH_FACEBOOK_KEY = '386843648701452'
|
||||
SOCIAL_AUTH_FACEBOOK_SECRET = 'a71cf0bf3980843a8f1ea74c6d805fd7'
|
||||
SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get('FB_APPLICATION_ID')
|
||||
SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get('FB_PRIVATE_KEY')
|
||||
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', ]
|
||||
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
|
||||
'fields': 'id, name, email',
|
||||
|
|
@ -490,3 +490,8 @@ PHONENUMBER_DB_FORMAT = 'NATIONAL'
|
|||
PHONENUMBER_DEFAULT_REGION = "FR"
|
||||
|
||||
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']
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = ['.gm.id-east.ru', ]
|
||||
|
||||
SEND_SMS = False
|
||||
SMS_CODE_SHOW = True
|
||||
USE_CELERY = True
|
||||
|
|
@ -38,7 +40,7 @@ sentry_sdk.init(
|
|||
|
||||
# TMP ( TODO remove it later)
|
||||
# Временный хардкод для демонстрации 4 ноября, потом удалить!
|
||||
HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17]
|
||||
HARDCODED_INTERNATIONAL_NEWS_IDS = [1460, 1471, 1482, 1484, 1611, 1612]
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||
|
|
@ -52,12 +54,16 @@ DATABASES = {
|
|||
'HOST': os.environ.get('DB_HOSTNAME'),
|
||||
'PORT': os.environ.get('DB_PORT'),
|
||||
},
|
||||
'legacy': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'HOST': os.environ.get('MYSQL_HOSTNAME'),
|
||||
'PORT': os.environ.get('MYSQL_PORT'),
|
||||
'NAME': os.environ.get('MYSQL_DATABASE'),
|
||||
'USER': os.environ.get('MYSQL_USER'),
|
||||
'PASSWORD': os.environ.get('MYSQL_PASSWORD')
|
||||
}
|
||||
}
|
||||
# 'legacy': {
|
||||
# 'ENGINE': 'django.db.backends.mysql',
|
||||
# 'HOST': os.environ.get('MYSQL_HOSTNAME'),
|
||||
# 'PORT': os.environ.get('MYSQL_PORT'),
|
||||
# 'NAME': os.environ.get('MYSQL_DATABASE'),
|
||||
# 'USER': os.environ.get('MYSQL_USER'),
|
||||
# 'PASSWORD': os.environ.get('MYSQL_PASSWORD')
|
||||
# }
|
||||
}
|
||||
|
||||
BROKER_URL = 'redis://localhost:6379/1'
|
||||
CELERY_RESULT_BACKEND = BROKER_URL
|
||||
CELERY_BROKER_URL = BROKER_URL
|
||||
|
|
@ -1,10 +1,67 @@
|
|||
"""Production settings."""
|
||||
from .base 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
|
||||
GUESTONLINE_SERVICE = 'https://api.guestonline.fr/'
|
||||
GUESTONLINE_TOKEN = ''
|
||||
LASTABLE_SERVICE = ''
|
||||
LASTABLE_TOKEN = ''
|
||||
LASTABLE_PROXY = ''
|
||||
LASTABLE_PROXY = ''
|
||||
|
|
@ -30,4 +30,4 @@ ELASTICSEARCH_INDEX_NAMES = {
|
|||
|
||||
# TMP ( TODO remove it later)
|
||||
# Временный хардкод для демонстрации 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
|
||||
|
||||
|
||||
mysqlclient==1.4.4
|
||||
# mysqlclient==1.4.4
|
||||
PyYAML==5.1.2
|
||||
|
||||
# temp solution
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user