from django.db import models from django.urls import reverse from django.utils import timezone from django.contrib.auth import get_user_model from taggit.managers import TaggableManager from django.utils.html import strip_tags import re User = get_user_model() class Category(models.Model): """Категория статей""" name = models.CharField(max_length=100, unique=True, verbose_name="Название") slug = models.SlugField(max_length=120, unique=True, verbose_name="URL") description = models.TextField(blank=True, verbose_name="Описание") class Meta: verbose_name = "Категория" verbose_name_plural = "Категории" def __str__(self): return self.name class Article(models.Model): """Статья блога""" tags = TaggableManager(blank=True, verbose_name="Теги") title = models.CharField(max_length=200, verbose_name="Заголовок") slug = models.SlugField(max_length=220, unique=True, verbose_name="URL") category = models.ForeignKey( Category, on_delete=models.PROTECT, related_name="articles", verbose_name="Категория" ) author = models.ForeignKey( User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Автор" ) content = models.TextField(verbose_name="Содержание") image = models.ImageField( upload_to="blog/%Y/%m/%d/", blank=True, verbose_name="Изображение" ) views_count = models.PositiveIntegerField(default=0, verbose_name="Просмотры") is_published = models.BooleanField(default=True, verbose_name="Опубликовано") time_create = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") time_update = models.DateTimeField(auto_now=True, verbose_name="Дата изменения") meta_description = models.CharField( max_length=160, blank=True, verbose_name="Meta-описание", help_text="Краткое описание для поисковых систем (до 160 символов)" ) class Meta: verbose_name = "Статья" verbose_name_plural = "Статьи" ordering = ["-time_create"] indexes = [ models.Index(fields=["-time_create", "is_published"]), ] def __str__(self): return self.title def get_absolute_url(self): return reverse("blog:article_detail", kwargs={"slug": self.slug}) def get_seo_title(self): return f"{self.title} | Блог программиста 1С" def get_seo_description(self): if self.meta_description: return self.meta_description clean = re.sub(r'\s+', ' ', strip_tags(self.content)).strip() return clean[:157] + '…' if len(clean) > 160 else clean class Comment(models.Model): """Комментарий к статье""" article = models.ForeignKey( Article, on_delete=models.CASCADE, related_name="comments", verbose_name="Статья" ) author_name = models.CharField(max_length=100, verbose_name="Имя") author_email = models.EmailField(verbose_name="Email") content = models.TextField(verbose_name="Комментарий") is_moderated = models.BooleanField(default=False, verbose_name="Промодерировано") time_create = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") class Meta: verbose_name = "Комментарий" verbose_name_plural = "Комментарии" ordering = ["time_create"] def __str__(self): return f"{self.author_name} - {self.article.title}"