from django.db import models from django.utils.translation import gettext_lazy as _ from filer.fields.image import FilerImageField from utils import generate_slug_for_model from apps.account.models import User class BookCollection(models.Model): class DisplayPosition(models.TextChoices): PINNED = 'pinned', _('Pinned') MIDDLE = 'middle', _('Middle Section') # BOTTOM = 'bottom', _('Bottom Section') title = models.CharField(max_length=255) slug = models.SlugField(max_length=255, unique=True) summary = models.CharField(max_length=512, null=True, blank=True, help_text=_('could be null')) pin_top = models.BooleanField(_('pin top'), default=True) display_position = models.CharField( max_length=20, choices=DisplayPosition.choices, default=DisplayPosition.PINNED, verbose_name=_('Display Position') ) status = models.BooleanField(_('status'), default=True) order = models.IntegerField(default=0, verbose_name=_('order')) books = models.ManyToManyField('library.Book', related_name='related_collections_books',through="library.Book_collections" ,verbose_name=_('Books'), blank=True) def __str__(self): return f'Collection #{self.id}/{self.title}' class Meta: verbose_name = _('Book Collection') verbose_name_plural = _('Book Collections') def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug_for_model(BookCollection, self.title) super().save(*args, **kwargs) class PinnedBookCollection(BookCollection): """ Proxy model for pinned book collections """ class Meta: proxy = True verbose_name = _('Pinned Book Collection') verbose_name_plural = _('Pinned Book Collections') class MiddleBookCollection(BookCollection): """ Proxy model for middle section book collections """ class Meta: proxy = True verbose_name = _('Middle Section Book Collection') verbose_name_plural = _('Middle Section Book Collections') class Category(models.Model): title = models.CharField(max_length=255) slug = models.SlugField(max_length=255, unique=True) status = models.BooleanField(default=True, verbose_name=_('status')) # books = models.ManyToManyField('library.Book', related_name='related_categories_books',through="library.Book_categories" ,verbose_name=_('Books'), blank=True) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at')) updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at')) def __str__(self): return self.title def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug_for_model(Category, self.title) super().save(*args, **kwargs) @property def books_count(self): """Return the number of books in this category""" return self.related_categories.count() class Meta: verbose_name = _('Category') verbose_name_plural = _('Categories') class Book(models.Model): class FileType(models.TextChoices): pdf = 'pdf', 'Pdf' epub = 'epub', 'Epub' docx = 'docx', 'Docx' title = models.CharField(max_length=255) slug = models.SlugField(max_length=255, unique=True) summary = models.CharField(max_length=512, null=True, blank=True, help_text=_('could be null')) description = models.TextField(null=True, blank=True, help_text=_('could be null')) thumbnail = models.ImageField(upload_to='book_thumbnails/', null=True, blank=True, help_text=_('image allowed')) author = models.CharField(max_length=255, null=True, blank=True) pages_count = models.CharField(verbose_name=_('Number of Pages'), max_length=255, help_text=_('eg. 34'), null=True) status = models.BooleanField(default=True, verbose_name=_('status')) pin = models.BooleanField(default=True, verbose_name=_('Pin to top')) categories = models.ManyToManyField(Category, related_name='related_categories', verbose_name=_('categories'), blank=True) collections = models.ManyToManyField(BookCollection, related_name='related_collections', verbose_name=_('collections'), blank=True) view_count = models.PositiveBigIntegerField(default=0, verbose_name=_('view count')) download_count = models.PositiveBigIntegerField(default=0, verbose_name=_('view count')) # seo_fields = SeoGenericRelation(verbose_name=_('soe fields')) file_type = models.CharField(verbose_name=_('File Type'), choices=FileType.choices, default=FileType.pdf, max_length=16) book_file = models.FileField(null=True, blank=True, max_length=550, upload_to='books', verbose_name='Book File') created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at')) updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at')) def __str__(self): return f'<{self.id}>-{self.title}' def save(self, *args, **kwargs): if not self.slug: self.slug = generate_slug_for_model(Book, self.title) super().save(*args, **kwargs) def increment_view_count(self): """Increment the view count by 1 and save the model""" self.view_count += 1 self.save(update_fields=['view_count']) class Meta: verbose_name = _('Book') verbose_name_plural = _('Books') class BookDownload(models.Model): """ Model to track book downloads by users """ user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='book_downloads', verbose_name=_('user')) book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='downloads', verbose_name=_('book')) status = models.BooleanField(default=True, verbose_name=_('status')) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at')) updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at')) class Meta: verbose_name = _('Book Download') verbose_name_plural = _('Book Downloads') ordering = ('-created_at',) def __str__(self): return f"{self.user} - {self.book}"