Merge branch 'develop' into feature/fix-country-region-city-transfer
This commit is contained in:
commit
181e9599e4
49
apps/account/management/commands/add_ownership.py
Normal file
49
apps/account/management/commands/add_ownership.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
from account.models import User, UserRole, Role
|
||||||
|
from transfer.models import OwnershipAffs
|
||||||
|
from establishment.models import Establishment
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = """Add ownership to UserRoles."""
|
||||||
|
|
||||||
|
def handle(self, *args, **kwarg):
|
||||||
|
create_user_roles = []
|
||||||
|
# filter owner records with state not null only
|
||||||
|
owners = OwnershipAffs.objects.filter(state__isnull=False)
|
||||||
|
|
||||||
|
# Get role, may be more then 1
|
||||||
|
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER).first()
|
||||||
|
if not role:
|
||||||
|
role = Role.objects.create(
|
||||||
|
role=Role.ESTABLISHMENT_MANAGER
|
||||||
|
)
|
||||||
|
|
||||||
|
for owner in tqdm(owners):
|
||||||
|
user = User.objects.filter(
|
||||||
|
old_id=owner.account_id).first()
|
||||||
|
requester = User.objects.filter(
|
||||||
|
old_id=owner.requester_id).first()
|
||||||
|
establishment = Establishment.objects.filter(
|
||||||
|
old_id=owner.establishment_id).first()
|
||||||
|
|
||||||
|
if user and establishment:
|
||||||
|
user_role = UserRole.objects.filter(
|
||||||
|
user=user, role=role, establishment=establishment, state=owner.state).first()
|
||||||
|
if not user_role:
|
||||||
|
# add to bulk_create
|
||||||
|
create_user_roles.append(UserRole(
|
||||||
|
user=user,
|
||||||
|
role=role,
|
||||||
|
establishment=establishment,
|
||||||
|
state=owner.state,
|
||||||
|
requester=requester
|
||||||
|
))
|
||||||
|
|
||||||
|
UserRole.objects.bulk_create(create_user_roles)
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.WARNING(
|
||||||
|
f'Created roles: {len(create_user_roles)}')
|
||||||
|
)
|
||||||
25
apps/account/migrations/0026_auto_20191211_1134.py
Normal file
25
apps/account/migrations/0026_auto_20191211_1134.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-12-11 11:34
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0025_auto_20191210_0623'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userrole',
|
||||||
|
name='requester',
|
||||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='roles_requested', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userrole',
|
||||||
|
name='state',
|
||||||
|
field=models.CharField(choices=[('validated', 'validated'), ('pending', 'pending'), ('cancelled', 'cancelled'), ('rejected', 'rejected')], default='pending', max_length=10, verbose_name='state'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
apps/account/migrations/0027_auto_20191211_1444.py
Normal file
18
apps/account/migrations/0027_auto_20191211_1444.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-12-11 14:44
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0067_auto_20191122_1244'),
|
||||||
|
('account', '0026_auto_20191211_1134'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='userrole',
|
||||||
|
unique_together={('user', 'role', 'establishment', 'state')},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -34,16 +34,16 @@ class Role(ProjectBaseMixin):
|
||||||
REVIEWER_MANGER = 6
|
REVIEWER_MANGER = 6
|
||||||
RESTAURANT_REVIEWER = 7
|
RESTAURANT_REVIEWER = 7
|
||||||
SALES_MAN = 8
|
SALES_MAN = 8
|
||||||
WINERY_REVIEWER = 9 # Establishments subtype "winery"
|
WINERY_REVIEWER = 9 # Establishments subtype "winery"
|
||||||
SELLER = 10
|
SELLER = 10
|
||||||
|
|
||||||
ROLE_CHOICES = (
|
ROLE_CHOICES = (
|
||||||
(STANDARD_USER, 'Standard user'),
|
(STANDARD_USER, _('Standard user')),
|
||||||
(COMMENTS_MODERATOR, 'Comments moderator'),
|
(COMMENTS_MODERATOR, _('Comments moderator')),
|
||||||
(COUNTRY_ADMIN, 'Country admin'),
|
(COUNTRY_ADMIN, _('Country admin')),
|
||||||
(CONTENT_PAGE_MANAGER, 'Content page manager'),
|
(CONTENT_PAGE_MANAGER, _('Content page manager')),
|
||||||
(ESTABLISHMENT_MANAGER, 'Establishment manager'),
|
(ESTABLISHMENT_MANAGER, _('Establishment manager')),
|
||||||
(REVIEWER_MANGER, 'Reviewer manager'),
|
(REVIEWER_MANGER, _('Reviewer manager')),
|
||||||
(RESTAURANT_REVIEWER, 'Restaurant reviewer'),
|
(RESTAURANT_REVIEWER, 'Restaurant reviewer'),
|
||||||
(SALES_MAN, 'Sales man'),
|
(SALES_MAN, 'Sales man'),
|
||||||
(WINERY_REVIEWER, 'Winery reviewer'),
|
(WINERY_REVIEWER, 'Winery reviewer'),
|
||||||
|
|
@ -93,6 +93,18 @@ class UserQuerySet(models.QuerySet):
|
||||||
return self.filter(oauth2_provider_refreshtoken__token=token,
|
return self.filter(oauth2_provider_refreshtoken__token=token,
|
||||||
oauth2_provider_refreshtoken__expires__gt=timezone.now())
|
oauth2_provider_refreshtoken__expires__gt=timezone.now())
|
||||||
|
|
||||||
|
def by_role(self, role):
|
||||||
|
"""Filter by role."""
|
||||||
|
return self.filter(userrole__role=role)
|
||||||
|
|
||||||
|
def by_roles(self, roles: list):
|
||||||
|
"""Filter by roles."""
|
||||||
|
return self.filter(userrole__role__in=roles)
|
||||||
|
|
||||||
|
def establishment_admin(self, establishment):
|
||||||
|
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER).first()
|
||||||
|
return self.by_role(role).filter(userrole__establishment=establishment)
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
"""Base user model."""
|
"""Base user model."""
|
||||||
|
|
@ -116,7 +128,9 @@ class User(AbstractUser):
|
||||||
USERNAME_FIELD = 'username'
|
USERNAME_FIELD = 'username'
|
||||||
REQUIRED_FIELDS = ['email']
|
REQUIRED_FIELDS = ['email']
|
||||||
|
|
||||||
roles = models.ManyToManyField(Role, verbose_name=_('Roles'), through='UserRole')
|
roles = models.ManyToManyField(
|
||||||
|
Role, verbose_name=_('Roles'), symmetrical=False,
|
||||||
|
through_fields=('user', 'role'), through='UserRole')
|
||||||
objects = UserManager.from_queryset(UserQuerySet)()
|
objects = UserManager.from_queryset(UserQuerySet)()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -301,14 +315,33 @@ class User(AbstractUser):
|
||||||
|
|
||||||
class UserRole(ProjectBaseMixin):
|
class UserRole(ProjectBaseMixin):
|
||||||
"""UserRole model."""
|
"""UserRole model."""
|
||||||
user = models.ForeignKey('account.User',
|
VALIDATED = 'validated'
|
||||||
verbose_name=_('User'),
|
PENDING = 'pending'
|
||||||
on_delete=models.CASCADE)
|
CANCELLED = 'cancelled'
|
||||||
role = models.ForeignKey(Role, verbose_name=_('Role'), on_delete=models.SET_NULL, null=True)
|
REJECTED = 'rejected'
|
||||||
establishment = models.ForeignKey(Establishment, verbose_name=_('Establishment'),
|
|
||||||
on_delete=models.SET_NULL, null=True, blank=True)
|
STATE_CHOICES = (
|
||||||
|
(VALIDATED, _('validated')),
|
||||||
|
(PENDING, _('pending')),
|
||||||
|
(CANCELLED, _('cancelled')),
|
||||||
|
(REJECTED, _('rejected'))
|
||||||
|
)
|
||||||
|
user = models.ForeignKey(
|
||||||
|
'account.User', verbose_name=_('User'), on_delete=models.CASCADE)
|
||||||
|
role = models.ForeignKey(
|
||||||
|
Role, verbose_name=_('Role'), on_delete=models.SET_NULL, null=True)
|
||||||
|
establishment = models.ForeignKey(
|
||||||
|
Establishment, verbose_name=_('Establishment'),
|
||||||
|
on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
|
|
||||||
|
state = models.CharField(
|
||||||
|
_('state'), choices=STATE_CHOICES, max_length=10, default=PENDING)
|
||||||
|
requester = models.ForeignKey(
|
||||||
|
'account.User', blank=True, null=True, default=None, related_name='roles_requested',
|
||||||
|
on_delete=models.SET_NULL)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ['user', 'role']
|
unique_together = ['user', 'role', 'establishment', 'state']
|
||||||
|
|
||||||
|
|
||||||
class OldRole(models.Model):
|
class OldRole(models.Model):
|
||||||
|
|
|
||||||
27
apps/collection/migrations/0024_auto_20191215_2156.py
Normal file
27
apps/collection/migrations/0024_auto_20191215_2156.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-12-15 21:56
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('collection', '0023_advertorial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='collection',
|
||||||
|
name='rank',
|
||||||
|
field=models.IntegerField(default=None, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='collection',
|
||||||
|
name='start',
|
||||||
|
field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='start'),
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='collection',
|
||||||
|
name='description',
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
@ -6,9 +6,10 @@ from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from utils.models import ProjectBaseMixin, URLImageMixin
|
from utils.models import (
|
||||||
from utils.models import TJSONField
|
ProjectBaseMixin, TJSONField, TranslatedFieldsMixin,
|
||||||
from utils.models import TranslatedFieldsMixin
|
URLImageMixin,
|
||||||
|
)
|
||||||
from utils.querysets import RelatedObjectsCountMixin
|
from utils.querysets import RelatedObjectsCountMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -24,7 +25,8 @@ class CollectionNameMixin(models.Model):
|
||||||
|
|
||||||
class CollectionDateMixin(models.Model):
|
class CollectionDateMixin(models.Model):
|
||||||
"""CollectionDate mixin"""
|
"""CollectionDate mixin"""
|
||||||
start = models.DateTimeField(_('start'))
|
start = models.DateTimeField(blank=True, null=True, default=None,
|
||||||
|
verbose_name=_('start'))
|
||||||
end = models.DateTimeField(blank=True, null=True, default=None,
|
end = models.DateTimeField(blank=True, null=True, default=None,
|
||||||
verbose_name=_('end'))
|
verbose_name=_('end'))
|
||||||
|
|
||||||
|
|
@ -73,13 +75,15 @@ class Collection(ProjectBaseMixin, CollectionDateMixin,
|
||||||
block_size = JSONField(
|
block_size = JSONField(
|
||||||
_('collection block properties'), null=True, blank=True,
|
_('collection block properties'), null=True, blank=True,
|
||||||
default=None, help_text='{"width": "250px", "height":"250px"}')
|
default=None, help_text='{"width": "250px", "height":"250px"}')
|
||||||
description = TJSONField(
|
# description = TJSONField(
|
||||||
_('description'), null=True, blank=True,
|
# _('description'), null=True, blank=True,
|
||||||
default=None, help_text='{"en-GB":"some text"}')
|
# default=None, help_text='{"en-GB":"some text"}')
|
||||||
slug = models.SlugField(max_length=50, unique=True,
|
slug = models.SlugField(max_length=50, unique=True,
|
||||||
verbose_name=_('Collection slug'), editable=True, null=True)
|
verbose_name=_('Collection slug'), editable=True, null=True)
|
||||||
old_id = models.IntegerField(null=True, blank=True)
|
old_id = models.IntegerField(null=True, blank=True)
|
||||||
|
|
||||||
|
rank = models.IntegerField(null=True, default=None)
|
||||||
|
|
||||||
objects = CollectionQuerySet.as_manager()
|
objects = CollectionQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -108,20 +112,29 @@ class Collection(ProjectBaseMixin, CollectionDateMixin,
|
||||||
@property
|
@property
|
||||||
def related_object_names(self) -> list:
|
def related_object_names(self) -> list:
|
||||||
"""Return related object names."""
|
"""Return related object names."""
|
||||||
raw_object_names = []
|
raw_object_names = {}
|
||||||
for related_object in [related_object.name for related_object in self._related_objects]:
|
for related_object in [(related_object.id, related_object.name) for related_object in self._related_objects]:
|
||||||
instances = getattr(self, f'{related_object}')
|
instances = getattr(self, f'{related_object[1]}')
|
||||||
if instances.exists():
|
if instances.exists():
|
||||||
for instance in instances.all():
|
for instance in instances.all():
|
||||||
raw_object_names.append(instance.slug if hasattr(instance, 'slug') else None)
|
raw_object_names[related_object[0]] = instance.slug if hasattr(instance, 'slug') else None
|
||||||
|
|
||||||
# parse slugs
|
# parse slugs
|
||||||
object_names = []
|
related_objects = []
|
||||||
|
object_names = set()
|
||||||
re_pattern = r'[\w]+'
|
re_pattern = r'[\w]+'
|
||||||
for raw_name in raw_object_names:
|
for object_id in raw_object_names:
|
||||||
result = re.findall(re_pattern, raw_name)
|
result = re.findall(re_pattern, raw_object_names[object_id])
|
||||||
if result: object_names.append(' '.join(result).capitalize())
|
if result:
|
||||||
return set(object_names)
|
name = ' '.join(result).capitalize()
|
||||||
|
if name not in object_names:
|
||||||
|
related_objects.append({
|
||||||
|
'id': object_id,
|
||||||
|
'name': name
|
||||||
|
})
|
||||||
|
object_names.add(name)
|
||||||
|
|
||||||
|
return related_objects
|
||||||
|
|
||||||
|
|
||||||
class GuideTypeQuerySet(models.QuerySet):
|
class GuideTypeQuerySet(models.QuerySet):
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ from location.models import Country
|
||||||
from location.serializers import CountrySimpleSerializer
|
from location.serializers import CountrySimpleSerializer
|
||||||
from product.models import Product
|
from product.models import Product
|
||||||
from utils.exceptions import (
|
from utils.exceptions import (
|
||||||
BindingObjectNotFound, RemovedBindingObjectNotFound, ObjectAlreadyAdded
|
BindingObjectNotFound, ObjectAlreadyAdded,
|
||||||
|
RemovedBindingObjectNotFound,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -33,13 +34,14 @@ class CollectionBackOfficeSerializer(CollectionBaseSerializer):
|
||||||
'on_top',
|
'on_top',
|
||||||
'country',
|
'country',
|
||||||
'country_id',
|
'country_id',
|
||||||
'block_size',
|
# 'block_size',
|
||||||
'description',
|
# 'description',
|
||||||
'slug',
|
'slug',
|
||||||
'start',
|
# 'start',
|
||||||
'end',
|
# 'end',
|
||||||
'count_related_objects',
|
'count_related_objects',
|
||||||
'related_object_names',
|
'related_object_names',
|
||||||
|
'rank',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -68,15 +70,15 @@ class CollectionBindObjectSerializer(serializers.Serializer):
|
||||||
attrs['collection'] = collection
|
attrs['collection'] = collection
|
||||||
|
|
||||||
if obj_type == self.ESTABLISHMENT:
|
if obj_type == self.ESTABLISHMENT:
|
||||||
establishment = Establishment.objects.filter(pk=obj_id).\
|
establishment = Establishment.objects.filter(pk=obj_id). \
|
||||||
first()
|
first()
|
||||||
if not establishment:
|
if not establishment:
|
||||||
raise BindingObjectNotFound()
|
raise BindingObjectNotFound()
|
||||||
if request.method == 'POST' and collection.establishments.\
|
if request.method == 'POST' and collection.establishments. \
|
||||||
filter(pk=establishment.pk).exists():
|
filter(pk=establishment.pk).exists():
|
||||||
raise ObjectAlreadyAdded()
|
raise ObjectAlreadyAdded()
|
||||||
if request.method == 'DELETE' and not collection.\
|
if request.method == 'DELETE' and not collection. \
|
||||||
establishments.filter(pk=establishment.pk).\
|
establishments.filter(pk=establishment.pk). \
|
||||||
exists():
|
exists():
|
||||||
raise RemovedBindingObjectNotFound()
|
raise RemovedBindingObjectNotFound()
|
||||||
attrs['related_object'] = establishment
|
attrs['related_object'] = establishment
|
||||||
|
|
@ -84,10 +86,10 @@ class CollectionBindObjectSerializer(serializers.Serializer):
|
||||||
product = Product.objects.filter(pk=obj_id).first()
|
product = Product.objects.filter(pk=obj_id).first()
|
||||||
if not product:
|
if not product:
|
||||||
raise BindingObjectNotFound()
|
raise BindingObjectNotFound()
|
||||||
if request.method == 'POST' and collection.products.\
|
if request.method == 'POST' and collection.products. \
|
||||||
filter(pk=product.pk).exists():
|
filter(pk=product.pk).exists():
|
||||||
raise ObjectAlreadyAdded()
|
raise ObjectAlreadyAdded()
|
||||||
if request.method == 'DELETE' and not collection.products.\
|
if request.method == 'DELETE' and not collection.products. \
|
||||||
filter(pk=product.pk).exists():
|
filter(pk=product.pk).exists():
|
||||||
raise RemovedBindingObjectNotFound()
|
raise RemovedBindingObjectNotFound()
|
||||||
attrs['related_object'] = product
|
attrs['related_object'] = product
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Collection common urlpaths."""
|
"""Collection common urlpaths."""
|
||||||
|
from django.urls import path
|
||||||
from rest_framework.routers import SimpleRouter
|
from rest_framework.routers import SimpleRouter
|
||||||
|
|
||||||
from collection.views import back as views
|
from collection.views import back as views
|
||||||
|
|
@ -8,3 +9,4 @@ router = SimpleRouter()
|
||||||
router.register(r'', views.CollectionBackOfficeViewSet)
|
router.register(r'', views.CollectionBackOfficeViewSet)
|
||||||
|
|
||||||
urlpatterns = router.urls
|
urlpatterns = router.urls
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from rest_framework import permissions
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import viewsets, mixins
|
from rest_framework import mixins, permissions, viewsets
|
||||||
|
from rest_framework.filters import OrderingFilter
|
||||||
|
|
||||||
from collection import models
|
from collection import models
|
||||||
from collection.serializers import back as serializers
|
from collection.serializers import back as serializers
|
||||||
|
|
@ -31,9 +32,13 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin,
|
||||||
|
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
permission_classes = (permissions.IsAuthenticated,)
|
||||||
queryset = models.Collection.objects.all()
|
queryset = models.Collection.objects.all()
|
||||||
|
filter_backends = [DjangoFilterBackend, OrderingFilter]
|
||||||
serializer_class = serializers.CollectionBackOfficeSerializer
|
serializer_class = serializers.CollectionBackOfficeSerializer
|
||||||
bind_object_serializer_class = serializers.CollectionBindObjectSerializer
|
bind_object_serializer_class = serializers.CollectionBindObjectSerializer
|
||||||
|
|
||||||
|
ordering_fields = ('rank', 'start')
|
||||||
|
ordering = ('-start', )
|
||||||
|
|
||||||
def perform_binding(self, serializer):
|
def perform_binding(self, serializer):
|
||||||
data = serializer.validated_data
|
data = serializer.validated_data
|
||||||
collection = data.pop('collection')
|
collection = data.pop('collection')
|
||||||
|
|
|
||||||
|
|
@ -541,9 +541,15 @@ class Establishment(GalleryModelMixin, ProjectBaseMixin, URLImageMixin,
|
||||||
def visible_tags(self):
|
def visible_tags(self):
|
||||||
return super().visible_tags \
|
return super().visible_tags \
|
||||||
.exclude(category__index_name__in=['guide', 'collection', 'purchased_item',
|
.exclude(category__index_name__in=['guide', 'collection', 'purchased_item',
|
||||||
'business_tag', 'business_tags_de', 'tag'])
|
'business_tag', 'business_tags_de']) \
|
||||||
|
.exclude(value__in=['rss', 'rss_selection'])
|
||||||
# todo: recalculate toque_number
|
# todo: recalculate toque_number
|
||||||
|
|
||||||
|
@property
|
||||||
|
def visible_tags_detail(self):
|
||||||
|
"""Removes some tags from detail Establishment representation"""
|
||||||
|
return self.visible_tags.exclude(category__index_name__in=['tag'])
|
||||||
|
|
||||||
def recalculate_toque_number(self):
|
def recalculate_toque_number(self):
|
||||||
toque_number = 0
|
toque_number = 0
|
||||||
if self.address and self.public_mark:
|
if self.address and self.public_mark:
|
||||||
|
|
|
||||||
|
|
@ -324,3 +324,14 @@ class EstablishmentNoteListCreateSerializer(EstablishmentNoteBaseSerializer):
|
||||||
"""Return establishment instance from view."""
|
"""Return establishment instance from view."""
|
||||||
if self.serializer_view:
|
if self.serializer_view:
|
||||||
return self.serializer_view.get_object()
|
return self.serializer_view.get_object()
|
||||||
|
|
||||||
|
|
||||||
|
class EstablishmentAdminListSerializer(UserShortSerializer):
|
||||||
|
"""Establishment admin serializer."""
|
||||||
|
class Meta:
|
||||||
|
model = UserShortSerializer.Meta.model
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'username',
|
||||||
|
'email'
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ urlpatterns = [
|
||||||
name='note-list-create'),
|
name='note-list-create'),
|
||||||
path('slug/<slug:slug>/notes/<int:note_pk>/', views.EstablishmentNoteRUDView.as_view(),
|
path('slug/<slug:slug>/notes/<int:note_pk>/', views.EstablishmentNoteRUDView.as_view(),
|
||||||
name='note-rud'),
|
name='note-rud'),
|
||||||
|
path('slug/<slug:slug>/admin/', views.EstablishmentAdminView.as_view(),
|
||||||
|
name='establishment-admin-list'),
|
||||||
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
|
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
|
||||||
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
|
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
|
||||||
path('plates/', views.PlateListCreateView.as_view(), name='plates'),
|
path('plates/', views.PlateListCreateView.as_view(), name='plates'),
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from django.shortcuts import get_object_or_404
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import generics, permissions, status
|
from rest_framework import generics, permissions, status
|
||||||
|
|
||||||
|
from account.models import User
|
||||||
from establishment import filters, models, serializers
|
from establishment import filters, models, serializers
|
||||||
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
|
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
|
||||||
from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer
|
from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer
|
||||||
|
|
@ -380,3 +381,14 @@ class EstablishmentPositionListView(generics.ListAPIView):
|
||||||
permission_classes = (permissions.AllowAny,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
queryset = models.Position.objects.all()
|
queryset = models.Position.objects.all()
|
||||||
serializer_class = serializers.PositionBackSerializer
|
serializer_class = serializers.PositionBackSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class EstablishmentAdminView(generics.ListAPIView):
|
||||||
|
"""Establishment admin list view."""
|
||||||
|
serializer_class = serializers.EstablishmentAdminListSerializer
|
||||||
|
permission_classes = (permissions.IsAuthenticatedOrReadOnly, )
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
establishment = get_object_or_404(
|
||||||
|
models.Establishment, slug=self.kwargs['slug'])
|
||||||
|
return User.objects.establishment_admin(establishment).distinct()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""News app views."""
|
"""News app views."""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework import generics, permissions
|
from rest_framework import generics, permissions, response
|
||||||
|
|
||||||
from news import filters, models, serializers
|
from news import filters, models, serializers
|
||||||
from rating.tasks import add_rating
|
from rating.tasks import add_rating
|
||||||
|
|
@ -99,7 +99,10 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView,
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
"""Override get_queryset method."""
|
"""Override get_queryset method."""
|
||||||
return super().get_queryset().with_extended_related()
|
qs = super().get_queryset().with_extended_related()
|
||||||
|
if self.request.country_code:
|
||||||
|
qs = qs.by_country_code(self.request.country_code)
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
|
class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
|
||||||
|
|
@ -107,6 +110,13 @@ class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
|
||||||
"""Resource for a create gallery for news for back-office users."""
|
"""Resource for a create gallery for news for back-office users."""
|
||||||
serializer_class = serializers.NewsBackOfficeGallerySerializer
|
serializer_class = serializers.NewsBackOfficeGallerySerializer
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
_ = super().create(request, *args, **kwargs)
|
||||||
|
news_qs = self.filter_queryset(self.get_queryset())
|
||||||
|
return response.Response(
|
||||||
|
data=serializers.NewsDetailSerializer(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data
|
||||||
|
)
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
"""
|
"""
|
||||||
Returns the object the view is displaying.
|
Returns the object the view is displaying.
|
||||||
|
|
|
||||||
|
|
@ -12,24 +12,9 @@ from search_indexes import serializers, filters, utils
|
||||||
from search_indexes.documents import EstablishmentDocument, NewsDocument
|
from search_indexes.documents import EstablishmentDocument, NewsDocument
|
||||||
from search_indexes.documents.product import ProductDocument
|
from search_indexes.documents.product import ProductDocument
|
||||||
from utils.pagination import ESDocumentPagination
|
from utils.pagination import ESDocumentPagination
|
||||||
from tag.models import TagCategory
|
|
||||||
|
|
||||||
|
|
||||||
class CustomBaseDocumentViewSet(BaseDocumentViewSet):
|
class NewsDocumentViewSet(BaseDocumentViewSet):
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
if self.filter_fields:
|
|
||||||
for name in TagCategory.objects.all().values('index_name'):
|
|
||||||
self.filter_fields.update({
|
|
||||||
f'{name["index_name"]}_id': {
|
|
||||||
'field': 'tags.id',
|
|
||||||
'lookups': [constants.LOOKUP_QUERY_IN]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class NewsDocumentViewSet(CustomBaseDocumentViewSet):
|
|
||||||
"""News document ViewSet."""
|
"""News document ViewSet."""
|
||||||
|
|
||||||
document = NewsDocument
|
document = NewsDocument
|
||||||
|
|
@ -76,11 +61,18 @@ class NewsDocumentViewSet(CustomBaseDocumentViewSet):
|
||||||
)
|
)
|
||||||
|
|
||||||
filter_fields = {
|
filter_fields = {
|
||||||
|
'tags_id': {
|
||||||
|
'field': 'tags.id',
|
||||||
|
'lookups': [
|
||||||
|
constants.LOOKUP_QUERY_IN,
|
||||||
|
constants.LOOKUP_QUERY_EXCLUDE,
|
||||||
|
],
|
||||||
|
},
|
||||||
'tag': {
|
'tag': {
|
||||||
'field': 'tags.id',
|
'field': 'tags.id',
|
||||||
'lookups': [
|
'lookups': [
|
||||||
constants.LOOKUP_QUERY_IN,
|
constants.LOOKUP_QUERY_IN,
|
||||||
constants.LOOKUP_QUERY_EXCLUDE
|
constants.LOOKUP_QUERY_EXCLUDE,
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
'tag_value': {
|
'tag_value': {
|
||||||
|
|
@ -108,7 +100,7 @@ class MobileNewsDocumentViewSet(NewsDocumentViewSet):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentDocumentViewSet(CustomBaseDocumentViewSet):
|
class EstablishmentDocumentViewSet(BaseDocumentViewSet):
|
||||||
"""Establishment document ViewSet."""
|
"""Establishment document ViewSet."""
|
||||||
|
|
||||||
document = EstablishmentDocument
|
document = EstablishmentDocument
|
||||||
|
|
@ -333,7 +325,7 @@ class MobileEstablishmentDocumentViewSet(EstablishmentDocumentViewSet):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ProductDocumentViewSet(CustomBaseDocumentViewSet):
|
class ProductDocumentViewSet(BaseDocumentViewSet):
|
||||||
"""Product document ViewSet."""
|
"""Product document ViewSet."""
|
||||||
|
|
||||||
document = ProductDocument
|
document = ProductDocument
|
||||||
|
|
@ -405,7 +397,7 @@ class ProductDocumentViewSet(CustomBaseDocumentViewSet):
|
||||||
'lookups': [constants.LOOKUP_QUERY_IN],
|
'lookups': [constants.LOOKUP_QUERY_IN],
|
||||||
},
|
},
|
||||||
'country': {
|
'country': {
|
||||||
'field': 'establishment.address.city.country.code',
|
'field': 'establishment.city.country.code',
|
||||||
},
|
},
|
||||||
'wine_colors_id': {
|
'wine_colors_id': {
|
||||||
'field': 'wine_colors.id',
|
'field': 'wine_colors.id',
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,9 @@ class FiltersTagCategoryBaseSerializer(serializers.ModelSerializer):
|
||||||
return obj in ['open_now', ]
|
return obj in ['open_now', ]
|
||||||
|
|
||||||
def get_param_name(self, obj):
|
def get_param_name(self, obj):
|
||||||
return f'{obj.index_name}_id__in'
|
if obj.index_name == 'wine-color':
|
||||||
|
return 'wine_colors_id__in'
|
||||||
|
return 'tags_id__in'
|
||||||
|
|
||||||
def get_fields(self, *args, **kwargs):
|
def get_fields(self, *args, **kwargs):
|
||||||
fields = super(FiltersTagCategoryBaseSerializer, self).get_fields()
|
fields = super(FiltersTagCategoryBaseSerializer, self).get_fields()
|
||||||
|
|
|
||||||
|
|
@ -63,9 +63,20 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
"""ViewSet for TagCategory model."""
|
"""ViewSet for TagCategory model."""
|
||||||
|
|
||||||
serializer_class = serializers.FiltersTagCategoryBaseSerializer
|
serializer_class = serializers.FiltersTagCategoryBaseSerializer
|
||||||
|
index_name_to_order = {
|
||||||
|
'open_now': 9,
|
||||||
|
'works_noon': 8,
|
||||||
|
'works_evening': 7,
|
||||||
|
'pop': 6,
|
||||||
|
'category': 5,
|
||||||
|
'toque_number': 4,
|
||||||
|
'cuisine': 3,
|
||||||
|
'moment': 2,
|
||||||
|
'service': 1,
|
||||||
|
}
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
queryset = self.filter_queryset(self.get_queryset())
|
queryset = self.filter_queryset(self.get_queryset().exclude(public=False))
|
||||||
serializer = self.get_serializer(queryset, many=True)
|
serializer = self.get_serializer(queryset, many=True)
|
||||||
|
|
||||||
result_list = serializer.data
|
result_list = serializer.data
|
||||||
|
|
@ -77,7 +88,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
elif query_params.get('product_type'):
|
elif query_params.get('product_type'):
|
||||||
params_type = query_params.get('product_type')
|
params_type = query_params.get('product_type')
|
||||||
|
|
||||||
week_days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
week_days = tuple(map(_, ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")))
|
||||||
flags = ('toque_number', 'wine_region', 'works_noon', 'works_evening', 'works_now', 'works_at_weekday')
|
flags = ('toque_number', 'wine_region', 'works_noon', 'works_evening', 'works_now', 'works_at_weekday')
|
||||||
filter_flags = {flag_name: False for flag_name in flags}
|
filter_flags = {flag_name: False for flag_name in flags}
|
||||||
additional_flags = []
|
additional_flags = []
|
||||||
|
|
@ -94,19 +105,6 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
for flag_name in additional_flags:
|
for flag_name in additional_flags:
|
||||||
filter_flags[flag_name] = True
|
filter_flags[flag_name] = True
|
||||||
|
|
||||||
if filter_flags['toque_number']:
|
|
||||||
toques = {
|
|
||||||
"index_name": "toque_number",
|
|
||||||
"label_translated": "Toques",
|
|
||||||
"param_name": "toque_number__in",
|
|
||||||
"filters": [{
|
|
||||||
"id": toque_id,
|
|
||||||
"index_name": "toque_%d" % toque_id,
|
|
||||||
"label_translated": "Toque %d" % toque_id
|
|
||||||
} for toque_id in range(6)]
|
|
||||||
}
|
|
||||||
result_list.append(toques)
|
|
||||||
|
|
||||||
if request.query_params.get('product_type') == ProductType.WINE:
|
if request.query_params.get('product_type') == ProductType.WINE:
|
||||||
wine_region_id = query_params.get('wine_region_id__in')
|
wine_region_id = query_params.get('wine_region_id__in')
|
||||||
|
|
||||||
|
|
@ -129,11 +127,30 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
|
|
||||||
result_list.append(wine_regions)
|
result_list.append(wine_regions)
|
||||||
|
|
||||||
|
for item in result_list:
|
||||||
|
if 'filters' in item:
|
||||||
|
item['filters'].sort(key=lambda x: x.get('label_translated'))
|
||||||
|
|
||||||
|
if filter_flags['toque_number']:
|
||||||
|
toques = {
|
||||||
|
"index_name": "toque_number",
|
||||||
|
"label_translated": "Toques",
|
||||||
|
"param_name": "toque_number__in",
|
||||||
|
'type': 'toque',
|
||||||
|
"filters": [{
|
||||||
|
"id": toque_id,
|
||||||
|
"index_name": "toque_%d" % toque_id,
|
||||||
|
"label_translated": "Toque %d" % toque_id
|
||||||
|
} for toque_id in range(6)]
|
||||||
|
}
|
||||||
|
result_list.append(toques)
|
||||||
|
|
||||||
if filter_flags['works_noon']:
|
if filter_flags['works_noon']:
|
||||||
works_noon = {
|
works_noon = {
|
||||||
"index_name": "works_noon",
|
"index_name": "works_noon",
|
||||||
"label_translated": "Open noon",
|
"label_translated": "Open noon",
|
||||||
"param_name": "works_noon__in",
|
"param_name": "works_noon__in",
|
||||||
|
'type': 'weekday',
|
||||||
"filters": [{
|
"filters": [{
|
||||||
"id": weekday,
|
"id": weekday,
|
||||||
"index_name": week_days[weekday].lower(),
|
"index_name": week_days[weekday].lower(),
|
||||||
|
|
@ -148,6 +165,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
"index_name": "works_evening",
|
"index_name": "works_evening",
|
||||||
"label_translated": "Open evening",
|
"label_translated": "Open evening",
|
||||||
"param_name": "works_evening__in",
|
"param_name": "works_evening__in",
|
||||||
|
'type': 'weekday',
|
||||||
"filters": [{
|
"filters": [{
|
||||||
"id": weekday,
|
"id": weekday,
|
||||||
"index_name": week_days[weekday].lower(),
|
"index_name": week_days[weekday].lower(),
|
||||||
|
|
@ -161,7 +179,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
"index_name": "open_now",
|
"index_name": "open_now",
|
||||||
"label_translated": "Open now",
|
"label_translated": "Open now",
|
||||||
"param_name": "open_now",
|
"param_name": "open_now",
|
||||||
"type": True
|
"type": 'bool',
|
||||||
}
|
}
|
||||||
result_list.append(works_now)
|
result_list.append(works_now)
|
||||||
|
|
||||||
|
|
@ -170,6 +188,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
"index_name": "works_at_weekday",
|
"index_name": "works_at_weekday",
|
||||||
"label_translated": "Works at weekday",
|
"label_translated": "Works at weekday",
|
||||||
"param_name": "works_at_weekday__in",
|
"param_name": "works_at_weekday__in",
|
||||||
|
'type': 'weekday',
|
||||||
"filters": [{
|
"filters": [{
|
||||||
"id": weekday,
|
"id": weekday,
|
||||||
"index_name": week_days[weekday].lower(),
|
"index_name": week_days[weekday].lower(),
|
||||||
|
|
@ -180,7 +199,17 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
|
|
||||||
search_view_class = self.define_search_view_by_request(request)
|
search_view_class = self.define_search_view_by_request(request)
|
||||||
facets = search_view_class.as_view({'get': 'list'})(self.mutate_request(self.request)).data['facets']
|
facets = search_view_class.as_view({'get': 'list'})(self.mutate_request(self.request)).data['facets']
|
||||||
return Response(self.remove_empty_filters(result_list, facets))
|
result_list = self.remove_empty_filters(result_list, facets)
|
||||||
|
tag_category = list(filter(lambda x: x.get('index_name') == 'tag', result_list))
|
||||||
|
result_list = [category for category in result_list if category.get('index_name') != 'tag']
|
||||||
|
if len(tag_category):
|
||||||
|
tag_category = list(filter(lambda x: x.get('index_name') == 'pop', tag_category[0]['filters']))
|
||||||
|
if len(tag_category): # we have Pop tag in our results
|
||||||
|
tag_category = tag_category[0]
|
||||||
|
tag_category['param_name'] = 'tags_id__in'
|
||||||
|
result_list.append(tag_category)
|
||||||
|
result_list.sort(key=lambda x: self.index_name_to_order.get(x.get('index_name'), 0), reverse=True)
|
||||||
|
return Response(result_list)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mutate_request(request):
|
def mutate_request(request):
|
||||||
|
|
@ -213,6 +242,46 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove_empty_filters(filters, facets):
|
def remove_empty_filters(filters, facets):
|
||||||
|
# parse facets
|
||||||
|
if facets.get('_filter_tag'):
|
||||||
|
tags_to_preserve = list(map(lambda el: el['key'], facets['_filter_tag']['tag']['buckets']))
|
||||||
|
if facets.get('_filter_wine_colors'):
|
||||||
|
wine_colors_to_preserve = list(
|
||||||
|
map(lambda el: el['key'], facets['_filter_wine_colors']['wine_colors']['buckets']))
|
||||||
|
if facets.get('_filter_wine_region_id'):
|
||||||
|
wine_regions_to_preserve = list(
|
||||||
|
map(lambda el: el['key'], facets['_filter_wine_region_id']['wine_region_id']['buckets']))
|
||||||
|
if facets.get('_filter_toque_number'):
|
||||||
|
toque_numbers = list(map(lambda el: el['key'], facets['_filter_toque_number']['toque_number']['buckets']))
|
||||||
|
if facets.get('_filter_works_noon'):
|
||||||
|
works_noon = list(map(lambda el: el['key'], facets['_filter_works_noon']['works_noon']['buckets']))
|
||||||
|
if facets.get('_filter_works_evening'):
|
||||||
|
works_evening = list(map(lambda el: el['key'], facets['_filter_works_evening']['works_evening']['buckets']))
|
||||||
|
if facets.get('_filter_works_at_weekday'):
|
||||||
|
works_at_weekday = list(
|
||||||
|
map(lambda el: el['key'], facets['_filter_works_at_weekday']['works_at_weekday']['buckets']))
|
||||||
|
if facets.get('_filter_works_now'):
|
||||||
|
works_now = list(map(lambda el: el['key'], facets['_filter_works_now']['works_now']['buckets']))
|
||||||
|
|
||||||
|
# remove empty filters
|
||||||
|
for category in filters:
|
||||||
|
param_name = category.get('param_name')
|
||||||
|
if param_name == 'tags_id__in':
|
||||||
|
category['filters'] = list(filter(lambda tag: tag['id'] in tags_to_preserve, category['filters']))
|
||||||
|
elif param_name == 'wine_colors_id__in':
|
||||||
|
category['filters'] = list(
|
||||||
|
filter(lambda tag: tag['id'] in wine_colors_to_preserve, category['filters']))
|
||||||
|
elif param_name == 'wine_region_id__in':
|
||||||
|
category['filters'] = list(
|
||||||
|
filter(lambda tag: tag['id'] in wine_regions_to_preserve, category['filters']))
|
||||||
|
elif param_name == 'toque_number__in':
|
||||||
|
category['filters'] = list(filter(lambda tag: tag['id'] in toque_numbers, category['filters']))
|
||||||
|
elif param_name == 'works_noon__in':
|
||||||
|
category['filters'] = list(filter(lambda tag: tag['id'] in works_noon, category['filters']))
|
||||||
|
elif param_name == 'works_evening__in':
|
||||||
|
category['filters'] = list(filter(lambda tag: tag['id'] in works_evening, category['filters']))
|
||||||
|
elif param_name == 'works_at_weekday__in':
|
||||||
|
category['filters'] = list(filter(lambda tag: tag['id'] in works_at_weekday, category['filters']))
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1224,6 +1224,21 @@ class Footers(MigrateMixin):
|
||||||
db_table = 'footers'
|
db_table = 'footers'
|
||||||
|
|
||||||
|
|
||||||
|
class OwnershipAffs(MigrateMixin):
|
||||||
|
using = 'legacy'
|
||||||
|
|
||||||
|
role = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
state = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
account_id = models.IntegerField(blank=True, null=True)
|
||||||
|
establishment_id = models.IntegerField(blank=True, null=True)
|
||||||
|
created_at = models.DateTimeField()
|
||||||
|
updated_at = models.DateTimeField()
|
||||||
|
requester_id = models.IntegerField(blank=True, null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
db_table = 'ownership_affs'
|
||||||
|
|
||||||
class Panels(MigrateMixin):
|
class Panels(MigrateMixin):
|
||||||
using = 'legacy'
|
using = 'legacy'
|
||||||
|
|
||||||
|
|
|
||||||
12
db_migration_resolve.txt
Normal file
12
db_migration_resolve.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
В случае возникновения проблемы с применением миграции account 0027:
|
||||||
|
|
||||||
|
1 Удаляем unique together constrain для app - account
|
||||||
|
ALTER TABLE account_userrole
|
||||||
|
DROP CONSTRAINT account_userrole_user_id_role_id_26fa14c4_uniq;
|
||||||
|
2 Правим миграцию 0023
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='userrole',
|
||||||
|
unique_together=set(),
|
||||||
|
),
|
||||||
|
3 Применяем account 0027
|
||||||
|
4 Возвращаем миграцию account 0023, в исходное состояние
|
||||||
Loading…
Reference in New Issue
Block a user