prod
This commit is contained in:
@@ -2,6 +2,8 @@ from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser, User
|
||||
import uuid
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
from django.conf import settings
|
||||
|
||||
class Category(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
@@ -57,18 +59,45 @@ class Client(models.Model):
|
||||
return f"{self.first_name} {self.last_name} {self.chat_id}"
|
||||
|
||||
class BlogPost(models.Model):
|
||||
DRAFT = 'draft'
|
||||
PUBLISHED = 'published'
|
||||
STATUS_CHOICES = [
|
||||
(DRAFT, 'Черновик'),
|
||||
(PUBLISHED, 'Опубликовано'),
|
||||
]
|
||||
|
||||
title = models.CharField(max_length=200)
|
||||
slug = models.SlugField(max_length=220, unique=True, blank=True)
|
||||
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='blog_posts')
|
||||
excerpt = models.CharField(max_length=400, blank=True)
|
||||
content = models.TextField()
|
||||
published_date = models.DateTimeField(auto_now_add=True)
|
||||
image = models.ImageField(upload_to='static/img/blog/', blank=True, null=True)
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=DRAFT)
|
||||
published_date = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
views = models.PositiveIntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Блог'
|
||||
verbose_name_plural = 'Блоги'
|
||||
verbose_name = 'Запись блога'
|
||||
verbose_name_plural = 'Записи блога'
|
||||
ordering = ['-published_date']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
base = slugify(self.title)[:200]
|
||||
slug = base
|
||||
i = 1
|
||||
while BlogPost.objects.filter(slug=slug).exists():
|
||||
slug = f"{base}-{i}"
|
||||
i += 1
|
||||
self.slug = slug
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('blog_detail', kwargs={'slug': self.slug})
|
||||
|
||||
class ServiceRequest(models.Model):
|
||||
service = models.ForeignKey(Service, on_delete=models.CASCADE)
|
||||
@@ -136,6 +165,37 @@ class Project(models.Model):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class PortfolioItem(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
slug = models.SlugField(max_length=220, unique=True, blank=True)
|
||||
description = models.TextField()
|
||||
client_name = models.CharField(max_length=200, blank=True)
|
||||
completion_date = models.DateField(blank=True, null=True)
|
||||
image = models.ImageField(upload_to='static/img/portfolio/', blank=True, null=True)
|
||||
featured = models.BooleanField(default=False)
|
||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True, related_name='portfolio_items')
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Портфолио'
|
||||
verbose_name_plural = 'Портфолио'
|
||||
ordering = ['-completion_date']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
base = slugify(self.title)[:200]
|
||||
slug = base
|
||||
i = 1
|
||||
while PortfolioItem.objects.filter(slug=slug).exists():
|
||||
slug = f"{base}-{i}"
|
||||
i += 1
|
||||
self.slug = slug
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Review(models.Model):
|
||||
client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name='reviews')
|
||||
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name='reviews')
|
||||
@@ -247,6 +307,119 @@ class AboutPage(models.Model):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class PrivacyPolicy(models.Model):
|
||||
version = models.CharField(max_length=50, default='1.0')
|
||||
content = models.TextField()
|
||||
effective_date = models.DateField(auto_now_add=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Политика конфиденциальности'
|
||||
verbose_name_plural = 'Политики конфиденциальности'
|
||||
|
||||
def __str__(self):
|
||||
return f"Privacy Policy v{self.version} ({self.effective_date})"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.is_active:
|
||||
PrivacyPolicy.objects.exclude(pk=self.pk).update(is_active=False)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class TermsOfUse(models.Model):
|
||||
version = models.CharField(max_length=50, default='1.0')
|
||||
content = models.TextField()
|
||||
effective_date = models.DateField(auto_now_add=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Условия использования'
|
||||
verbose_name_plural = 'Условия использования'
|
||||
|
||||
def __str__(self):
|
||||
return f"Terms v{self.version} ({self.effective_date})"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.is_active:
|
||||
TermsOfUse.objects.exclude(pk=self.pk).update(is_active=False)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class NewsArticle(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
slug = models.SlugField(max_length=220, unique=True, blank=True)
|
||||
excerpt = models.CharField(max_length=300, blank=True)
|
||||
content = models.TextField()
|
||||
image = models.ImageField(upload_to='static/img/news/', blank=True, null=True)
|
||||
is_published = models.BooleanField(default=False)
|
||||
published_date = models.DateTimeField(blank=True, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Новость'
|
||||
verbose_name_plural = 'Новости'
|
||||
ordering = ['-published_date', '-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
base = slugify(self.title)[:200]
|
||||
slug = base
|
||||
i = 1
|
||||
while NewsArticle.objects.filter(slug=slug).exists():
|
||||
slug = f"{base}-{i}"
|
||||
i += 1
|
||||
self.slug = slug
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class CareerVacancy(models.Model):
|
||||
FULL_TIME = 'FT'
|
||||
PART_TIME = 'PT'
|
||||
CONTRACT = 'CT'
|
||||
INTERN = 'IN'
|
||||
EMPLOYMENT_CHOICES = [
|
||||
(FULL_TIME, 'Полная занятость'),
|
||||
(PART_TIME, 'Частичная занятость'),
|
||||
(CONTRACT, 'Контракт'),
|
||||
(INTERN, 'Стажировка'),
|
||||
]
|
||||
|
||||
title = models.CharField(max_length=200)
|
||||
slug = models.SlugField(max_length=220, unique=True, blank=True)
|
||||
location = models.CharField(max_length=200, blank=True)
|
||||
employment_type = models.CharField(max_length=2, choices=EMPLOYMENT_CHOICES, default=FULL_TIME)
|
||||
responsibilities = models.TextField()
|
||||
requirements = models.TextField()
|
||||
desirable = models.TextField(blank=True)
|
||||
salary_min = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
|
||||
salary_max = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
posted_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Вакансия'
|
||||
verbose_name_plural = 'Вакансии'
|
||||
ordering = ['-posted_at']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
base = slugify(self.title)[:200]
|
||||
slug = base
|
||||
i = 1
|
||||
while CareerVacancy.objects.filter(slug=slug).exists():
|
||||
slug = f"{base}-{i}"
|
||||
i += 1
|
||||
self.slug = slug
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class FooterSettings(models.Model):
|
||||
"""Настройки футера - все данные управляются из админки"""
|
||||
|
||||
@@ -374,7 +547,12 @@ class TeamMember(models.Model):
|
||||
# Social Links
|
||||
email = models.EmailField(blank=True, verbose_name='Email')
|
||||
phone = models.CharField(max_length=50, blank=True, verbose_name='Телефон')
|
||||
telegram = models.CharField(max_length=100, blank=True, verbose_name='Telegram')
|
||||
telegram = models.CharField(
|
||||
max_length=100,
|
||||
blank=True,
|
||||
verbose_name='Telegram',
|
||||
help_text='Username без @ (например: trevor1985)'
|
||||
)
|
||||
linkedin = models.URLField(blank=True, verbose_name='LinkedIn')
|
||||
github = models.URLField(blank=True, verbose_name='GitHub')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user