diff --git a/apps/hadis/admin/transmitter.py b/apps/hadis/admin/transmitter.py index 9ae727f..fa9f751 100644 --- a/apps/hadis/admin/transmitter.py +++ b/apps/hadis/admin/transmitter.py @@ -134,7 +134,7 @@ class TransmittersAdmin(ModelAdmin): fieldsets = ( (None, { - 'fields': ('full_name', 'birth_year_hijri', 'death_year_hijri','known_as','nickname','thumbnail') + 'fields': ('full_name', 'birth_year_hijri', 'death_year_hijri','known_as','nickname') }), (_('Additional Information'), { 'fields': ('description','origin','lived_in','died_in','kunya'), @@ -159,23 +159,8 @@ class TransmittersAdmin(ModelAdmin): @display(description=_("Transmitter"), header=True) def display_header(self, obj): - from django.templatetags.static import static - # Get thumbnail image path - use article's thumbnail if available, otherwise use default - thumbnail_path = obj.thumbnail.url if obj.thumbnail else None - - return [ - self.get_full_name_display(obj), - None, - None, - { - "path": thumbnail_path, - "height": 30, - "width": 50, - "borderless": True, - # "squared": True, - }, - ] + return self.get_full_name_display(obj), class HadisTransmitterAdmin(ModelAdmin): diff --git a/apps/hadis/models/category.py b/apps/hadis/models/category.py index 3bbce65..c648f94 100644 --- a/apps/hadis/models/category.py +++ b/apps/hadis/models/category.py @@ -92,13 +92,61 @@ class HadisCategory(MPTTModel): def save(self, *args, **kwargs): self.full_clean() - if not self.slug: - title = self.title[0]['text'] - base_slug = slugify(title, allow_unicode=True) - slug = base_slug - while HadisCategory.objects.filter(slug=slug).exclude(pk=self.pk).exists(): - slug = f"{base_slug}" - self.slug = slug + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): + # Try to get text from title field with robust error handling + try: + if self.title and isinstance(self.title, list) and len(self.title) > 0: + first_item = self.title[0] + if isinstance(first_item, dict): + title_text = first_item.get('text', '').strip() + if title_text: + base_slug = slugify(title_text, allow_unicode=True) + slug = base_slug + counter = 1 + while HadisCategory.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug + else: + # Fallback if text is empty + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"category-{suffix}" + counter = 1 + while HadisCategory.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"category-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if structure is invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"category-{suffix}" + counter = 1 + while HadisCategory.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"category-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if title is empty or invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"category-{suffix}" + counter = 1 + while HadisCategory.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"category-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + except (IndexError, KeyError, AttributeError, TypeError): + # Fallback on any error + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"category-{suffix}" + counter = 1 + while HadisCategory.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"category-{suffix}-{counter}" + counter += 1 + self.slug = base_slug super().save(*args, **kwargs) diff --git a/apps/hadis/models/hadis.py b/apps/hadis/models/hadis.py index 3f7c98b..9f5548c 100644 --- a/apps/hadis/models/hadis.py +++ b/apps/hadis/models/hadis.py @@ -19,14 +19,61 @@ class HadisCollection(models.Model): updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at')) 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 HadisCollection.objects.filter(slug=slug).exclude(pk=self.pk).exists(): - slug = f"{base_slug}-{counter}" - counter += 1 - self.slug = slug + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): + # Try to get text from title field with robust error handling + try: + if self.title and isinstance(self.title, list) and len(self.title) > 0: + first_item = self.title[0] + if isinstance(first_item, dict): + title_text = first_item.get('text', '').strip() + if title_text: + base_slug = slugify(title_text, allow_unicode=True) + slug = base_slug + counter = 1 + while HadisCollection.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug + else: + # Fallback if text is empty + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"collection-{suffix}" + counter = 1 + while HadisCollection.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"collection-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if structure is invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"collection-{suffix}" + counter = 1 + while HadisCollection.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"collection-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if title is empty or invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"collection-{suffix}" + counter = 1 + while HadisCollection.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"collection-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + except (IndexError, KeyError, AttributeError, TypeError): + # Fallback on any error + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"collection-{suffix}" + counter = 1 + while HadisCollection.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"collection-{suffix}-{counter}" + counter += 1 + self.slug = base_slug super().save(*args, **kwargs) def __str__(self): @@ -132,9 +179,62 @@ class HadisStatus(models.Model): description = models.JSONField(default = list , verbose_name=_('Description')) def save(self, *args, **kwargs): - if not self.slug: - slug = slugify(self.title[0]['text']) - self.slug = slug + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): + # Try to get text from title field with robust error handling + try: + if self.title and isinstance(self.title, list) and len(self.title) > 0: + first_item = self.title[0] + if isinstance(first_item, dict): + title_text = first_item.get('text', '').strip() + if title_text: + slug = slugify(title_text) + # Ensure uniqueness + counter = 1 + base_slug = slug + while HadisStatus.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug + else: + # Fallback if text is empty + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"status-{suffix}" + counter = 1 + while HadisStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"status-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if structure is invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"status-{suffix}" + counter = 1 + while HadisStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"status-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if title is empty or invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"status-{suffix}" + counter = 1 + while HadisStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"status-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + except (IndexError, KeyError, AttributeError, TypeError): + # Fallback on any error + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"status-{suffix}" + counter = 1 + while HadisStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"status-{suffix}-{counter}" + counter += 1 + self.slug = base_slug super().save(*args, **kwargs) def __str__(self): @@ -195,51 +295,45 @@ class Hadis(models.Model): return f"{self.number} - {self.title[0]['text']}" if self.title else f"Hadis {self.number}" def save(self, *args, **kwargs): - """ - Override save to automatically generate smart slugs. - - - If slug is empty, generates a new one - - Uses the first 8 words from the title (configurable) - - Ensures uniqueness with counters (-1, -2, etc.) - - Max length: 100 characters (configurable) - - Examples: - >>> hadis = Hadis.objects.create( - ... number=1877, - ... title=[ - ... { - ... "text": "Fatwa on Combining Prayers While Traveling and Missing Prayer", - ... "language_code": "en" - ... } - ... ] - ... ) - >>> print(hadis.slug) - 'fatwa-on-combining-prayers-while' - """ - - # Generate slug if not already set - if not self.slug and self.title: - # Extract title text + # Generate slug if not already set or if slug is empty + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): title_text = None - if isinstance(self.title, list) and self.title: + + # 1. Try to extract text if title exists + if self.title and isinstance(self.title, list) and len(self.title) > 0: first_item = self.title[0] if isinstance(first_item, dict): title_text = first_item.get("text") - # Generate smart slug + # 2. If we found text, use smart slug if title_text: self.slug = generate_smart_slug( text=title_text, model_class=Hadis, - max_length=100, # ← Adjust max length here - keep_words=8, # ← Limit to 8 words (your requirement) + max_length=100, + keep_words=8, instance=self, ) + # 3. CRITICAL FALLBACK: If no title text, use the number with unique suffix else: - # Fallback if title is empty - self.slug = f"hadis-{self.number or 'unknown'}" + # We use a random suffix or timestamp to ensure uniqueness if multiple untitled hadiths exist + from datetime import datetime + import random + import time + # Use timestamp + random to ensure uniqueness + suffix = int(time.time() * 1000) % 1000000 # Use milliseconds for better uniqueness + base_slug = f"hadis-{self.number or 'unknown'}-{suffix}" + # Ensure uniqueness by checking database + counter = 1 + while Hadis.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"hadis-{self.number or 'unknown'}-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + + # Generate share_link before saving + if not self.share_link and self.slug: + self.share_link = f"{settings.SITE_DOMAIN}/hadis/{self.slug}" - # Call parent save super().save(*args, **kwargs) def _get_json_field(self, field_name: str, lang: Optional[str]=None , fallback: str = "en"): @@ -295,12 +389,6 @@ class Hadis(models.Model): """Get address details (returns full list, not localized)""" return self.address_details if self.address_details else [] - def save(self, *args, **kwargs): - # ساخت share_link قبل از ذخیره - if not self.share_link: - self.share_link = f"{settings.SITE_DOMAIN}/hadis/{self.slug}" - super().save(*args, **kwargs) - class Meta: indexes = [ # Optimizes: Hadis.objects.filter(status=True).order_by('id') @@ -432,12 +520,21 @@ class HadisCorrection(models.Model): instance=self, ) else: - # Fallback if title is empty - self.slug = f"correction-{self.hadis.slug}-{self.id}" + # Fallback if title is empty - use timestamp for uniqueness + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"correction-{self.hadis.slug if self.hadis and self.hadis.slug else 'unknown'}-{suffix}" + # Ensure uniqueness + counter = 1 + while HadisCorrection.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"correction-{self.hadis.slug if self.hadis and self.hadis.slug else 'unknown'}-{suffix}-{counter}" + counter += 1 + self.slug = base_slug - # Call parent save - if not self.share_link: + # Generate share_link before saving + if not self.share_link and self.slug and self.hadis and self.hadis.slug: self.share_link = f"{settings.SITE_DOMAIN}/hadis/{self.hadis.slug}/corrections/{self.slug}" + super().save(*args, **kwargs) def get_title(self,lang): diff --git a/apps/hadis/models/reference.py b/apps/hadis/models/reference.py index 9e0cb09..5b74fa6 100644 --- a/apps/hadis/models/reference.py +++ b/apps/hadis/models/reference.py @@ -136,14 +136,61 @@ class BookReference(models.Model): 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 + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): + # Try to get text from title field with robust error handling + try: + if self.title and isinstance(self.title, list) and len(self.title) > 0: + first_item = self.title[0] + if isinstance(first_item, dict): + title_text = first_item.get('text', '').strip() + if title_text: + base_slug = slugify(title_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 + else: + # Fallback if text is empty + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"book-{suffix}" + counter = 1 + while BookReference.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"book-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if structure is invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"book-{suffix}" + counter = 1 + while BookReference.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"book-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if title is empty or invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"book-{suffix}" + counter = 1 + while BookReference.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"book-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + except (IndexError, KeyError, AttributeError, TypeError): + # Fallback on any error + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"book-{suffix}" + counter = 1 + while BookReference.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"book-{suffix}-{counter}" + counter += 1 + self.slug = base_slug super().save(*args, **kwargs) class BookReferenceImage(models.Model): diff --git a/apps/hadis/models/transmitter.py b/apps/hadis/models/transmitter.py index fd7b78c..ea8e8f8 100644 --- a/apps/hadis/models/transmitter.py +++ b/apps/hadis/models/transmitter.py @@ -66,24 +66,58 @@ class NarratorLayer(models.Model): return None def save(self, *args, **kwargs): - if not self.slug: + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): # Try to get text from name field with robust error handling try: if self.name and isinstance(self.name, list) and len(self.name) > 0: - text = self.name[0].get('text', '').strip() - if text: - slug = slugify(text) + first_item = self.name[0] + if isinstance(first_item, dict): + text = first_item.get('text', '').strip() + if text: + slug = slugify(text) + # Ensure uniqueness + counter = 1 + base_slug = slug + while NarratorLayer.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug + else: + # Fallback to layer number if text is empty + base_slug = f"layer-{self.number}" + slug = base_slug + counter = 1 + while NarratorLayer.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug else: - # Fallback to layer number if text is empty - slug = f"layer-{self.number}" + # Fallback to layer number if name structure is invalid + base_slug = f"layer-{self.number}" + slug = base_slug + counter = 1 + while NarratorLayer.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug else: # Fallback to layer number if name structure is invalid - slug = f"layer-{self.number}" + base_slug = f"layer-{self.number}" + slug = base_slug + counter = 1 + while NarratorLayer.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug except (IndexError, KeyError, AttributeError, TypeError): # Fallback to layer number on any error - slug = f"layer-{self.number}" - - self.slug = slug + base_slug = f"layer-{self.number}" + slug = base_slug + counter = 1 + while NarratorLayer.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug super().save(*args, **kwargs) class TransmitterReliability(models.Model): @@ -102,25 +136,59 @@ class TransmitterReliability(models.Model): color = models.CharField(max_length=20, choices=ColorChoices.choices, verbose_name=_('color')) def save(self, *args, **kwargs): - if not self.slug: + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): # Try to get text from title field with robust error handling try: if self.title and isinstance(self.title, list) and len(self.title) > 0: - text = self.title[0].get('text', '').strip() - if text: - slug = slugify(text) + first_item = self.title[0] + if isinstance(first_item, dict): + text = first_item.get('text', '').strip() + if text: + slug = slugify(text) + # Ensure uniqueness + counter = 1 + base_slug = slug + while TransmitterReliability.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug + else: + # Fallback to a timestamp-based slug + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"reliability-{suffix}" + counter = 1 + while TransmitterReliability.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"reliability-{suffix}-{counter}" + counter += 1 + self.slug = base_slug else: - # Fallback to a timestamp-based slug - from datetime import datetime - slug = f"reliability-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"reliability-{suffix}" + counter = 1 + while TransmitterReliability.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"reliability-{suffix}-{counter}" + counter += 1 + self.slug = base_slug else: - from datetime import datetime - slug = f"reliability-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"reliability-{suffix}" + counter = 1 + while TransmitterReliability.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"reliability-{suffix}-{counter}" + counter += 1 + self.slug = base_slug except (IndexError, KeyError, AttributeError, TypeError): - from datetime import datetime - slug = f"reliability-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" - - self.slug = slug + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"reliability-{suffix}" + counter = 1 + while TransmitterReliability.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"reliability-{suffix}-{counter}" + counter += 1 + self.slug = base_slug super().save(*args, **kwargs) def __str__(self): @@ -229,15 +297,61 @@ class Transmitters(models.Model): ordering = ('full_name',) def save(self, *args, **kwargs): - if not self.slug: - name = self.full_name[0] - base_slug = slugify(name.get('text'), allow_unicode=True) - slug = base_slug - counter = 1 - while Transmitters.objects.filter(slug=slug).exclude(pk=self.pk).exists(): - slug = f"{base_slug}-{counter}" - counter += 1 - self.slug = slug + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): + # Try to get text from full_name field with robust error handling + try: + if self.full_name and isinstance(self.full_name, list) and len(self.full_name) > 0: + first_item = self.full_name[0] + if isinstance(first_item, dict): + name_text = first_item.get('text', '').strip() + if name_text: + base_slug = slugify(name_text, allow_unicode=True) + slug = base_slug + counter = 1 + while Transmitters.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug + else: + # Fallback if text is empty + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"transmitter-{suffix}" + counter = 1 + while Transmitters.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"transmitter-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if structure is invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"transmitter-{suffix}" + counter = 1 + while Transmitters.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"transmitter-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + else: + # Fallback if full_name is empty or invalid + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"transmitter-{suffix}" + counter = 1 + while Transmitters.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"transmitter-{suffix}-{counter}" + counter += 1 + self.slug = base_slug + except (IndexError, KeyError, AttributeError, TypeError): + # Fallback on any error + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"transmitter-{suffix}" + counter = 1 + while Transmitters.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"transmitter-{suffix}-{counter}" + counter += 1 + self.slug = base_slug super().save(*args, **kwargs) def _get_json_field(self, field_name: str, lang: Optional[str]=None , fallback: str = "en"): @@ -367,25 +481,59 @@ class OpinionStatus(models.Model): color = models.CharField(max_length=20, choices=ColorChoices.choices, verbose_name=_('color')) def save(self, *args, **kwargs): - if not self.slug: + if not self.slug or (isinstance(self.slug, str) and self.slug.strip() == ''): # Try to get text from title field with robust error handling try: if self.title and isinstance(self.title, list) and len(self.title) > 0: - text = self.title[0].get('text', '').strip() - if text: - slug = slugify(text) + first_item = self.title[0] + if isinstance(first_item, dict): + text = first_item.get('text', '').strip() + if text: + slug = slugify(text) + # Ensure uniqueness + counter = 1 + base_slug = slug + while OpinionStatus.objects.filter(slug=slug).exclude(pk=self.pk).exists(): + slug = f"{base_slug}-{counter}" + counter += 1 + self.slug = slug + else: + # Fallback to a timestamp-based slug + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"opinion-{suffix}" + counter = 1 + while OpinionStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"opinion-{suffix}-{counter}" + counter += 1 + self.slug = base_slug else: - # Fallback to a timestamp-based slug - from datetime import datetime - slug = f"opinion-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"opinion-{suffix}" + counter = 1 + while OpinionStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"opinion-{suffix}-{counter}" + counter += 1 + self.slug = base_slug else: - from datetime import datetime - slug = f"opinion-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"opinion-{suffix}" + counter = 1 + while OpinionStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"opinion-{suffix}-{counter}" + counter += 1 + self.slug = base_slug except (IndexError, KeyError, AttributeError, TypeError): - from datetime import datetime - slug = f"opinion-{datetime.now().strftime('%Y%m%d%H%M%S%f')}" - - self.slug = slug + import time + suffix = int(time.time() * 1000) % 1000000 + base_slug = f"opinion-{suffix}" + counter = 1 + while OpinionStatus.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"opinion-{suffix}-{counter}" + counter += 1 + self.slug = base_slug super().save(*args, **kwargs) def __str__(self): @@ -536,12 +684,22 @@ class TransmitterOriginalText(models.Model): instance=self, ) else: - # Fallback if title is empty - self.slug = f"original-text-{self.transmitter.slug}-{self.id or 'unknown'}" + # Fallback if title is empty - use timestamp for uniqueness + import time + suffix = int(time.time() * 1000) % 1000000 + transmitter_slug = self.transmitter.slug if self.transmitter and self.transmitter.slug else 'unknown' + base_slug = f"original-text-{transmitter_slug}-{suffix}" + # Ensure uniqueness + counter = 1 + while TransmitterOriginalText.objects.filter(slug=base_slug).exclude(pk=self.pk).exists(): + base_slug = f"original-text-{transmitter_slug}-{suffix}-{counter}" + counter += 1 + self.slug = base_slug - # Call parent save - if not self.share_link: + # Generate share_link before saving + if not self.share_link and self.slug and self.transmitter and self.transmitter.slug: self.share_link = f"{settings.SITE_DOMAIN}/hadis/narrators/{self.transmitter.slug}/original-texts/{self.slug}" + super().save(*args, **kwargs)