1441 lines
56 KiB
Python
1441 lines
56 KiB
Python
import re
|
||
import requests
|
||
|
||
from django.conf import settings
|
||
from django.db import models
|
||
from django.urls import reverse
|
||
from django.template.defaultfilters import slugify
|
||
from django.utils.html import format_html
|
||
from django_ckeditor_5.fields import CKEditor5Field
|
||
from django.utils import timezone
|
||
from django.utils.dateformat import DateFormat
|
||
from filer.fields.folder import FilerFolderField
|
||
from filer.fields.image import FilerImageField, FilerFileField
|
||
from easy_thumbnails.files import get_thumbnailer
|
||
from unidecode import unidecode
|
||
from googletrans import Translator
|
||
|
||
ReviewSource = (
|
||
('1', 'Яндекс'),
|
||
('2', '2ГИС'),
|
||
('3', 'VL.ru'),
|
||
)
|
||
|
||
TransportCategory = (
|
||
('1', 'Япония'),
|
||
('2', 'Корея'),
|
||
)
|
||
|
||
Currency = (
|
||
('¥', 'Йены'),
|
||
('₩', 'Воны'),
|
||
)
|
||
|
||
Import_type = (
|
||
('ЭПТС', 'ЭПТС'),
|
||
('ГТД', 'ГТД'),
|
||
)
|
||
|
||
|
||
class StaticPage(models.Model):
|
||
title = models.CharField(verbose_name='Заголовок', max_length=255)
|
||
content = CKEditor5Field(verbose_name='Контент', blank=True, null=True)
|
||
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=512, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
|
||
class Meta:
|
||
verbose_name = 'текстовый раздел'
|
||
verbose_name_plural = 'текстовые разделы'
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def get_absolute_url(self):
|
||
return reverse('core:static_page', kwargs={'slug': self.slug})
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if StaticPage.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class StaticBlock(models.Model):
|
||
title = models.CharField(verbose_name='Заголовок', max_length=255)
|
||
content = models.TextField(verbose_name='Контент', null=True, blank=True)
|
||
|
||
class Meta:
|
||
verbose_name = 'статический блок'
|
||
verbose_name_plural = 'статические блоки'
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
|
||
class Category(models.Model):
|
||
title = models.CharField(verbose_name='Заголовок', max_length=255)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=512, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'категория новости'
|
||
verbose_name_plural = 'категории новостей'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if Category.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class Article(models.Model):
|
||
category = models.ForeignKey(Category, verbose_name='Категория', related_name='articles', blank=True, null=True,
|
||
on_delete=models.SET_NULL)
|
||
cover = FilerImageField(verbose_name='Обложка', null=True, on_delete=models.SET_NULL)
|
||
title = models.CharField(verbose_name='Заголовок', max_length=255)
|
||
content = CKEditor5Field(verbose_name='Контент')
|
||
date = models.DateTimeField(verbose_name='Дата')
|
||
is_active = models.BooleanField(verbose_name='Отображать на сайте?', default=True)
|
||
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=512, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
|
||
class Meta:
|
||
verbose_name = 'статья/новость'
|
||
verbose_name_plural = 'Статьи/новости'
|
||
ordering = ['-date']
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def get_thumbnail(self):
|
||
image = '-'
|
||
if self.cover:
|
||
image = format_html('<img src="{0}"/>', get_thumbnailer(self.cover)['article_thumbnail'].url)
|
||
return image
|
||
|
||
get_thumbnail.allow_tags = True
|
||
get_thumbnail.short_description = 'Обложка'
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if Article.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
@property
|
||
def get_date(self):
|
||
return DateFormat(timezone.make_naive(self.date)).format('j E Y')
|
||
|
||
def get_absolute_url(self):
|
||
return reverse('core:article_details', kwargs={'slug': self.slug})
|
||
|
||
|
||
class Question(models.Model):
|
||
title = models.CharField(verbose_name='Вопрос', max_length=255)
|
||
content = CKEditor5Field(verbose_name='Ответ')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
is_active = models.BooleanField(verbose_name='Отображать на сайте?', default=True)
|
||
|
||
class Meta:
|
||
verbose_name = 'FAQ'
|
||
verbose_name_plural = 'FAQ'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
|
||
class Video(models.Model):
|
||
title = models.CharField(verbose_name='Название', max_length=255)
|
||
link = models.CharField(verbose_name='Ссылка', max_length=512)
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
is_active = models.BooleanField(verbose_name='Отображать на сайте?', default=True)
|
||
on_main = models.BooleanField(verbose_name='На главной странице?', default=True)
|
||
cover = models.CharField(verbose_name='Обложка', max_length=512, blank=True, null=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
player_link = models.CharField(verbose_name='Ссылка плеера', max_length=512, blank=True, null=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
|
||
class Meta:
|
||
verbose_name = 'видео'
|
||
verbose_name_plural = 'видео'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def _extract_video_params(self):
|
||
pattern = r"video(-?\d+)_(\d+)"
|
||
match = re.search(pattern, self.link)
|
||
|
||
if match:
|
||
owner_id = match.group(1)
|
||
video_id = match.group(2)
|
||
return owner_id, video_id
|
||
else:
|
||
return None, None
|
||
|
||
def _get_cover(self):
|
||
owner_id, video_id = self._extract_video_params()
|
||
cover = None
|
||
player_link = None
|
||
if owner_id and video_id:
|
||
url = settings.VK_VIDEO_ENDPOINT
|
||
data = {
|
||
'videos': f'{owner_id}_{video_id}',
|
||
'v': '5.199',
|
||
'access_token': settings.VK_TOKEN,
|
||
}
|
||
|
||
response = requests.get(url, params=data)
|
||
|
||
try:
|
||
cover = response.json().get('response').get('items')[0].get('image')[-1].get('url')
|
||
player_link = response.json().get('response').get('items')[0].get('player')
|
||
except:
|
||
pass
|
||
|
||
return cover, player_link
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.cover is None:
|
||
cover, player = self._get_cover()
|
||
if cover:
|
||
self.cover = cover
|
||
if player:
|
||
self.player_link = player
|
||
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class Review(models.Model):
|
||
name = models.CharField(verbose_name='Фамилия Имя', max_length=255)
|
||
date = models.DateField(verbose_name='Дата')
|
||
text = models.TextField(verbose_name='Отзыв')
|
||
screen = FilerImageField(verbose_name='Скрин', null=True, blank=True, on_delete=models.SET_NULL)
|
||
is_active = models.BooleanField(verbose_name='Активный', default=True)
|
||
on_main = models.BooleanField(verbose_name='На главной странице?', default=True)
|
||
source = models.CharField(verbose_name='Источник', blank=True, null=True, choices=ReviewSource, max_length=50)
|
||
|
||
class Meta:
|
||
verbose_name = 'отзыв'
|
||
verbose_name_plural = 'отзывы'
|
||
ordering = ('-date',)
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
def get_thumbnail(self):
|
||
image = '-'
|
||
if self.screen:
|
||
image = format_html('<img src="{0}"/>', get_thumbnailer(self.screen)['review_thumbnail'].url)
|
||
return image
|
||
|
||
get_thumbnail.allow_tags = True
|
||
get_thumbnail.short_description = 'Скрин'
|
||
|
||
@property
|
||
def get_date(self):
|
||
return DateFormat(self.date).format('j E Y')
|
||
|
||
|
||
class TransportBrand(models.Model):
|
||
title = models.CharField(verbose_name='Название', max_length=255)
|
||
db_id = models.CharField(max_length=255)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=512, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'марка'
|
||
verbose_name_plural = 'марки'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if Category.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class TransportModel(models.Model):
|
||
brand = models.ForeignKey(TransportBrand, verbose_name='Марка', related_name='transport_models',
|
||
on_delete=models.CASCADE)
|
||
title = models.CharField(verbose_name='Название', max_length=255)
|
||
db_id = models.CharField(max_length=255)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=512, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
category = models.CharField(verbose_name='Категория', choices=TransportCategory, max_length=50, null=True)
|
||
|
||
class Meta:
|
||
verbose_name = 'модель'
|
||
verbose_name_plural = 'модели'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
country = 'не определено'
|
||
if self.category == '1':
|
||
country = 'Япония'
|
||
elif self.category == '2':
|
||
country = 'Корея'
|
||
|
||
return f'{self.title} ({country})'
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if Category.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class MachineryBrand(models.Model):
|
||
title = models.CharField(verbose_name='Название', max_length=255)
|
||
db_id = models.CharField(max_length=255)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=512, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'марка (спец техника)'
|
||
verbose_name_plural = 'марки (спец техника)'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if Category.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class MachineryModel(models.Model):
|
||
brand = models.ForeignKey(MachineryBrand, verbose_name='Марка', related_name='machinery_models',
|
||
on_delete=models.CASCADE)
|
||
title = models.CharField(verbose_name='Название', max_length=255)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=512, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'модель (спец техника)'
|
||
verbose_name_plural = 'модели (спец техника)'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if Category.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class TransportExperience(models.Model):
|
||
category = models.CharField(verbose_name='Категория', choices=TransportCategory, max_length=50)
|
||
cover = FilerImageField(verbose_name='Обложка', null=True, blank=True, on_delete=models.SET_NULL)
|
||
slider = FilerFolderField(on_delete=models.CASCADE, verbose_name='Галерея', null=True, blank=True)
|
||
currency = models.CharField(verbose_name='Валюта', choices=Currency, max_length=50)
|
||
import_type = models.CharField(verbose_name='Ввоз', choices=Import_type, max_length=50, default='ЭПТС')
|
||
|
||
title = models.CharField(verbose_name='Заголовок', max_length=255, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
brand = models.ForeignKey(TransportBrand, verbose_name='Марка', related_name='transport_experience',
|
||
on_delete=models.CASCADE)
|
||
transport_model = models.ForeignKey(TransportModel, verbose_name='Модель', related_name='transport_experience',
|
||
on_delete=models.SET_NULL, null=True)
|
||
lot = models.CharField(verbose_name="Лот", max_length=100, null=True, blank=True)
|
||
auction = models.CharField(verbose_name="Аукцион", max_length=100, null=True, blank=True)
|
||
year = models.PositiveIntegerField(verbose_name='Год', null=True)
|
||
mileage = models.PositiveBigIntegerField(verbose_name='Пробег (км)', null=True, blank=True)
|
||
car_body = models.CharField(verbose_name='Кузов', max_length=255, null=True, blank=True)
|
||
rate = models.FloatField(verbose_name='Оценка', null=True, blank=True)
|
||
volume = models.PositiveIntegerField(verbose_name='Объем двигателя (см3)', null=True, blank=True)
|
||
power = models.PositiveIntegerField(verbose_name='Мощность (л.с.)', null=True, blank=True)
|
||
drive = models.CharField(verbose_name='Привод', max_length=255, null=True, blank=True)
|
||
transmission = models.CharField(verbose_name='Трансмиссия', max_length=255, null=True, blank=True)
|
||
equipment = models.CharField(verbose_name='Комплектация', max_length=255, null=True, blank=True)
|
||
comment = models.TextField(verbose_name='Комментарий', null=True, blank=True)
|
||
|
||
auction_price = models.PositiveBigIntegerField(verbose_name='Цена на аукционе (валюта)')
|
||
auction_price_rub = models.PositiveBigIntegerField(verbose_name='Цена на аукционе (руб.)')
|
||
delivery_price_rub = models.PositiveBigIntegerField(verbose_name='Доставка (руб.)')
|
||
tax_price_rub = models.PositiveBigIntegerField(verbose_name='Пошлина (руб.)')
|
||
|
||
is_active = models.BooleanField(verbose_name='Активный', default=True)
|
||
on_main = models.BooleanField(verbose_name='На главной странице?', default=True)
|
||
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'привезенное авто'
|
||
verbose_name_plural = 'привезенные авто'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
if self.title:
|
||
return self.title
|
||
else:
|
||
return self.brand.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.title is None:
|
||
title = f'{self.brand.title} {self.transport_model.title}'
|
||
if self.volume:
|
||
eng_v = round(self.volume / 1000, 1)
|
||
title += f', {eng_v} л.'
|
||
|
||
if self.year:
|
||
title += f', {self.year}'
|
||
|
||
self.title = title
|
||
return super().save(*args, **kwargs)
|
||
|
||
def get_thumbnail(self):
|
||
image = '-'
|
||
if self.cover:
|
||
image = format_html('<img src="{0}"/>', get_thumbnailer(self.cover)['experience_thumbnail'].url)
|
||
return image
|
||
|
||
get_thumbnail.allow_tags = True
|
||
get_thumbnail.short_description = 'Обложка'
|
||
|
||
@property
|
||
def full_title(self):
|
||
model_name = self.transport_model.title
|
||
brand_name = self.brand.title
|
||
|
||
full_title = ''
|
||
if brand_name:
|
||
full_title += brand_name.capitalize()
|
||
|
||
if model_name:
|
||
full_title += f' {model_name.capitalize()}'
|
||
|
||
if self.volume:
|
||
eng_v = round(self.volume / 1000, 1)
|
||
full_title += f', {eng_v} л.'
|
||
|
||
if self.year:
|
||
full_title += f', {self.year}'
|
||
|
||
return full_title
|
||
|
||
@property
|
||
def short_description(self):
|
||
description = ''
|
||
if self.volume:
|
||
description += f'{self.volume} cc'
|
||
if self.power:
|
||
description += f' / {self.power} л.с.'
|
||
if self.transmission:
|
||
description += f' / {self.transmission}'
|
||
if self.mileage:
|
||
description += f' / Пробег {self.mileage} км.'
|
||
|
||
description = description.strip(' / ')
|
||
return description
|
||
|
||
@property
|
||
def total_cost_rub(self):
|
||
return self.auction_price_rub + self.tax_price_rub + self.delivery_price_rub
|
||
|
||
@property
|
||
def currency_price_readable(self):
|
||
if self.auction_price_rub:
|
||
formatted_price = f"{self.auction_price_rub:,}".replace(',', ' ')
|
||
return f'{formatted_price} {self.currency}'
|
||
return 'не указана'
|
||
|
||
@property
|
||
def rub_price_readable(self):
|
||
if self.auction_price_rub:
|
||
formatted_price = f"{self.auction_price_rub:,}".replace(',', ' ')
|
||
return f'{formatted_price} ₽'
|
||
return 'не указана'
|
||
|
||
@property
|
||
def get_absolute_url(self):
|
||
if self.category == '1':
|
||
return reverse('core:experience_japan_details', kwargs={'pk': self.id})
|
||
elif self.category == '2':
|
||
return reverse('core:experience_korea_details', kwargs={'pk': self.id})
|
||
|
||
|
||
class MachineryExperience(models.Model):
|
||
cover = FilerImageField(verbose_name='Обложка', null=True, blank=True, on_delete=models.SET_NULL)
|
||
slider = FilerFolderField(on_delete=models.CASCADE, verbose_name='Галерея', null=True, blank=True)
|
||
currency = models.CharField(verbose_name='Валюта', choices=Currency, max_length=50)
|
||
import_type = models.CharField(verbose_name='Ввоз', choices=Import_type, max_length=50, default='ЭПТС')
|
||
|
||
title = models.CharField(verbose_name='Заголовок', max_length=255, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
brand = models.ForeignKey(MachineryBrand, verbose_name='Марка', related_name='transport_experience',
|
||
on_delete=models.CASCADE)
|
||
transport_model = models.ForeignKey(MachineryModel, verbose_name='Модель', related_name='transport_experience',
|
||
on_delete=models.CASCADE)
|
||
lot = models.CharField(verbose_name="Лот", max_length=100, null=True, blank=True)
|
||
auction = models.CharField(verbose_name="Аукцион", max_length=100, null=True, blank=True)
|
||
year = models.PositiveIntegerField(verbose_name='Год', null=True)
|
||
mileage = models.PositiveBigIntegerField(verbose_name='Пробег (км)', null=True, blank=True)
|
||
car_body = models.CharField(verbose_name='Кузов', max_length=255, null=True, blank=True)
|
||
rate = models.FloatField(verbose_name='Оценка', null=True, blank=True)
|
||
volume = models.PositiveIntegerField(verbose_name='Объем двигателя (см3)', null=True, blank=True)
|
||
power = models.PositiveIntegerField(verbose_name='Мощность (л.с.)', null=True, blank=True)
|
||
drive = models.CharField(verbose_name='Привод', max_length=255, null=True, blank=True)
|
||
transmission = models.CharField(verbose_name='Трансмиссия', max_length=255, null=True, blank=True)
|
||
equipment = models.CharField(verbose_name='Комплектация', max_length=255, null=True, blank=True)
|
||
comment = models.TextField(verbose_name='Комментарий', null=True, blank=True)
|
||
|
||
auction_price = models.PositiveBigIntegerField(verbose_name='Цена на аукционе (валюта)')
|
||
auction_price_rub = models.PositiveBigIntegerField(verbose_name='Цена на аукционе (руб.)')
|
||
delivery_price_rub = models.PositiveBigIntegerField(verbose_name='Доставка (руб.)')
|
||
tax_price_rub = models.PositiveBigIntegerField(verbose_name='Пошлина (руб.)')
|
||
|
||
is_active = models.BooleanField(verbose_name='Активный', default=True)
|
||
on_main = models.BooleanField(verbose_name='На главной странице?', default=True)
|
||
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'привезенная (спец техника)'
|
||
verbose_name_plural = 'привезенные (спец техника)'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
if self.title:
|
||
return self.title
|
||
else:
|
||
return self.brand.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.title is None:
|
||
title = f'{self.brand.title} {self.transport_model.title}'
|
||
if self.volume:
|
||
title += f', {self.volume} cc'
|
||
|
||
if self.year:
|
||
title += f', {self.year}'
|
||
|
||
self.title = title
|
||
return super().save(*args, **kwargs)
|
||
|
||
def get_thumbnail(self):
|
||
image = '-'
|
||
if self.cover:
|
||
image = format_html('<img src="{0}"/>', get_thumbnailer(self.cover)['experience_thumbnail'].url)
|
||
return image
|
||
|
||
get_thumbnail.allow_tags = True
|
||
get_thumbnail.short_description = 'Обложка'
|
||
|
||
@property
|
||
def full_title(self):
|
||
model_name = self.transport_model.title
|
||
brand_name = self.brand.title
|
||
|
||
full_title = ''
|
||
if brand_name:
|
||
full_title += brand_name.capitalize()
|
||
|
||
if model_name:
|
||
full_title += f' {model_name.capitalize()}'
|
||
|
||
if self.volume:
|
||
full_title += f', {self.volume} cc'
|
||
|
||
if self.year:
|
||
full_title += f', {self.year}'
|
||
|
||
return full_title
|
||
|
||
@property
|
||
def short_description(self):
|
||
description = ''
|
||
if self.volume:
|
||
description += f'{self.volume} cc'
|
||
if self.power:
|
||
description += f' / {self.power} л.с.'
|
||
if self.transmission:
|
||
description += f' / {self.transmission}'
|
||
if self.mileage:
|
||
description += f' / Пробег {self.mileage} км.'
|
||
|
||
description = description.strip(' / ')
|
||
return description
|
||
|
||
@property
|
||
def total_cost_rub(self):
|
||
return self.auction_price_rub + self.tax_price_rub + self.delivery_price_rub
|
||
|
||
@property
|
||
def currency_price_readable(self):
|
||
if self.auction_price_rub:
|
||
formatted_price = f"{self.auction_price_rub:,}".replace(',', ' ')
|
||
return f'{formatted_price} {self.currency}'
|
||
return 'не указана'
|
||
|
||
@property
|
||
def rub_price_readable(self):
|
||
if self.auction_price_rub:
|
||
formatted_price = f"{self.auction_price_rub:,}".replace(',', ' ')
|
||
return f'{formatted_price} ₽'
|
||
return 'не указана'
|
||
|
||
@property
|
||
def get_absolute_url(self):
|
||
return reverse('core:experience_machinery_details', kwargs={'pk': self.id})
|
||
|
||
|
||
class Rate(models.Model):
|
||
slug = models.CharField(verbose_name='Валютная пара', max_length=15)
|
||
rate = models.DecimalField(max_digits=10, decimal_places=3, default=0)
|
||
|
||
class Meta:
|
||
verbose_name = 'курс валют'
|
||
verbose_name_plural = 'курсы валют'
|
||
|
||
def __str__(self):
|
||
return str(self.rate)
|
||
|
||
|
||
class ColorFilter(models.Model):
|
||
title = models.CharField(verbose_name='Цвет', max_length=100, unique=True)
|
||
contain = models.CharField(verbose_name='Название цвета включает', max_length=100, unique=True)
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'фильтр цветы'
|
||
verbose_name_plural = 'фильтры цветов'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
|
||
class MainLot(models.Model):
|
||
category = models.CharField(max_length=5, default='1')
|
||
db_id = models.CharField(max_length=100, unique=True)
|
||
lot = models.CharField(max_length=100, null=True, blank=True)
|
||
auction_type = models.CharField(max_length=100, null=True, blank=True)
|
||
auction_date = models.CharField(max_length=100, null=True, blank=True)
|
||
auction = models.CharField(max_length=100, null=True, blank=True)
|
||
car_model = models.ForeignKey(TransportModel, related_name='main_lots', null=True, blank=True,
|
||
on_delete=models.CASCADE)
|
||
year = models.PositiveIntegerField(null=True, blank=True)
|
||
town = models.CharField(max_length=100, null=True, blank=True)
|
||
eng_v = models.PositiveIntegerField(null=True, blank=True)
|
||
pw = models.PositiveIntegerField(null=True, blank=True)
|
||
kuzov = models.CharField(max_length=100, null=True, blank=True)
|
||
grade = models.CharField(max_length=2016, null=True, blank=True)
|
||
color = models.CharField(max_length=100, null=True, blank=True)
|
||
kpp = models.CharField(max_length=100, null=True, blank=True)
|
||
kpp_type = models.CharField(max_length=100, null=True, blank=True)
|
||
priv = models.CharField(max_length=100, null=True, blank=True)
|
||
mileage = models.PositiveIntegerField(null=True, blank=True)
|
||
equip = models.CharField(max_length=4096, null=True, blank=True)
|
||
rate = models.CharField(max_length=100, null=True, blank=True)
|
||
start = models.PositiveIntegerField(null=True, blank=True)
|
||
finish = models.PositiveIntegerField(null=True, blank=True)
|
||
status = models.CharField(max_length=100, null=True, blank=True)
|
||
time = models.CharField(max_length=100, null=True, blank=True)
|
||
avg_price = models.PositiveIntegerField(null=True, blank=True)
|
||
avg_string = models.CharField(max_length=1000, null=True, blank=True)
|
||
auction_list = models.CharField(max_length=200, null=True, blank=True)
|
||
cover = models.CharField(max_length=200, null=True, blank=True)
|
||
images = models.TextField(null=True, blank=True)
|
||
serial = models.CharField(max_length=4096, null=True, blank=True)
|
||
info = models.TextField(max_length=8192, null=True, blank=True)
|
||
full_info = models.BooleanField(default=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'лот (Япония)'
|
||
verbose_name_plural = 'лоты (Япония)'
|
||
|
||
@property
|
||
def currency_price(self):
|
||
if self.avg_price and self.avg_price > 0:
|
||
return self.avg_price
|
||
|
||
if self.start and self.start > 0:
|
||
return self.start
|
||
|
||
if self.finish and self.finish > 0:
|
||
return self.finish
|
||
|
||
return 'не указана'
|
||
|
||
@property
|
||
def currency_price_readable(self):
|
||
price = self.currency_price
|
||
if isinstance(price, int):
|
||
formatted_price = f"{price:,}".replace(',', ' ')
|
||
return f'{formatted_price} ¥'
|
||
|
||
return price
|
||
|
||
@property
|
||
def rub_price(self):
|
||
rate = Rate.objects.get(slug='rub-jpy')
|
||
if isinstance(self.currency_price, int):
|
||
price = int(self.currency_price / rate.rate)
|
||
formatted_price = f"{price:,}".replace(',', ' ')
|
||
else:
|
||
return 'не указана'
|
||
|
||
return f'{formatted_price} ₽'
|
||
|
||
@property
|
||
def rub_price_int(self):
|
||
rate = Rate.objects.get(slug='rub-jpy')
|
||
if isinstance(self.currency_price, int):
|
||
price = int(self.currency_price / rate.rate)
|
||
return price
|
||
else:
|
||
return False
|
||
|
||
@property
|
||
def full_title(self):
|
||
if self.car_model:
|
||
model_name = self.car_model.title
|
||
brand_name = self.car_model.brand.title
|
||
else:
|
||
model_name = None
|
||
brand_name = None
|
||
|
||
full_title = ''
|
||
if brand_name:
|
||
full_title += brand_name.capitalize()
|
||
|
||
if model_name:
|
||
full_title += f' {model_name.capitalize()}'
|
||
|
||
if self.eng_v:
|
||
eng_v = round(self.eng_v / 1000, 1)
|
||
full_title += f', {eng_v} л.'
|
||
|
||
if self.year:
|
||
full_title += f', {self.year}'
|
||
|
||
return full_title
|
||
|
||
@property
|
||
def xml_description(self):
|
||
eng_v = ''
|
||
pw = ''
|
||
transmission = ''
|
||
|
||
if self.eng_v:
|
||
eng_v = round(self.eng_v / 1000, 1)
|
||
if self.pw:
|
||
pw = f' ({self.pw} л.с.)'
|
||
if self.kpp:
|
||
transmission = f' {self.kpp}'
|
||
|
||
return f'{eng_v}{transmission}{pw}'
|
||
|
||
@property
|
||
def get_absolute_url(self):
|
||
brand = ''
|
||
model = ''
|
||
try:
|
||
brand = self.car_model.brand.title.lower().replace(' ', '-')
|
||
except:
|
||
pass
|
||
|
||
try:
|
||
model = self.car_model.title.lower().replace(' ', '-')
|
||
model = f'-{model}'
|
||
except:
|
||
pass
|
||
|
||
if self.year:
|
||
year = f'-{self.year}'
|
||
else:
|
||
year = ''
|
||
|
||
url = f'{brand}{model}{year}-{self.db_id}'
|
||
url = url.strip('-')
|
||
|
||
return reverse('core:lot_japan', kwargs={'lot_id': url})
|
||
|
||
@property
|
||
def get_absolute_truck_url(self):
|
||
brand = ''
|
||
model = ''
|
||
try:
|
||
brand = self.car_model.brand.title.lower().replace(' ', '-')
|
||
except:
|
||
pass
|
||
|
||
try:
|
||
model = self.car_model.title.lower().replace(' ', '-')
|
||
model = f'-{model}'
|
||
except:
|
||
pass
|
||
|
||
if self.year:
|
||
year = f'-{self.year}'
|
||
else:
|
||
year = ''
|
||
|
||
url = f'{brand}{model}{year}-{self.db_id}'
|
||
url = url.strip('-')
|
||
|
||
return reverse('core:lot_truck', kwargs={'lot_id': url})
|
||
|
||
|
||
class KoreaLot(models.Model):
|
||
category = models.CharField(max_length=5, default='2')
|
||
db_id = models.CharField(max_length=100, unique=True)
|
||
lot = models.CharField(max_length=100, null=True, blank=True)
|
||
auction_date = models.CharField(max_length=100, null=True, blank=True)
|
||
auction = models.CharField(max_length=100, null=True, blank=True)
|
||
car_model = models.ForeignKey(TransportModel, related_name='korea_lots', null=True, blank=True,
|
||
on_delete=models.CASCADE)
|
||
year = models.PositiveIntegerField(null=True, blank=True)
|
||
eng_v = models.PositiveIntegerField(null=True, blank=True)
|
||
pw = models.PositiveIntegerField(null=True, blank=True)
|
||
kuzov = models.CharField(max_length=100, null=True, blank=True)
|
||
grade = models.CharField(max_length=2016, null=True, blank=True)
|
||
color = models.CharField(max_length=100, null=True, blank=True)
|
||
kpp = models.CharField(max_length=100, null=True, blank=True)
|
||
kpp_type = models.CharField(max_length=100, null=True, blank=True)
|
||
priv = models.CharField(max_length=100, null=True, blank=True)
|
||
mileage = models.PositiveIntegerField(null=True, blank=True)
|
||
equip = models.CharField(max_length=4096, null=True, blank=True)
|
||
rate = models.CharField(max_length=100, null=True, blank=True)
|
||
start = models.PositiveIntegerField(null=True, blank=True)
|
||
finish = models.PositiveIntegerField(null=True, blank=True)
|
||
status = models.CharField(max_length=100, null=True, blank=True)
|
||
time = models.CharField(max_length=100, null=True, blank=True)
|
||
avg_price = models.PositiveIntegerField(null=True, blank=True)
|
||
avg_string = models.CharField(max_length=1000, null=True, blank=True)
|
||
cover = models.CharField(max_length=200, null=True, blank=True)
|
||
images = models.TextField(null=True, blank=True)
|
||
serial = models.CharField(max_length=4096, null=True, blank=True)
|
||
info = models.TextField(max_length=8192, null=True, blank=True)
|
||
info_rus = models.TextField(max_length=8192, null=True, blank=True)
|
||
full_info = models.BooleanField(default=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'лот (Корея)'
|
||
verbose_name_plural = 'лоты (Корея)'
|
||
|
||
@property
|
||
def currency_price(self):
|
||
if self.avg_price and self.avg_price > 0:
|
||
return self.avg_price
|
||
|
||
if self.start and self.start > 0:
|
||
return self.start
|
||
|
||
if self.finish and self.finish > 0:
|
||
return self.finish
|
||
|
||
return 'не указана'
|
||
|
||
@property
|
||
def rub_price_int(self):
|
||
rate = Rate.objects.get(slug='rub-krw')
|
||
if isinstance(self.currency_price, int):
|
||
price = int(self.currency_price / rate.rate)
|
||
return price
|
||
else:
|
||
return False
|
||
|
||
@property
|
||
def currency_price_readable(self):
|
||
price = self.currency_price
|
||
if isinstance(price, int):
|
||
formatted_price = f"{price:,}".replace(',', ' ')
|
||
return f'{formatted_price} ₩'
|
||
|
||
return price
|
||
|
||
@property
|
||
def rub_price(self):
|
||
rate = Rate.objects.get(slug='rub-krw')
|
||
if isinstance(self.currency_price, int):
|
||
price = int(self.currency_price / rate.rate)
|
||
formatted_price = f"{price:,}".replace(',', ' ')
|
||
else:
|
||
return 'не указана'
|
||
|
||
return f'{formatted_price} ₽'
|
||
|
||
@property
|
||
def full_title(self):
|
||
try:
|
||
model_name = self.car_model.title
|
||
brand_name = self.car_model.brand.title
|
||
except:
|
||
model_name = None
|
||
brand_name = None
|
||
|
||
full_title = ''
|
||
if brand_name:
|
||
full_title += brand_name.capitalize()
|
||
|
||
if model_name:
|
||
full_title += f' {model_name.capitalize()}'
|
||
|
||
if self.eng_v:
|
||
eng_v = round(self.eng_v / 1000, 1)
|
||
full_title += f', {eng_v} л.'
|
||
|
||
if self.year:
|
||
full_title += f', {self.year}'
|
||
|
||
return full_title
|
||
|
||
@property
|
||
def xml_description(self):
|
||
eng_v = ''
|
||
pw = ''
|
||
transmission = ''
|
||
|
||
if self.eng_v:
|
||
eng_v = round(self.eng_v / 1000, 1)
|
||
if self.pw:
|
||
pw = f' ({self.pw} л.с.)'
|
||
if self.kpp:
|
||
transmission = f' {self.kpp}'
|
||
|
||
return f'{eng_v}{transmission}{pw}'
|
||
|
||
@property
|
||
def get_absolute_url(self):
|
||
brand = ''
|
||
model = ''
|
||
try:
|
||
brand = self.car_model.brand.title.lower().replace(' ', '-')
|
||
except:
|
||
pass
|
||
|
||
try:
|
||
model = self.car_model.title.lower().replace(' ', '-')
|
||
model = f'-{model}'
|
||
except:
|
||
pass
|
||
|
||
if self.year:
|
||
year = f'-{self.year}'
|
||
else:
|
||
year = ''
|
||
|
||
url = f'{brand}{model}{year}-{self.db_id}'
|
||
url = url.strip('-')
|
||
|
||
return reverse('core:lot_korea', kwargs={'lot_id': url})
|
||
|
||
def translate_to_rus(self):
|
||
try:
|
||
translator = Translator()
|
||
text_rus = translator.translate(text=self.info, dest='ru', src='auto')
|
||
if text_rus.text:
|
||
return text_rus.text
|
||
return False
|
||
except:
|
||
return False
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.info and self.info_rus is None:
|
||
info_rus = self.translate_to_rus()
|
||
if info_rus:
|
||
self.info_rus = info_rus
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class MachineryLot(models.Model):
|
||
db_id = models.CharField(max_length=100, unique=True)
|
||
lot = models.CharField(max_length=100, null=True, blank=True)
|
||
auction_date = models.CharField(max_length=100, null=True, blank=True)
|
||
auction = models.CharField(max_length=100, null=True, blank=True)
|
||
group = models.CharField(max_length=100, null=True, blank=True)
|
||
category = models.CharField(max_length=100, null=True, blank=True)
|
||
gg = models.CharField(max_length=100, null=True, blank=True)
|
||
cc = models.CharField(max_length=100, null=True, blank=True)
|
||
machinery_model = models.ForeignKey(MachineryModel, related_name='machinery_lots', null=True, blank=True,
|
||
on_delete=models.CASCADE)
|
||
year = models.PositiveIntegerField(null=True, blank=True)
|
||
grade = models.CharField(max_length=2016, null=True, blank=True)
|
||
kpp = models.CharField(max_length=100, null=True, blank=True)
|
||
priv = models.CharField(max_length=100, null=True, blank=True)
|
||
mileage = models.PositiveIntegerField(null=True, blank=True)
|
||
rate = models.CharField(max_length=100, null=True, blank=True)
|
||
volume = models.CharField(max_length=100, null=True, blank=True)
|
||
price = models.PositiveIntegerField(null=True, blank=True)
|
||
finish = models.PositiveIntegerField(null=True, blank=True)
|
||
status = models.CharField(max_length=100, null=True, blank=True)
|
||
cover = models.CharField(max_length=200, null=True, blank=True)
|
||
auction_list = models.CharField(max_length=200, null=True, blank=True)
|
||
images = models.TextField(null=True, blank=True)
|
||
serial = models.CharField(max_length=4096, null=True, blank=True)
|
||
info = models.TextField(max_length=8192, null=True, blank=True)
|
||
info_rus = models.TextField(max_length=8192, null=True, blank=True)
|
||
machinery_filter = models.ForeignKey('MachineryFilter', related_name='machinery_lots', null=True, blank=True,
|
||
on_delete=models.CASCADE)
|
||
full_info = models.BooleanField(default=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'лот (спец техника)'
|
||
verbose_name_plural = 'лоты (спец техника)'
|
||
|
||
@property
|
||
def currency_price(self):
|
||
if self.finish and self.finish > 0:
|
||
return self.finish
|
||
|
||
if self.price and self.price > 0:
|
||
return self.price
|
||
|
||
return 'не указана'
|
||
|
||
@property
|
||
def rub_price_int(self):
|
||
rate = Rate.objects.get(slug='rub-jpy')
|
||
if isinstance(self.currency_price, int):
|
||
price = int(self.currency_price / rate.rate)
|
||
return price
|
||
else:
|
||
return False
|
||
|
||
@property
|
||
def currency_price_readable(self):
|
||
price = self.currency_price
|
||
if isinstance(price, int):
|
||
formatted_price = f"{price:,}".replace(',', ' ')
|
||
return f'{formatted_price} ¥'
|
||
|
||
return price
|
||
|
||
@property
|
||
def rub_price(self):
|
||
rate = Rate.objects.get(slug='rub-jpy')
|
||
if isinstance(self.currency_price, int):
|
||
price = int(self.currency_price / rate.rate)
|
||
formatted_price = f"{price:,}".replace(',', ' ')
|
||
else:
|
||
return 'не указана'
|
||
|
||
return f'{formatted_price} ₽'
|
||
|
||
@property
|
||
def full_title(self):
|
||
try:
|
||
model_name = self.machinery_model.title
|
||
brand_name = self.machinery_model.brand.title
|
||
except:
|
||
model_name = None
|
||
brand_name = None
|
||
|
||
full_title = ''
|
||
if brand_name:
|
||
full_title += brand_name.capitalize()
|
||
|
||
if model_name:
|
||
full_title += f' {model_name.capitalize()}'
|
||
|
||
if self.cc:
|
||
full_title += f', {self.cc} cc'
|
||
|
||
if self.year:
|
||
full_title += f', {self.year}'
|
||
|
||
return full_title
|
||
|
||
@property
|
||
def get_absolute_url(self):
|
||
brand = ''
|
||
model = ''
|
||
try:
|
||
brand = self.machinery_model.brand.title.lower().replace(' ', '-')
|
||
except:
|
||
pass
|
||
|
||
try:
|
||
model = self.machinery_model.title.lower().replace(' ', '-')
|
||
model = f'-{model}'
|
||
except:
|
||
pass
|
||
|
||
if self.year:
|
||
year = f'-{self.year}'
|
||
else:
|
||
year = ''
|
||
|
||
url = f'{brand}{model}{year}-{self.db_id}'
|
||
url = url.strip('-')
|
||
|
||
return reverse('core:lot_machinery', kwargs={'lot_id': url})
|
||
|
||
def translate_to_rus(self):
|
||
try:
|
||
translator = Translator()
|
||
text_rus = translator.translate(text=self.info, dest='ru', src='auto')
|
||
if text_rus.text:
|
||
return text_rus.text
|
||
return False
|
||
except:
|
||
return False
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.info and self.info_rus is None:
|
||
info_rus = self.translate_to_rus()
|
||
if info_rus:
|
||
self.info_rus = info_rus
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class MachineryGroup(models.Model):
|
||
title = models.CharField(verbose_name='Группа спец. техники', max_length=100, unique=True)
|
||
|
||
class Meta:
|
||
verbose_name = 'группа спец. техники'
|
||
verbose_name_plural = 'группы спец. техники'
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
|
||
class MachineryFilter(models.Model):
|
||
title = models.CharField(verbose_name='Название фильтра', max_length=100, unique=True)
|
||
groups = models.ManyToManyField(MachineryGroup, verbose_name='Группы спец. техники', related_name='filters')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
on_main = models.BooleanField(verbose_name='Отображать на главной?', default=True)
|
||
icon = FilerImageField(verbose_name='Иконка фильтра', null=True, on_delete=models.SET_NULL)
|
||
|
||
class Meta:
|
||
verbose_name = 'фильтр спец. техники'
|
||
verbose_name_plural = 'фильтры спец.техники'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
|
||
class Banner(models.Model):
|
||
title = models.CharField(verbose_name='Заголовок', max_length=100)
|
||
banner = FilerImageField(verbose_name='Баннер', null=True, on_delete=models.SET_NULL)
|
||
button_text = models.CharField(verbose_name='Текст кнопки', max_length=50)
|
||
is_active = models.BooleanField(verbose_name='Отображать на сайте?', default=True)
|
||
|
||
link = models.URLField()
|
||
|
||
class Meta:
|
||
verbose_name = 'баннер'
|
||
verbose_name_plural = 'баннеры'
|
||
|
||
def get_thumbnail(self):
|
||
image = '-'
|
||
if self.banner:
|
||
image = format_html('<img src="{0}"/>', get_thumbnailer(self.banner)['banner_thumbnail'].url)
|
||
return image
|
||
|
||
get_thumbnail.allow_tags = True
|
||
get_thumbnail.short_description = 'Баннер'
|
||
|
||
|
||
class Document(models.Model):
|
||
title = models.TextField(verbose_name='Заголовок', null=True, blank=True)
|
||
file = FilerFileField(verbose_name='Файл', related_name="document_files", on_delete=models.SET_NULL, null=True,
|
||
blank=True)
|
||
slug = models.SlugField(verbose_name='Уникальный URL', max_length=255, unique=True, null=True, blank=True)
|
||
|
||
class Meta:
|
||
verbose_name = 'документ'
|
||
verbose_name_plural = 'документы'
|
||
|
||
def __str__(self):
|
||
return f'{self.title}'
|
||
|
||
@property
|
||
def get_file_size(self):
|
||
if self.file:
|
||
size_in_bytes = self.file.size
|
||
size_in_kb = int(size_in_bytes / 1024)
|
||
size_in_mb = int(size_in_bytes / (1024 * 1024))
|
||
|
||
if size_in_mb >= 1:
|
||
return f'{size_in_mb}МБ'
|
||
|
||
return f'{size_in_kb}КБ'
|
||
|
||
return False
|
||
|
||
|
||
class SeoAbove(models.Model):
|
||
h1 = models.CharField(verbose_name='H1 заголовок', max_length=512, blank=True, null=True)
|
||
meta_title = models.CharField(verbose_name='meta Title', max_length=512, blank=True, null=True)
|
||
meta_description = models.CharField(verbose_name='meta Description', max_length=512, blank=True, null=True)
|
||
meta_keywords = models.CharField(verbose_name='meta Keywords', max_length=512, blank=True, null=True)
|
||
og_image = FilerImageField(verbose_name='meta og image', null=True, blank=True, on_delete=models.SET_NULL)
|
||
slug = models.CharField(verbose_name='Слаг необходимой страницы', max_length=255, null=True, blank=True,
|
||
unique=True, help_text='Без домена.')
|
||
|
||
class Meta:
|
||
verbose_name = 'принудительное SEO'
|
||
verbose_name_plural = 'Принудительное SEO'
|
||
|
||
def __str__(self):
|
||
return f'{self.id} - {self.h1}'
|
||
|
||
|
||
class FormRequest(models.Model):
|
||
name = models.CharField(max_length=256, verbose_name="Имя")
|
||
phone = models.CharField(max_length=256, verbose_name="Номер")
|
||
comment = models.TextField(verbose_name="Комментарий", null=True, blank=True)
|
||
file = models.FileField(verbose_name="Конкурентное предложение", null=True, blank=True, upload_to="uploads/")
|
||
created_at = models.DateTimeField(verbose_name="Дата", auto_now_add=True)
|
||
|
||
class Meta:
|
||
verbose_name = 'заявка'
|
||
verbose_name_plural = 'заявки'
|
||
ordering = ('-created_at',)
|
||
|
||
def __str__(self):
|
||
return f'{self.name} - {self.phone}'
|
||
|
||
|
||
class StockAuto(models.Model):
|
||
cover = FilerImageField(verbose_name='Обложка', null=True, blank=True, on_delete=models.SET_NULL)
|
||
slider = FilerFolderField(on_delete=models.CASCADE, verbose_name='Галерея', null=True, blank=True)
|
||
city = models.ForeignKey('City', null=True, verbose_name='Город', blank=True, on_delete=models.SET_NULL,
|
||
related_name='autos_in_stock')
|
||
|
||
title = models.CharField(verbose_name='Заголовок', max_length=255, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
brand = models.ForeignKey(TransportBrand, verbose_name='Марка', related_name='autos_in_stock',
|
||
on_delete=models.CASCADE)
|
||
transport_model = models.ForeignKey(TransportModel, verbose_name='Модель', related_name='autos_in_stock',
|
||
on_delete=models.SET_NULL, null=True)
|
||
engine = models.ForeignKey('EngineType', null=True, verbose_name='Тип двигателя', blank=True,
|
||
on_delete=models.SET_NULL, related_name='autos_in_stock')
|
||
import_type = models.ForeignKey('ImportType', null=True, verbose_name='Ввоз', blank=True, on_delete=models.SET_NULL,
|
||
related_name='autos_in_stock')
|
||
year = models.PositiveIntegerField(verbose_name='Год', null=True)
|
||
mileage = models.PositiveBigIntegerField(verbose_name='Пробег (км)', null=True, blank=True,
|
||
help_text='Заполняется или поле "пробег" или поле "моточасы", при заполнении обоих будет отображен только пробег')
|
||
moto_hours = models.PositiveBigIntegerField(verbose_name='Маточасы', null=True, blank=True,
|
||
help_text='Заполняется или поле "пробег" или поле "моточасы", при заполнении обоих будет отображен только пробег')
|
||
car_body = models.CharField(verbose_name='Кузов', max_length=255, null=True, blank=True)
|
||
volume = models.PositiveIntegerField(verbose_name='Объем двигателя (см3)', null=True, blank=True)
|
||
power = models.PositiveIntegerField(verbose_name='Мощность (л.с.)', null=True, blank=True)
|
||
drive = models.CharField(verbose_name='Привод', max_length=255, null=True, blank=True)
|
||
transmission = models.CharField(verbose_name='Трансмиссия', max_length=255, null=True, blank=True)
|
||
equipment = models.CharField(verbose_name='Комплектация', max_length=255, null=True, blank=True)
|
||
comment = models.TextField(verbose_name='Комментарий', null=True, blank=True)
|
||
|
||
price = models.PositiveBigIntegerField(verbose_name='Цена (руб.)')
|
||
auction_price = models.IntegerField(default=0)
|
||
|
||
is_active = models.BooleanField(verbose_name='Активный', default=True)
|
||
on_main = models.BooleanField(verbose_name='На главной странице?', default=True)
|
||
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'авто в наличии'
|
||
verbose_name_plural = 'авто в наличии'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
if self.title:
|
||
return self.title
|
||
else:
|
||
return self.brand.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.title is None:
|
||
title = f'{self.brand.title} {self.transport_model.title}'
|
||
if self.volume:
|
||
eng_v = round(self.volume / 1000, 1)
|
||
title += f', {eng_v} л.'
|
||
|
||
if self.year:
|
||
title += f', {self.year}'
|
||
|
||
self.title = title
|
||
return super().save(*args, **kwargs)
|
||
|
||
def get_thumbnail(self):
|
||
image = '-'
|
||
if self.cover:
|
||
image = format_html('<img src="{0}"/>', get_thumbnailer(self.cover)['experience_thumbnail'].url)
|
||
return image
|
||
|
||
get_thumbnail.allow_tags = True
|
||
get_thumbnail.short_description = 'Обложка'
|
||
|
||
@property
|
||
def short_description(self):
|
||
description = ''
|
||
if self.power:
|
||
description += f'{self.power} л.с.'
|
||
if self.transmission:
|
||
description += f' / {self.transmission}'
|
||
|
||
if self.mileage:
|
||
description += f' / Пробег {self.mileage} км.'
|
||
elif self.moto_hours:
|
||
description += f' / Моточасы: {self.mileage} мч.'
|
||
|
||
description = description.strip(' / ')
|
||
return description
|
||
|
||
@property
|
||
def readable_price(self):
|
||
return f"{self.price:,}".replace(',', ' ')
|
||
|
||
@property
|
||
def get_absolute_url(self):
|
||
brand = ''
|
||
model = ''
|
||
try:
|
||
brand = self.brand.title.lower().replace(' ', '-')
|
||
except:
|
||
pass
|
||
|
||
try:
|
||
model = self.transport_model.title.lower().replace(' ', '-')
|
||
model = f'-{model}'
|
||
except:
|
||
pass
|
||
|
||
if self.year:
|
||
year = f'-{self.year}'
|
||
else:
|
||
year = ''
|
||
|
||
url = f'{brand}{model}{year}-{self.id}'
|
||
url = url.strip('-')
|
||
|
||
return reverse('core:stock_auto_details', kwargs={'lot_id': url})
|
||
|
||
|
||
class City(models.Model):
|
||
title = models.CharField(verbose_name='Город/регион', max_length=128, unique=True)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=128, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'город/регион'
|
||
verbose_name_plural = 'города/регионы'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if StaticPage.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class Contact(models.Model):
|
||
phone = models.CharField(max_length=64)
|
||
bitrix_id = models.IntegerField()
|
||
|
||
def __str__(self):
|
||
return self.phone
|
||
|
||
|
||
class Lead(models.Model):
|
||
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
|
||
bitrix_id = models.IntegerField()
|
||
|
||
def __str__(self):
|
||
return str(self.bitrix_id)
|
||
|
||
|
||
class ImportType(models.Model):
|
||
title = models.CharField(verbose_name='Ввоз', max_length=128, unique=True)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=128, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'тип ввоза'
|
||
verbose_name_plural = 'типы ввоза'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if StaticPage.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class EngineType(models.Model):
|
||
title = models.CharField(verbose_name='Двигатель', max_length=128, unique=True)
|
||
slug = models.CharField(verbose_name='Уникальный URL', max_length=128, null=True, blank=True,
|
||
help_text='Оставить пустым для автоматической генерации')
|
||
order = models.PositiveIntegerField(verbose_name='Порядок', default=0, blank=False, null=False)
|
||
|
||
class Meta:
|
||
verbose_name = 'тип двигателя'
|
||
verbose_name_plural = 'типы двигателей'
|
||
ordering = ('order',)
|
||
|
||
def __str__(self):
|
||
return self.title
|
||
|
||
def save(self, *args, **kwargs) -> None:
|
||
if self.slug is None:
|
||
slug = f'{slugify(unidecode(self.title))}'
|
||
if StaticPage.objects.filter(slug=slug).exists():
|
||
slug = f'{slugify(unidecode(self.title))}-{self.id}'
|
||
self.slug = slug
|
||
return super().save(*args, **kwargs)
|
||
|
||
|
||
class BitrixEmployee(models.Model):
|
||
bitrix_id = models.IntegerField(verbose_name='ID пользователя в bitrix', unique=True)
|
||
active = models.BooleanField(verbose_name='Активен?', default=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
verbose_name = 'сотрудник Bitrix'
|
||
verbose_name_plural = 'сотрудники Bitrix'
|
||
ordering = ('updated_at',)
|
||
|
||
def __str__(self):
|
||
return str(self.bitrix_id)
|