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('
', 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('
', 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('
', 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('
', 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('
', 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('
', 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)