class ResidentalComplexFeature(models.Model): title = models.CharField( verbose_name=_('заголовок'), max_length=127, ) description = models.TextField( verbose_name=_('описание'), max_length=500, ) image = models.ImageField( verbose_name=_('изображение'), upload_to=get_file_path, ) image_spec = spec_factory(680, 450, to_fit=False) thumbnail_admin = spec_factory(100, 100) residental_complex = models.ForeignKey( ResidentalComplex, on_delete=models.CASCADE, related_name='features', ) def __str__(self): return self.title class Meta: verbose_name = _('особенность комплекса') verbose_name_plural = _('особенности комплекса')
class NewApartment(Apartment): """ It will be objects of layouts for now """ is_primary = True buildings = models.ManyToManyField( 'NewBuilding', verbose_name=_('планировка присутсвует в домах'), ) residental_complex = models.ForeignKey( 'ResidentalComplex', verbose_name=_('комплекс'), ) date_of_construction = models.DateField( editable=False, null=True, blank=True, ) layout_small = spec_factory(260, 250, source='layout') layout_large = spec_factory(690, 640, source='layout') def get_residental_complex(self): return self.residental_complex def get_neighbourhood(self): return self.residental_complex.neighbourhood def get_buildings(self): return self.buildings.filter(is_active=True) def get_date_of_construction(self): return get_quarter_verbose(self.date_of_construction) def _set_date_of_construction(self): """ Set self.date_of_construction as nearest date_of_construction of related buildings. return Bool changed this field or not""" buildings = self.get_buildings() date = buildings.aggregate( Min('date_of_construction')).get('date_of_construction__min') date_origin = self.date_of_construction self.date_of_construction = date return not date_origin == date def is_built(self): if self.date_of_construction: return self.date_of_construction <= datetime.date.today() @property def full_price(self): return self.price class Meta: verbose_name = _('объект "планировка"') verbose_name_plural = _('планировки') ordering = ('rooms', )
class Award(BaseDraggapbleImage): image_thumbnail = spec_factory(320, 430) thumbnail_admin = spec_factory(90, 120) def __str__(self): return _('грамота №%(pk)s') % {'pk': self.pk} class Meta: ordering = ['position'] verbose_name = _('грамота') verbose_name_plural = _('грамоты')
class ResidentalComplexImage(BaseDraggapbleImage): residental_complex = models.ForeignKey( ResidentalComplex, on_delete=models.CASCADE, related_name='photos', ) image_spec = spec_factory(**new_buildings_spec_kwargs)
class BankPartner(BaseDraggapbleImage): title = models.CharField( verbose_name=_('название банка'), max_length=127, ) thumbnail_34_34 = spec_factory(34, 34) thumbnail_64_64 = thumbnail_64_64 thumbnail_260_260 = thumbnail_260_260 def __str__(self): return self.title class Meta: ordering = ('position', ) verbose_name = _('объект банк-партнер') verbose_name_plural = _('банки-партнеры')
class Feedback(models.Model): author = models.CharField( verbose_name=_('клиент'), max_length=127, ) bought = models.ForeignKey( ResidentalComplex, verbose_name=_('где купили'), ) date = models.DateField( verbose_name=_('когда совершили сделку'), blank=True, null=True, ) message = models.TextField(verbose_name=_('текст отзыва')) work_at = models.CharField( verbose_name=_('место работы'), max_length=127, blank=True, null=True, ) image = models.ImageField(verbose_name=_('фото'), upload_to=get_file_path) is_active = models.BooleanField( verbose_name=_('отображать на сайте'), default=True, ) image_250_250 = spec_factory( 250, 250, format='JPEG', options__quality=70, to_fit=False, ) # social_media_links - one to many field def __str__(self): return _("{author} из {company}").format(author=self.author, company=self.work_at) def get_social_media_links(self): return self.social_media_links.all() class Meta: verbose_name = _('отзыв') verbose_name_plural = _('отзывы') ordering = ('-date', '-id')
class ResaleCharacteristic(Characteristic): class Meta: verbose_name = _('объект "характеристика вторички"') verbose_name_plural = _('характеристики вторички') proxy = True class ResaleWatermark(BaseWatermarkProcessor): pass resale_image_spec = spec_factory(750, 500, pre_processors=[ResaleWatermark()], options__quality=70, format='jpeg') layout_image_spec = copy.deepcopy(resale_image_spec) layout_image_spec.source = 'layout' front_image_spec = spec_factory( 370, 320, pre_processors=[ResaleWatermark()], format='jpeg', ) class TransactionMixin(models.Model): ACTIVE = 'ACTIVE'
class ResidentalComplex(models.Model): """ it is aggregate of houses. They are built in the same style by the same builder. """ type_of_complex = models.ForeignKey( TypeOfComplex, verbose_name=_('тип комплекса'), default=1, help_text=_('Жилой комплекс/Микрорайон/...'), on_delete=models.PROTECT, ) name = models.CharField( verbose_name=_('название'), max_length=127, unique=True, ) slug = models.SlugField( verbose_name=_('строка запроса'), max_length=127, db_index=True, allow_unicode=True, ) description = models.TextField(verbose_name=_('описание ЖК'), ) builder = models.ForeignKey( 'Builder', verbose_name=_('застройщик'), on_delete=models.PROTECT, ) # one to many "photos" characteristics = models.ManyToManyField( 'ResidentalComplexCharacteristic', verbose_name=_('характеристики ЖК'), blank=True, ) front_image = models.ImageField( verbose_name=_('основное изображение'), upload_to=get_file_path, blank=True, null=True, ) front_image_spec_normal = spec_factory(source='front_image', **new_buildings_spec_kwargs) front_image_spec_heading = spec_factory( 1200, 900, source='front_image', format='JPEG', options__quality=100, ) front_image_thumbnail = spec_factory( 555, 328, source='front_image', format='JPEG', to_fit=False, # options__quality=60, ) # one to many "features" # one to many "houses" video_link = models.URLField( verbose_name=_('ссылка на видео'), null=True, blank=True, ) presentation = models.FileField( verbose_name=_('презентация ЖК'), null=True, blank=True, ) # one to many "documents_for_construction" is_active = models.BooleanField( verbose_name=_('отображать в новостройках'), default=False, ) is_popular = models.BooleanField( verbose_name=_('отображать на главной'), default=False, ) number_of_flats = models.PositiveIntegerField( verbose_name=_('количество квартир в комплексе'), help_text=_('оставьте пустым для автоматического подсчета'), default=None, null=True, blank=True, ) number_of_buildings = models.PositiveIntegerField( verbose_name=_('количество домов в комплексе'), help_text=_('оставьте пустым для автоматического подсчета'), default=None, null=True, blank=True, ) neighbourhood = models.ForeignKey( NeighbourhoodModel, verbose_name=_('район'), on_delete=models.PROTECT, ) date_of_construction = models.DateField( editable=False, null=True, blank=True, ) lowest_price = models.DecimalField( editable=False, null=True, blank=True, decimal_places=0, max_digits=15, ) def set_unique_slug(self): self.slug = orig = slugify(self.name) for x in itertools.count(1): if not ResidentalComplex.objects.filter(slug=self.slug).exclude( id=self.id).exists(): break self.slug = '%s-%d' % (orig, x) def save(self, *args, **kwargs): self.set_unique_slug() return super().save(*args, **kwargs) def get_date_of_construction(self): return get_quarter_verbose(self.date_of_construction) def _set_date_of_construction(self): buildings = self.get_new_buildings() date = buildings.aggregate( Max('date_of_construction')).get('date_of_construction__max') date_original = self.date_of_construction self.date_of_construction = date return not date_original == date def get_features(self): return self.features.all() def get_characteristic(self): return self.characteristics.all() def get_new_apartments(self): return self.newapartment_set.filter( is_active=True, buildings__is_active=True, ) def get_new_apartments_json(self): return get_json_objects_with_props(self.get_new_apartments()) def get_new_buildings(self): return self.newbuilding_set.filter( is_active=True).prefetch_related('newapartment_set') def get_new_buildings_json(self): return get_json_objects_with_props( self.get_new_buildings(), props=['get_quarter_of_construction']) def count_flats(self): if self.number_of_flats: return self.number_of_flats count = self.get_new_apartments().count() if count: return count return "" def count_buildings(self): if self.number_of_buildings: return self.number_of_buildings return len(self.get_new_buildings()) @cached_property def min_and_max_dates(self): buildings = self.get_new_buildings() if buildings: return buildings.aggregate( min_date_of_construction=Min('date_of_construction'), max_date_of_construction=Max('date_of_construction'), ) return {} def get_nearest_date_of_building(self, use_quarter=True): date = self.min_and_max_dates.get('min_date_of_construction', '') if use_quarter: return get_quarter_verbose(date) return date def get_latest_date_of_building(self, use_quarter=True): date = self.min_and_max_dates.get('max_date_of_construction', '') if use_quarter: return get_quarter_verbose(date) return date def get_title_photo_url(self): if self.front_image_spec_heading: return self.front_image_spec_heading.url return static('img/main.jpg') @cached_property def youtube_frame_link(self): if not self.video_link: return None link = re.sub( r'(.*youtube.com/)(watch\?v=)(.*)', r'\1embed/\3', self.video_link, re.U | re.I, ) return link def min_and_max_prices(self): apartments = self.get_new_apartments() if apartments: return apartments.aggregate( min_price=Min('price'), max_price=Max('price'), ) return {} def get_lowest_price(self): if self.lowest_price: return self.lowest_price return '' def get_highest_price(self): return self.min_and_max_prices().get('max_price') def _set_lowest_price(self): lowest_price_origin = self.lowest_price self.lowest_price = self.min_and_max_prices().get('min_price') return not self.lowest_price == lowest_price_origin def __str__(self): return self.get_quoted_name() def get_quoted_name(self): return get_quoted(self.name) def get_absolute_url(self): return reverse('new_buildings:residental-complex-detail', args=[self.slug]) def get_all_photos_url(self): urls = [] if self.front_image: urls.append(self.front_image_spec_normal.url) for photo in self.photos.all(): urls.append(photo.image_spec.url) return urls def is_built(self): if self.date_of_construction: return self.date_of_construction <= datetime.date.today() class Meta: verbose_name = _('комплекс') verbose_name_plural = _('комплексы') ordering = ( '-id', '-is_popular', )
class RealEstateUser(AbstactRealEstateUser): patronymic = models.CharField(_('отчество'), max_length=30, blank=True) phone_number = PhoneNumberField( _('номер телефона'), blank=True, ) show_phone_number = models.BooleanField( _('Отображать номер телефона на сайте'), default=True, help_text=_('Показывать ли личный номер на сайте?\ В противном случае будет показан номер компании')) show_email = models.BooleanField( _('Отображать email на сайте'), default=True, help_text=_('Показывать ли личный email на сайте?\ В противном случае будет показан email компании')) photo = models.ImageField( verbose_name=_('фото'), upload_to=get_file_path, help_text=_('Будет отображаться на сайте при определенных настройках'), blank=True, ) photo_300x300 = spec_factory( 300, 300, source='photo', to_fit=False, options__quality=70, format='jpeg', ) photo_370x500 = spec_factory( 370, 500, source='photo', to_fit=False, options__quality=80, format='jpeg', ) bio = models.TextField(_('биография'), max_length=255, blank=True) show_at_company_page = models.BooleanField( _('Отображать профиль на сайте'), default=True, help_text=_('Показывать ли контакт на странице с контактами компании\ и на прочих страницах, где это уместно?')) def get_full_name(self): """ Returns the first_name plus the last_name plus patronymic, with a space in between. """ full_name = '%s %s' % (self.last_name, self.first_name) if self.patronymic: full_name += ' %s' % self.patronymic return full_name.strip() get_full_name.short_description = _("Полное имя") def get_short_name(self): "Returns the short name for the user." short_name = '%s %s.' % ( self.last_name, self.first_name[0] if self.first_name else '', ) if self.patronymic: short_name += ' %s.' % self.patronymic[0] return short_name.strip().title() get_short_name.short_description = _("Сокращенное имя") def get_phone_number(self): if self.phone_number and self.show_phone_number: return self.phone_number return '' def get_phone_number_str(self): return phone_stringify(self.get_phone_number()) def get_photo(self): if self.photo: return self.photo.url return static('img/team/placeholder.jpg') def get_agent_photo(self): if self.photo: return self.photo_300x300.url return static('img/team/placeholder_300x300.jpg') def get_contact_photo(self): if self.photo: return self.photo_370x500.url return static('img/team/placeholder_370x500.jpg') def get_email(self): if self.email and self.show_email: return self.email return DEFAULT_EMAIL def get_instance_or_default(self): if self.is_active \ and self.show_at_company_page and not self.is_superuser: return self default_user_id = getattr(settings, 'DEFAULT_USER_ID', None) if default_user_id: try: default_user = RealEstateUser.objects.get( id=default_user_id, is_active=True, show_at_company_page=True, is_superuser=False) except Exception: pass else: return default_user user_list = RealEstateUser.objects.filter(is_active=True, show_at_company_page=True, is_superuser=False) return user_list[0] def get_absolute_url(self): return reverse('contacts:index') def __str__(self): return self.get_short_name()