732 lines
27 KiB
Python
732 lines
27 KiB
Python
import re
|
|
|
|
from django.contrib.contenttypes.fields import ContentType
|
|
from django.contrib.postgres.fields import JSONField
|
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
|
from django.db import models
|
|
from django.utils.translation import gettext_lazy as _
|
|
from mptt.models import MPTTModel, TreeForeignKey
|
|
from django.conf import settings
|
|
from collection import tasks
|
|
|
|
from location.models import Country, Region, WineRegion, WineSubRegion
|
|
from review.models import Review
|
|
from translation.models import Language
|
|
from utils.models import (
|
|
ProjectBaseMixin, TJSONField, TranslatedFieldsMixin,
|
|
URLImageMixin, IntermediateGalleryModelMixin
|
|
)
|
|
from utils.querysets import RelatedObjectsCountMixin
|
|
|
|
|
|
# Mixins
|
|
class CollectionNameMixin(models.Model):
|
|
"""CollectionName mixin"""
|
|
name = models.CharField(_('name'), max_length=250)
|
|
|
|
class Meta:
|
|
"""Meta class"""
|
|
abstract = True
|
|
|
|
|
|
class CollectionDateMixin(models.Model):
|
|
"""CollectionDate mixin"""
|
|
start = models.DateTimeField(blank=True, null=True, default=None,
|
|
verbose_name=_('start'))
|
|
end = models.DateTimeField(blank=True, null=True, default=None,
|
|
verbose_name=_('end'))
|
|
|
|
class Meta:
|
|
"""Meta class"""
|
|
abstract = True
|
|
|
|
|
|
# Models
|
|
class CollectionQuerySet(RelatedObjectsCountMixin):
|
|
"""QuerySet for model Collection"""
|
|
|
|
def by_country_code(self, code):
|
|
"""Filter collection by country code."""
|
|
return self.filter(country__code=code)
|
|
|
|
def published(self):
|
|
"""Returned only published collection"""
|
|
return self.filter(is_publish=True)
|
|
|
|
|
|
class Collection(ProjectBaseMixin, CollectionDateMixin,
|
|
TranslatedFieldsMixin, URLImageMixin):
|
|
"""Collection model."""
|
|
STR_FIELD_NAME = 'name'
|
|
|
|
ORDINARY = 0 # Ordinary collection
|
|
POP = 1 # POP collection
|
|
|
|
COLLECTION_TYPES = (
|
|
(ORDINARY, _('Ordinary')),
|
|
(POP, _('Pop')),
|
|
)
|
|
|
|
name = TJSONField(verbose_name=_('name'),
|
|
help_text='{"en-GB":"some text"}')
|
|
collection_type = models.PositiveSmallIntegerField(choices=COLLECTION_TYPES,
|
|
default=ORDINARY,
|
|
verbose_name=_('Collection type'))
|
|
is_publish = models.BooleanField(
|
|
default=False, verbose_name=_('Publish status'))
|
|
on_top = models.BooleanField(
|
|
default=False, verbose_name=_('Position on top'))
|
|
country = models.ForeignKey(
|
|
'location.Country', verbose_name=_('country'), on_delete=models.CASCADE)
|
|
block_size = JSONField(
|
|
_('collection block properties'), null=True, blank=True,
|
|
default=None, help_text='{"width": "250px", "height":"250px"}')
|
|
description = TJSONField(
|
|
_('description'), null=True, blank=True,
|
|
default=None, help_text='{"en-GB":"some text"}')
|
|
slug = models.SlugField(max_length=50, unique=True,
|
|
verbose_name=_('Collection slug'), editable=True, null=True)
|
|
old_id = models.IntegerField(null=True, blank=True)
|
|
|
|
rank = models.IntegerField(null=True, default=None)
|
|
|
|
objects = CollectionQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('collection')
|
|
verbose_name_plural = _('collections')
|
|
|
|
@property
|
|
def _related_objects(self) -> list:
|
|
"""Return list of related objects."""
|
|
related_objects = []
|
|
# get related objects
|
|
for related_object in self._meta.related_objects:
|
|
related_objects.append(related_object)
|
|
return related_objects
|
|
|
|
@property
|
|
def count_related_objects(self) -> int:
|
|
"""Return count of related objects."""
|
|
counter = 0
|
|
# count of related objects
|
|
for related_object in [related_object.name for related_object in self._related_objects]:
|
|
counter += getattr(self, f'{related_object}').count()
|
|
return counter
|
|
|
|
@property
|
|
def related_object_names(self) -> list:
|
|
"""Return related object names."""
|
|
raw_objects = []
|
|
for related_object in [related_object.name for related_object in self._related_objects]:
|
|
instances = getattr(self, f'{related_object}')
|
|
if instances.exists():
|
|
for instance in instances.all():
|
|
raw_object = (instance.id, instance.establishment_type.index_name,
|
|
instance.slug) if \
|
|
hasattr(instance, 'slug') else (instance.id, None, None)
|
|
raw_objects.append(raw_object)
|
|
|
|
# parse slugs
|
|
related_objects = []
|
|
object_names = set()
|
|
re_pattern = r'[\w]+'
|
|
for object_id, object_type, raw_name, in raw_objects:
|
|
result = re.findall(re_pattern, raw_name)
|
|
if result:
|
|
name = ' '.join(result).capitalize()
|
|
if name not in object_names:
|
|
related_objects.append({
|
|
'id': object_id,
|
|
'establishment_type': object_type,
|
|
'name': name
|
|
})
|
|
object_names.add(name)
|
|
|
|
return related_objects
|
|
|
|
|
|
class GuideTypeQuerySet(models.QuerySet):
|
|
"""QuerySet for model GuideType."""
|
|
|
|
|
|
class GuideType(ProjectBaseMixin):
|
|
"""GuideType model."""
|
|
|
|
name = models.SlugField(max_length=255, unique=True,
|
|
verbose_name=_('code'))
|
|
|
|
objects = GuideTypeQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide type')
|
|
verbose_name_plural = _('guide types')
|
|
|
|
def __str__(self):
|
|
"""Overridden str dunder method."""
|
|
return self.name
|
|
|
|
|
|
class GuideQuerySet(models.QuerySet):
|
|
"""QuerySet for Guide."""
|
|
|
|
def with_base_related(self):
|
|
"""Return QuerySet with related."""
|
|
return self.select_related('guide_type', 'site')
|
|
|
|
def by_country_id(self, country_id):
|
|
"""Return QuerySet filtered by country code."""
|
|
return self.filter(country_json__id__contains=country_id)
|
|
|
|
def annotate_in_restaurant_section(self):
|
|
"""Annotate flag if GuideElement in RestaurantSectionNode."""
|
|
return self.annotate(
|
|
in_restaurant_section=models.Case(
|
|
models.When(
|
|
guideelement__guide_element_type__name='EstablishmentNode',
|
|
guideelement__parent__guide_element_type__name='RestaurantSectionNode',
|
|
then=True),
|
|
default=False,
|
|
output_field=models.BooleanField(default=False)
|
|
)
|
|
)
|
|
|
|
def annotate_in_shop_section(self):
|
|
"""Annotate flag if GuideElement in ShopSectionNode."""
|
|
return self.annotate(
|
|
in_shop_section=models.Case(
|
|
models.When(
|
|
guideelement__guide_element_type__name='EstablishmentNode',
|
|
guideelement__parent__guide_element_type__name='ShopSectionNode',
|
|
then=True),
|
|
default=False,
|
|
output_field=models.BooleanField(default=False)
|
|
)
|
|
)
|
|
|
|
def annotate_restaurant_counter(self):
|
|
"""Return QuerySet with annotated field - restaurant_counter."""
|
|
return self.annotate_in_restaurant_section().annotate(
|
|
restaurant_counter=models.Count(
|
|
'guideelement',
|
|
filter=models.Q(in_restaurant_section=True) &
|
|
models.Q(guideelement__parent_id__isnull=False),
|
|
distinct=True))
|
|
|
|
def annotate_shop_counter(self):
|
|
"""Return QuerySet with annotated field - shop_counter."""
|
|
return self.annotate_in_shop_section().annotate(
|
|
shop_counter=models.Count(
|
|
'guideelement',
|
|
filter=models.Q(in_shop_section=True) &
|
|
models.Q(guideelement__parent_id__isnull=False),
|
|
distinct=True))
|
|
|
|
def annotate_wine_counter(self):
|
|
"""Return QuerySet with annotated field - shop_counter."""
|
|
return self.annotate_in_restaurant_section().annotate(
|
|
wine_counter=models.Count(
|
|
'guideelement',
|
|
filter=models.Q(guideelement__guide_element_type__name='WineNode') &
|
|
models.Q(guideelement__parent_id__isnull=False),
|
|
distinct=True))
|
|
|
|
def annotate_present_objects_counter(self):
|
|
"""Return QuerySet with annotated field - present_objects_counter."""
|
|
return self.annotate_in_restaurant_section().annotate(
|
|
present_objects_counter=models.Count(
|
|
'guideelement',
|
|
filter=models.Q(guideelement__guide_element_type__name__in=['EstablishmentNode', 'WineNode']) &
|
|
models.Q(guideelement__parent_id__isnull=False),
|
|
distinct=True))
|
|
|
|
|
|
class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin):
|
|
"""Guide model."""
|
|
BUILT = 0
|
|
WAITING = 1
|
|
REMOVING = 2
|
|
BUILDING = 3
|
|
|
|
STATE_CHOICES = (
|
|
(BUILT, 'built'),
|
|
(WAITING, 'waiting'),
|
|
(REMOVING, 'removing'),
|
|
(BUILDING, 'building'),
|
|
)
|
|
|
|
start = models.DateTimeField(null=True,
|
|
verbose_name=_('start'))
|
|
vintage = models.IntegerField(validators=[MinValueValidator(1900),
|
|
MaxValueValidator(2100)],
|
|
null=True,
|
|
verbose_name=_('guide vintage year'))
|
|
slug = models.SlugField(max_length=255, unique=True, null=True,
|
|
verbose_name=_('slug'))
|
|
guide_type = models.ForeignKey('GuideType', on_delete=models.PROTECT,
|
|
null=True,
|
|
verbose_name=_('type'))
|
|
site = models.ForeignKey('main.SiteSettings', on_delete=models.SET_NULL,
|
|
null=True,
|
|
verbose_name=_('site settings'))
|
|
state = models.PositiveSmallIntegerField(default=WAITING, choices=STATE_CHOICES,
|
|
verbose_name=_('state'))
|
|
count_related_objects = models.PositiveIntegerField(
|
|
default=0,
|
|
help_text=_('* after rebuild guide, refresh count of related guide elements'),
|
|
verbose_name=_('count of related guide elements during initialization'))
|
|
old_id = models.IntegerField(blank=True, null=True)
|
|
|
|
objects = GuideQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide')
|
|
verbose_name_plural = _('guides')
|
|
|
|
def __str__(self):
|
|
"""String method."""
|
|
return f'{self.name}'
|
|
|
|
# todo: for test use, use annotation instead
|
|
# @property
|
|
# def restaurant_counter_prop(self):
|
|
# counter = 0
|
|
# root_node = GuideElement.objects.get_root_node(self)
|
|
# if root_node:
|
|
# descendants = GuideElement.objects.get_root_node(self).get_descendants()
|
|
# if descendants:
|
|
# restaurant_section_nodes = descendants.filter(
|
|
# guide_element_type__name='RestaurantSectionNode')
|
|
# counter = descendants.filter(guide_element_type__name='EstablishmentNode',
|
|
# parent__in=restaurant_section_nodes,
|
|
# parent_id__isnull=True).count()
|
|
# return counter
|
|
#
|
|
# @property
|
|
# def shop_counter_prop(self):
|
|
# counter = 0
|
|
# root_node = GuideElement.objects.get_root_node(self)
|
|
# if root_node:
|
|
# descendants = GuideElement.objects.get_root_node(self).get_descendants()
|
|
# if descendants:
|
|
# shop_section_nodes = descendants.filter(
|
|
# guide_element_type__name='ShopSectionNode')
|
|
# counter = descendants.filter(guide_element_type__name='EstablishmentNode',
|
|
# parent__in=shop_section_nodes,
|
|
# parent_id__isnull=True).count()
|
|
# return counter
|
|
#
|
|
# @property
|
|
# def wine_counter_prop(self):
|
|
# counter = 0
|
|
# root_node = GuideElement.objects.get_root_node(self)
|
|
# if root_node:
|
|
# descendants = GuideElement.objects.get_root_node(self).get_descendants()
|
|
# if descendants:
|
|
# counter = descendants.filter(guide_element_type__name='WineNode',
|
|
# parent_id__isnull=True).count()
|
|
# return counter
|
|
|
|
def update_count_related_objects(self, nodes: set = ('EstablishmentNode', 'WineNode')):
|
|
"""Update count of related guide element objects."""
|
|
descendants = GuideElement.objects.get_root_node(self) \
|
|
.get_descendants()
|
|
if descendants:
|
|
updated_count = descendants.filter(
|
|
guide_element_type__name__in=nodes).count()
|
|
self.count_related_objects = updated_count
|
|
self.save()
|
|
|
|
|
|
class AdvertorialQuerySet(models.QuerySet):
|
|
"""QuerySet for model Advertorial."""
|
|
|
|
|
|
class Advertorial(ProjectBaseMixin):
|
|
"""Guide advertorial model."""
|
|
number_of_pages = models.PositiveIntegerField(
|
|
verbose_name=_('number of pages'),
|
|
help_text=_('the total number of reserved pages'))
|
|
right_pages = models.PositiveIntegerField(
|
|
verbose_name=_('number of right pages'),
|
|
help_text=_('the number of right pages (which are part of total number).'))
|
|
guide_element = models.OneToOneField('GuideElement', on_delete=models.CASCADE,
|
|
related_name='advertorial',
|
|
verbose_name=_('guide element'))
|
|
old_id = models.IntegerField(blank=True, null=True)
|
|
|
|
objects = AdvertorialQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('advertorial')
|
|
verbose_name_plural = _('advertorials')
|
|
|
|
|
|
class GuideFilterQuerySet(models.QuerySet):
|
|
"""QuerySet for model GuideFilter."""
|
|
|
|
|
|
class GuideFilter(ProjectBaseMixin):
|
|
"""Guide filter model."""
|
|
establishment_type_json = JSONField(blank=True, null=True,
|
|
verbose_name='establishment types')
|
|
country_json = JSONField(blank=True, null=True,
|
|
verbose_name='countries')
|
|
region_json = JSONField(blank=True, null=True,
|
|
verbose_name='regions')
|
|
sub_region_json = JSONField(blank=True, null=True,
|
|
verbose_name='sub regions')
|
|
wine_region_json = JSONField(blank=True, null=True,
|
|
verbose_name='wine regions')
|
|
with_mark = models.BooleanField(default=True,
|
|
verbose_name=_('with mark'),
|
|
help_text=_('exclude empty marks?'))
|
|
locale_json = JSONField(blank=True, null=True,
|
|
verbose_name='locales')
|
|
max_mark = models.FloatField(verbose_name=_('max mark'),
|
|
null=True,
|
|
help_text=_('mark under'))
|
|
min_mark = models.FloatField(verbose_name=_('min mark'),
|
|
null=True,
|
|
help_text=_('mark over'))
|
|
review_vintage_json = JSONField(verbose_name='review vintage years')
|
|
review_state_json = JSONField(blank=True, null=True,
|
|
verbose_name='review states')
|
|
guide = models.OneToOneField(Guide, on_delete=models.CASCADE,
|
|
verbose_name=_('guide'))
|
|
old_id = models.IntegerField(blank=True, null=True)
|
|
|
|
objects = GuideFilterQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide filter')
|
|
verbose_name_plural = _('guide filters')
|
|
|
|
def get_value_list(self, json_field: dict,
|
|
model: object,
|
|
lookup_field: str,
|
|
search_field: int = 'id') -> list:
|
|
"""
|
|
Function to return an array with correct values from ids.
|
|
Algorithm:
|
|
1 Get values from json_field
|
|
2 Try to find model instances by search field and value from json field
|
|
3 If instance was found, then put value into array from instance by lookup field
|
|
"""
|
|
|
|
value_list = []
|
|
if hasattr(model, 'objects'):
|
|
for value in getattr(json_field, 'get')(search_field):
|
|
qs = model.objects.filter(**{search_field: value})
|
|
if qs.exists():
|
|
value_list.append(getattr(qs.first(), lookup_field))
|
|
return value_list
|
|
|
|
@property
|
|
def establishment_types(self):
|
|
from establishment.models import EstablishmentType
|
|
return self.get_value_list(json_field=self.establishment_type_json,
|
|
model=EstablishmentType,
|
|
lookup_field='index_name')
|
|
|
|
@property
|
|
def establishment_type_ids(self):
|
|
from establishment.models import EstablishmentType
|
|
return self.get_value_list(json_field=self.establishment_type_json,
|
|
model=EstablishmentType,
|
|
lookup_field='id')
|
|
|
|
@property
|
|
def locales(self):
|
|
return self.get_value_list(json_field=self.locale_json,
|
|
model=Language,
|
|
lookup_field='locale')
|
|
|
|
@property
|
|
def review_states(self):
|
|
states = []
|
|
for state in self.review_state_json.get('state'):
|
|
status_field = [field for field in Review._meta.fields
|
|
if field.name == 'status'][0]
|
|
status_field_id = Review._meta.fields.index(status_field)
|
|
states.append(dict(Review._meta.fields[status_field_id].choices).get(state))
|
|
return states
|
|
|
|
@property
|
|
def country_names(self):
|
|
return self.get_value_list(json_field=self.country_json,
|
|
model=Country,
|
|
lookup_field='name_translated')
|
|
|
|
@property
|
|
def country_ids(self):
|
|
return self.get_value_list(json_field=self.country_json,
|
|
model=Country,
|
|
lookup_field='id')
|
|
|
|
@property
|
|
def region_names(self):
|
|
return self.get_value_list(json_field=self.region_json,
|
|
model=Region,
|
|
lookup_field='name')
|
|
|
|
@property
|
|
def region_ids(self):
|
|
return self.get_value_list(json_field=self.region_json,
|
|
model=Region,
|
|
lookup_field='id')
|
|
|
|
@property
|
|
def sub_region_names(self):
|
|
return self.get_value_list(json_field=self.sub_region_json,
|
|
model=Region,
|
|
lookup_field='name_translated')
|
|
|
|
@property
|
|
def sub_region_ids(self):
|
|
return self.get_value_list(json_field=self.sub_region_json,
|
|
model=Region,
|
|
lookup_field='id')
|
|
|
|
@property
|
|
def wine_region_ids(self):
|
|
return self.get_value_list(json_field=self.wine_region_json,
|
|
model=WineRegion,
|
|
lookup_field='id')
|
|
|
|
@property
|
|
def review_vintages(self):
|
|
return self.review_vintage_json.get('vintage')
|
|
|
|
@property
|
|
def available_filters(self):
|
|
filters = list()
|
|
for i in self._meta.fields:
|
|
if isinstance(i, JSONField):
|
|
has_values = list(getattr(self, f'{i.name}').values())[0]
|
|
if has_values:
|
|
filters.append(i.name)
|
|
return filters
|
|
|
|
@property
|
|
def establishment_filter_set(self):
|
|
filters = {
|
|
# establishment.Establishment
|
|
'public_mark__in': [self.min_mark, self.max_mark],
|
|
# review.Reviews
|
|
'reviews__vintage__in': self.review_vintages,
|
|
}
|
|
|
|
if self.establishment_type_ids:
|
|
filters.update({
|
|
# establishment.EstablishmentType
|
|
'establishment_type_id__in': self.establishment_type_ids,
|
|
})
|
|
|
|
if self.country_ids:
|
|
filters.update({
|
|
# location.Country
|
|
'address__city__country_id__in': self.country_ids,
|
|
})
|
|
|
|
if self.region_ids:
|
|
filters.update({
|
|
# location.Region
|
|
'address__city__region__parent_id__in': self.region_ids,
|
|
})
|
|
|
|
if self.sub_region_ids:
|
|
filters.update({
|
|
# location.Region
|
|
'address__city__region__parent_id__in': self.region_ids,
|
|
'address__city__region_id__in': self.sub_region_ids,
|
|
})
|
|
|
|
if self.wine_region_ids:
|
|
filters.update({
|
|
# location.WineRegion
|
|
'wine_region_id__in': self.wine_region_ids,
|
|
})
|
|
|
|
if self.with_mark:
|
|
filters.update({
|
|
# establishment.Establishment
|
|
'public_mark__isnull': False,
|
|
})
|
|
|
|
if self.locale_json:
|
|
filters.update({
|
|
'reviews__text__has_any_keys': self.locales,
|
|
})
|
|
|
|
return filters
|
|
|
|
|
|
class GuideElementType(models.Model):
|
|
"""Model for type of guide elements."""
|
|
|
|
name = models.CharField(max_length=50,
|
|
verbose_name=_('name'))
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide element type')
|
|
verbose_name_plural = _('guide element types')
|
|
|
|
def __str__(self):
|
|
"""Overridden str dunder."""
|
|
return self.name
|
|
|
|
|
|
class GuideWineColorSectionQuerySet(models.QuerySet):
|
|
"""QuerySet for model GuideWineColorSection."""
|
|
|
|
|
|
class GuideWineColorSection(ProjectBaseMixin):
|
|
"""Sections for wine colors."""
|
|
|
|
name = models.CharField(max_length=255, verbose_name=_('section name'))
|
|
|
|
objects = GuideWineColorSectionQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide wine color section')
|
|
verbose_name_plural = _('guide wine color sections')
|
|
|
|
|
|
class GuideElementSectionCategoryQuerySet(models.QuerySet):
|
|
"""QuerySet for model GuideElementSectionCategory."""
|
|
|
|
|
|
class GuideElementSectionCategory(ProjectBaseMixin):
|
|
"""Section category for guide element."""
|
|
|
|
name = models.CharField(max_length=255,
|
|
verbose_name=_('category name'))
|
|
|
|
objects = GuideElementSectionCategoryQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide element section category')
|
|
verbose_name_plural = _('guide element section categories')
|
|
|
|
|
|
class GuideElementSectionQuerySet(models.QuerySet):
|
|
"""QuerySet for model GuideElementSection."""
|
|
|
|
|
|
class GuideElementSection(ProjectBaseMixin):
|
|
"""Sections for guide element."""
|
|
|
|
name = models.CharField(max_length=255, verbose_name=_('section name'))
|
|
category = models.ForeignKey(GuideElementSectionCategory, on_delete=models.PROTECT,
|
|
verbose_name=_('category'))
|
|
old_id = models.PositiveIntegerField(blank=True, null=True, default=None,
|
|
verbose_name=_('old id'))
|
|
|
|
objects = GuideElementSectionQuerySet.as_manager()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide element section')
|
|
verbose_name_plural = _('guide element sections')
|
|
|
|
|
|
class GuideElementManager(models.Manager):
|
|
"""Manager for model GuideElement."""
|
|
|
|
def get_root_node(self, guide):
|
|
"""Return guide root element node."""
|
|
qs = self.filter(guide=guide, guide_element_type__name='Root')
|
|
if qs.exists():
|
|
return qs.first()
|
|
|
|
|
|
class GuideElementQuerySet(models.QuerySet):
|
|
"""QuerySet for model Guide elements."""
|
|
|
|
def base_related(self):
|
|
"""Return QuerySet with base related."""
|
|
return self.select_related(
|
|
'guide_element_type',
|
|
'establishment',
|
|
'review',
|
|
'wine_region',
|
|
'product',
|
|
'city',
|
|
'wine_color_section',
|
|
'section',
|
|
'guide',
|
|
'label_photo',
|
|
)
|
|
|
|
def restaurant_nodes(self):
|
|
"""Return GuideElement with type RestaurantSectionNode."""
|
|
return self.filter(guide_element_type__name='RestaurantSectionNode')
|
|
|
|
def shop_nodes(self):
|
|
"""Return GuideElement with type ShopSectionNode."""
|
|
return self.filter(guide_element_type__name='ShopSectionNode')
|
|
|
|
def wine_nodes(self):
|
|
"""Return GuideElement with type WineNode."""
|
|
return self.filter(guide_element_type__name='WineNode')
|
|
|
|
def descendants(self):
|
|
"""Return QuerySet with descendants."""
|
|
return self.exclude(guide_element_type__name='Root')
|
|
|
|
|
|
class GuideElement(ProjectBaseMixin, MPTTModel):
|
|
"""Frozen state of elements of guide instance."""
|
|
|
|
guide_element_type = models.ForeignKey('GuideElementType', on_delete=models.SET_NULL,
|
|
null=True,
|
|
verbose_name=_('guide element type'))
|
|
establishment = models.ForeignKey('establishment.Establishment', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
review = models.ForeignKey('review.Review', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
wine_region = models.ForeignKey('location.WineRegion', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
product = models.ForeignKey('product.Product', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
priority = models.IntegerField(null=True, blank=True, default=None)
|
|
city = models.ForeignKey('location.City', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
wine_color_section = models.ForeignKey('GuideWineColorSection', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
section = models.ForeignKey('GuideElementSection', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
guide = models.ForeignKey('Guide', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None)
|
|
parent = TreeForeignKey('self', on_delete=models.CASCADE,
|
|
null=True, blank=True,
|
|
related_name='children')
|
|
label_photo = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL,
|
|
null=True, blank=True, default=None,
|
|
verbose_name=_('label photo'))
|
|
old_id = models.PositiveIntegerField(blank=True, null=True, default=None,
|
|
verbose_name=_('old id'))
|
|
|
|
objects = GuideElementManager.from_queryset(GuideElementQuerySet)()
|
|
|
|
class Meta:
|
|
"""Meta class."""
|
|
verbose_name = _('guide element')
|
|
verbose_name_plural = _('guide elements')
|
|
|
|
class MPTTMeta:
|
|
order_insertion_by = ['guide_element_type']
|
|
|
|
def __str__(self):
|
|
"""Overridden dunder method."""
|
|
return self.guide_element_type.name if self.guide_element_type else self.id
|