from django.db import models from django.utils.translation import gettext_lazy as _ from filer.fields.image import FilerImageField class NarratorLayer(models.Model): """ Model for narrator layers/classes (Tabaqat) Represents the classification level of narrators in hadis chains """ name = models.CharField(max_length=255, verbose_name=_('name')) number = models.PositiveIntegerField(verbose_name=_('layer number'), unique=True) description = models.TextField(verbose_name=_('description'), blank=True, 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 = _('Narrator Layer') verbose_name_plural = _('Narrator Layers') ordering = ['number'] def __str__(self): return f"{_('Layer')} {self.number} - {self.name}" class Transmitters(models.Model): class ReliabilityLevel(models.TextChoices): VERY_RELIABLE = 'very_reliable', _('Very Reliable') RELIABLE = 'reliable', _('Reliable') ACCEPTABLE = 'acceptable', _('Acceptable') WEAK = 'weak', _('Weak') VERY_WEAK = 'very_weak', _('Very Weak') UNKNOWN = 'unknown', _('Unknown') class MadhhabChoices(models.TextChoices): SHIA = 'shia', _('Shia') SUNNI = 'sunni', _('Sunni') HANAFI = 'hanafi', _('Hanafi') MALIKI = 'maliki', _('Maliki') SHAFII = 'shafii', _('Shafi\'i') HANBALI = 'hanbali', _('Hanbali') OTHER = 'other', _('Other') UNKNOWN = 'unknown', _('Unknown') # Basic Information full_name = models.CharField(max_length=255, verbose_name=_('full name')) kunya = models.CharField(max_length=255, verbose_name=_('Kunya'), blank=True, null=True, help_text=_('e.g., Abu Abdullah')) known_as = models.CharField(max_length=255, verbose_name=_('Known As'), blank=True, null=True) nickname = models.CharField(max_length=255, verbose_name=_('Nickname/Laqab'), blank=True, null=True) # Geographic Information origin = models.CharField(max_length=255, verbose_name=_('Origin'), blank=True, null=True, help_text=_('Place of origin')) lived_in = models.CharField(max_length=255, verbose_name=_('Lived In'), blank=True, null=True, help_text=_('Places where they lived')) died_in = models.CharField(max_length=255, verbose_name=_('Died In'), blank=True, null=True, help_text=_('Place of death')) # Date Information birth_year_hijri = models.IntegerField(verbose_name=_("Birth Year (Hijri)"), null=True, blank=True) death_year_hijri = models.IntegerField(verbose_name=_("Death Year (Hijri)"), null=True, blank=True) age_at_death = models.PositiveIntegerField(verbose_name=_('Age at Death'), blank=True, null=True) # Religious & Academic Information reliability = models.CharField( max_length=20, choices=ReliabilityLevel.choices, default=ReliabilityLevel.UNKNOWN, verbose_name=_('Reliability Level') ) madhhab = models.CharField( max_length=20, choices=MadhhabChoices.choices, default=MadhhabChoices.UNKNOWN, verbose_name=_('Madhhab/School of Thought') ) # Presence in Famous Collections in_sahih_muslim = models.BooleanField( default=False, verbose_name=_('In Sahih Muslim'), help_text=_('Is this narrator present in Sahih Muslim?') ) in_sahih_bukhari = models.BooleanField( default=False, verbose_name=_('In Sahih Bukhari'), help_text=_('Is this narrator present in Sahih Bukhari?') ) # Additional Information description = models.TextField(blank=True, null=True, verbose_name=_("Description")) thumbnail = FilerImageField( related_name="+", on_delete=models.CASCADE, help_text=_('image allowed'), null=True, 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 = _('Transmitter') verbose_name_plural = _('Transmitters') ordering = ('full_name',) def __str__(self): return self.full_name class HadisTransmitter(models.Model): class ReliabilityStatus(models.TextChoices): RELIABLE = 'reliable', _('Reliable') WEAK = 'weak', _('Weak') UNKNOWN = 'unknown', _('Unknown') hadis = models.ForeignKey( "hadis.Hadis", on_delete=models.CASCADE, verbose_name=_('hadis'), related_name='transmitters' ) transmitter = models.ForeignKey( Transmitters, on_delete=models.CASCADE, verbose_name=_('transmitter'), related_name='hadises' ) narrator_layer = models.ForeignKey( NarratorLayer, on_delete=models.SET_NULL, verbose_name=_('narrator layer'), related_name='transmitters', null=True, blank=True, help_text=_('The layer/class (Tabaqah) this narrator belongs to') ) status = models.CharField( max_length=20, choices=ReliabilityStatus.choices, default=ReliabilityStatus.UNKNOWN, verbose_name=_('reliability status'), help_text=_('Reliability status of the narrator') ) order = models.PositiveIntegerField( default=0, verbose_name=_('Order'), help_text=_('Order in the chain of transmission') ) is_gap = models.BooleanField(default=False, verbose_name=_('is gap')) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at')) class Meta: verbose_name = _('Hadis Transmitter') verbose_name_plural = _('Hadis Transmitters') ordering = ('hadis', 'order') unique_together = ('hadis', 'transmitter', 'order') def __str__(self): layer_info = f" - {self.narrator_layer}" if self.narrator_layer else "" return f'{self.hadis.number} - {self.transmitter.full_name} ({self.order}){layer_info}' class TransmitterOpinion(models.Model): """ Model for scholarly opinions about transmitters """ class OpinionStatus(models.TextChoices): CONFIRMED = 'confirmed', _('Confirmed') MIXED = 'mixed', _('Mixed') REJECTED = 'rejected', _('Rejected') transmitter = models.ForeignKey( Transmitters, on_delete=models.CASCADE, verbose_name=_('transmitter'), related_name='opinions' ) scholar_name = models.CharField( max_length=255, verbose_name=_('Scholar Name'), help_text=_('Name of the scholar who gave this opinion') ) opinion_text = models.TextField( verbose_name=_('Opinion Text'), help_text=_('The scholar\'s opinion about this transmitter') ) status = models.CharField( max_length=20, choices=OpinionStatus.choices, default=OpinionStatus.CONFIRMED, verbose_name=_('Opinion Status'), help_text=_('Status of the opinion') ) 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 = _('Transmitter Opinion') verbose_name_plural = _('Transmitter Opinions') ordering = ('-created_at',) def __str__(self): return f"{self.scholar_name}'s opinion on {self.transmitter.full_name} ({self.status})"