You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

234 lines
7.9 KiB

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.utils.text import slugify
from typing import Optional
class BookReference(models.Model):
"""
Model for hadis book references with detailed information
This is different from library books - these are reference books for hadis
"""
title = models.JSONField(default = list , verbose_name=_('Title'))
description = models.JSONField(default = list , verbose_name=_('Description'))
language = models.JSONField(default = list , verbose_name=_('Language'))
isbn = models.CharField(max_length=100, verbose_name=_('ISBN'), blank=True, null=True)
volume = models.CharField(max_length=100, verbose_name=_('volume'), blank=True, null=True)
year_of_publication = models.CharField(max_length=50, verbose_name=_('year of publication'), blank=True, null=True)
number_page = models.PositiveIntegerField(verbose_name=_('number of pages'), blank=True, null=True)
slug = models.SlugField(max_length=255, verbose_name=_('slug'), blank=True,unique=True)
publisher = models.JSONField(default = list , verbose_name=_('Publisher'))
rate = models.DecimalField(
max_digits=3,
decimal_places=2,
verbose_name=_('rate'),
blank=True,
null=True,
help_text=_('Rating from 0 to 5')
)
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 Reference')
verbose_name_plural = _('Book References')
ordering = ('-created_at',)
def __str__(self):
return self.title[0]['text']
def _get_json_field(self, field_name: str, lang: Optional[str]=None , fallback: str = "en"):
"""
Generic getter for JSONField in our [{text, language_code}] format.
Usage: self._get_json_field('title', 'fa')
"""
if lang is None:
lang = fallback
value = getattr(self, field_name, None)
if not value or not isinstance(value, list):
return None
# 1) exact language
for item in value:
if isinstance(item, dict) and item.get("language_code") == lang:
return item.get("text", "")
# 2) fallback language
if fallback and fallback != lang:
for item in value:
if isinstance(item, dict) and item.get("language_code") == fallback:
return item.get("text", "")
# 3) first available
item = value[0]
print(item)
return item.get("text", "") if isinstance(item, dict) else None
def get_title(self,lang):
return self._get_json_field("title" , lang)
def get_description(self, lang):
return self._get_json_field("description" , lang)
def get_publisher(self, lang):
return self._get_json_field("publisher" , lang)
def get_language(self, lang):
return self._get_json_field("language" , lang)
def save(self, *args, **kwargs):
if not self.slug:
base_slug = slugify(self.title[0]['text'], allow_unicode=True)
slug = base_slug
counter = 1
while BookReference.objects.filter(slug=slug).exclude(pk=self.pk).exists():
slug = f"{base_slug}-{counter}"
counter += 1
self.slug = slug
super().save(*args, **kwargs)
class BookReferenceImage(models.Model):
"""
Model for book reference images - multiple images per book reference
"""
book_reference = models.ForeignKey(
BookReference,
on_delete=models.CASCADE,
related_name='images',
verbose_name=_('book reference')
)
image = models.ImageField(upload_to='hadis/book_reference_images/', verbose_name=_('image'))
order = models.PositiveIntegerField(default=0, verbose_name=_('order'))
description = models.JSONField(default = list , verbose_name=_('Description'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
class Meta:
verbose_name = _('Book Reference Image')
verbose_name_plural = _('Book Reference Images')
ordering = ['order', '-created_at']
def get_description(self,lang):
"""
Get title for a specific language
"""
if not self.description or not isinstance(self.description, list):
return None
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
for tr in self.description:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return None
def __str__(self):
return f"{self.book_reference.title[0]['text']} - Image {self.order}"
class BookAuthor(models.Model):
"""
Model for book reference authors
"""
name = models.JSONField(default = list , verbose_name=_('Name'))
book_references = models.ManyToManyField(
BookReference,
related_name='authors',
verbose_name=_('book references'),
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'))
class Meta:
verbose_name = _('Book Author')
verbose_name_plural = _('Book Authors')
ordering = ['name']
def __str__(self):
return self.name[0]['text']
def get_name(self,lang):
"""
Get title for a specific language
"""
if not self.name or not isinstance(self.name, list):
return None
for tr in self.name:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
for tr in self.name:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return None
class BookAttribute(models.Model):
"""
Model for book reference attributes - custom key-value pairs
"""
title = models.JSONField(default = list , verbose_name=_('Title'))
value = models.JSONField(default = list , verbose_name=_('Value'))
book_reference = models.ForeignKey(
BookReference,
on_delete=models.CASCADE,
related_name='attributes',
verbose_name=_('book attribute'),
default = None,
null = True
)
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 Attribute')
verbose_name_plural = _('Book Attributes')
ordering = ['title']
def __str__(self):
return f"{self.title[0]['text']}: {self.value[0]['text']}"
def get_title(self,lang):
"""
Get title for a specific language
"""
if not self.title or not isinstance(self.title, list):
return None
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
for tr in self.title:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return None
def get_value(self,lang):
"""
Get title for a specific language
"""
if not self.value or not isinstance(self.value, list):
return None
for tr in self.value:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
for tr in self.value:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return None