Browse Source

added Optional instead of pipe

master
Mohsen Taba 5 months ago
parent
commit
f82c5f0803
  1. 2
      apps/api/urls.py
  2. 156
      apps/hadis/admin/reference.py
  3. 15
      apps/hadis/admin/transmitter.py
  4. 5
      apps/hadis/models/hadis.py
  5. 13
      apps/hadis/models/reference.py
  6. 9
      apps/hadis/models/transmitter.py
  7. 2
      config/urls.py

2
apps/api/urls.py

@ -1,5 +1,5 @@
from django.urls import path
from django.urls import path,include
from .views import HomeView, CountryView, CommentListAPIView from .views import HomeView, CountryView, CommentListAPIView
from .views.api_views import AppVersionListAPIView from .views.api_views import AppVersionListAPIView

156
apps/hadis/admin/reference.py

@ -0,0 +1,156 @@
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from unfold.admin import ModelAdmin, TabularInline
from unfold.decorators import display
# Import your custom admin site
from utils.admin import project_admin_site
# Import your models
from ..models import (
BookReference,
BookReferenceImage,
BookAuthor,
BookAttribute
)
# -----------------------------------------------------------------------------
# 1. Inlines
# -----------------------------------------------------------------------------
class BookReferenceImageInline(TabularInline):
"""
Inline for managing Book Images directly inside the BookReference page.
"""
model = BookReferenceImage
extra = 0
fields = ('image', 'order', 'description')
readonly_fields = ('created_at',)
class BookAttributeInline(TabularInline):
"""
Inline for managing Book Attributes (Key-Value pairs) inside BookReference.
"""
model = BookAttribute
extra = 0
fields = ('title', 'value')
readonly_fields = ('created_at',)
# -----------------------------------------------------------------------------
# 2. Main Admins
# -----------------------------------------------------------------------------
class BookReferenceAdmin(ModelAdmin):
"""Admin for BookReference model"""
# Use custom methods for JSON fields to show readable text
list_display = (
'get_title_display',
'slug',
'get_publisher_display',
'year_of_publication',
'rate',
'created_at'
)
list_filter = ('year_of_publication', 'rate', 'created_at')
# Searching by JSON fields via string is limited in Django,
# so we focus on standard fields
search_fields = ('isbn', 'slug', 'volume')
readonly_fields = ('created_at', 'updated_at')
# Add the inlines to manage images and attributes on the same page
inlines = [BookReferenceImageInline, BookAttributeInline]
fieldsets = (
(_('Basic Info'), {
'fields': ('title', 'description', 'slug', 'language')
}),
(_('Publication Info'), {
'fields': ('publisher', 'isbn', 'year_of_publication', 'number_page', 'volume')
}),
(_('Rating & Stats'), {
'fields': ('rate', 'created_at', 'updated_at')
}),
)
# --- Custom Display Methods ---
@display(description=_('Title'), ordering='title')
def get_title_display(self, obj):
return self._extract_first_text(obj.title)
@display(description=_('Publisher'))
def get_publisher_display(self, obj):
return self._extract_first_text(obj.publisher)
def _extract_first_text(self, json_data):
"""Helper to safely extract the first 'text' from a JSON list"""
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first_item = json_data[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return '-'
class BookAuthorAdmin(ModelAdmin):
"""Admin for BookAuthor model"""
list_display = ('get_name_display', 'created_at', 'updated_at')
search_fields = ('name',) # Note: Search works best on exact text matches
readonly_fields = ('created_at', 'updated_at')
# Use filter_horizontal for ManyToMany fields to make selection easier
filter_horizontal = ('book_references',)
@display(description=_('Name'), ordering='name')
def get_name_display(self, obj):
if obj.name and isinstance(obj.name, list) and len(obj.name) > 0:
first = obj.name[0]
if isinstance(first, dict):
return first.get('text', '-')
return '-'
class BookAttributeAdmin(ModelAdmin):
"""
Admin for managing Attributes independently.
Useful if you want to see all attributes across all books.
"""
list_display = ('get_title_display', 'get_value_display', 'get_book_display', 'created_at')
list_filter = ('created_at',)
search_fields = ('book_reference__slug',)
@display(description=_('Title'), ordering='title')
def get_title_display(self, obj):
return self._extract_first_text(obj.title)
@display(description=_('Value'), ordering='value')
def get_value_display(self, obj):
return self._extract_first_text(obj.value)
@display(description=_('Book Reference'), ordering='book_reference')
def get_book_display(self, obj):
if obj.book_reference:
return self._extract_first_text(obj.book_reference.title)
return '-'
def _extract_first_text(self, json_data):
if json_data and isinstance(json_data, list) and len(json_data) > 0:
first = json_data[0]
if isinstance(first, dict):
return first.get('text', '-')
return '-'
# -----------------------------------------------------------------------------
# 3. Registration
# -----------------------------------------------------------------------------
project_admin_site.register(BookReference, BookReferenceAdmin)
project_admin_site.register(BookAuthor, BookAuthorAdmin)
project_admin_site.register(BookAttribute, BookAttributeAdmin)

15
apps/hadis/admin/transmitter.py

@ -17,7 +17,7 @@ class HadisTransmitterInline(TabularInline):
class TransmittersAdmin(ModelAdmin): class TransmittersAdmin(ModelAdmin):
"""Admin for Transmitters model""" """Admin for Transmitters model"""
list_display = ('full_name', 'birth_year_hijri', 'death_year_hijri')
list_display = ('get_full_name_display', 'birth_year_hijri', 'death_year_hijri')
list_filter = ('birth_year_hijri', 'death_year_hijri') list_filter = ('birth_year_hijri', 'death_year_hijri')
search_fields = ('full_name', 'description') search_fields = ('full_name', 'description')
readonly_fields = ('created_at', 'updated_at') readonly_fields = ('created_at', 'updated_at')
@ -28,7 +28,7 @@ class TransmittersAdmin(ModelAdmin):
'fields': ('full_name', 'birth_year_hijri', 'death_year_hijri') 'fields': ('full_name', 'birth_year_hijri', 'death_year_hijri')
}), }),
(_('Additional Information'), { (_('Additional Information'), {
'fields': ('description', 'thumbnail'),
'fields': ('description',),
'classes': ('collapse',) 'classes': ('collapse',)
}), }),
(_('Timestamps'), { (_('Timestamps'), {
@ -36,6 +36,17 @@ class TransmittersAdmin(ModelAdmin):
'classes': ('collapse',) 'classes': ('collapse',)
}), }),
) )
@display(description=_('Full Name'), ordering='full_name')
def get_full_name_display(self, obj):
"""
Parses the JSON full_name and returns the first item's text.
"""
if obj.full_name and isinstance(obj.full_name, list) and len(obj.full_name) > 0:
# Safely get the first item
first_item = obj.full_name[0]
if isinstance(first_item, dict):
return first_item.get('text', '-')
return '-'
class HadisTransmitterAdmin(ModelAdmin): class HadisTransmitterAdmin(ModelAdmin):

5
apps/hadis/models/hadis.py

@ -1,3 +1,4 @@
from typing import Optional
from django.db import models from django.db import models
from django.db.models import F, ForeignKey from django.db.models import F, ForeignKey
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -66,7 +67,7 @@ class HadisCollection(models.Model):
if isinstance(tr, dict) and tr.get('language_code') == lang: if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '') return tr.get('text', '')
for tr in self.translation:
for tr in self.summary:
if isinstance(tr, dict) and tr.get('language_code') == 'en': if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '') return tr.get('text', '')
return None return None
@ -189,7 +190,7 @@ class Hadis(models.Model):
def __str__(self): def __str__(self):
return f"{self.number} - {self.title}" if self.title else f"Hadis {self.number}" return f"{self.number} - {self.title}" if self.title else f"Hadis {self.number}"
def _get_json_field(self, field_name: str, lang: str | None = None, fallback: str = "en"):
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. Generic getter for JSONField in our [{text, language_code}] format.
Usage: self._get_json_field('title', 'fa') Usage: self._get_json_field('title', 'fa')

13
apps/hadis/models/reference.py

@ -1,6 +1,7 @@
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils.text import slugify from django.utils.text import slugify
from typing import Optional
class BookReference(models.Model): class BookReference(models.Model):
@ -35,9 +36,9 @@ class BookReference(models.Model):
ordering = ('-created_at',) ordering = ('-created_at',)
def __str__(self): def __str__(self):
return self.title
return self.title[0]['text']
def _get_json_field(self, field_name: str, lang: str | None = None, fallback: str = "en"):
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. Generic getter for JSONField in our [{text, language_code}] format.
Usage: self._get_json_field('title', 'fa') Usage: self._get_json_field('title', 'fa')
@ -81,7 +82,7 @@ class BookReference(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
base_slug = slugify(self.title, allow_unicode=True)
base_slug = slugify(self.title[0]['text'], allow_unicode=True)
slug = base_slug slug = base_slug
counter = 1 counter = 1
while BookReference.objects.filter(slug=slug).exclude(pk=self.pk).exists(): while BookReference.objects.filter(slug=slug).exclude(pk=self.pk).exists():
@ -129,7 +130,7 @@ class BookReferenceImage(models.Model):
return None return None
def __str__(self): def __str__(self):
return f"{self.book_reference.title} - Image {self.order}"
return f"{self.book_reference.title[0]['text']} - Image {self.order}"
class BookAuthor(models.Model): class BookAuthor(models.Model):
@ -153,7 +154,7 @@ class BookAuthor(models.Model):
ordering = ['name'] ordering = ['name']
def __str__(self): def __str__(self):
return self.name
return self.name[0]['text']
def get_name(self,lang): def get_name(self,lang):
""" """
@ -196,7 +197,7 @@ class BookAttribute(models.Model):
ordering = ['title'] ordering = ['title']
def __str__(self): def __str__(self):
return f"{self.title}: {self.value}"
return f"{self.title[0]['text']}: {self.value[0]['text']}"
def get_title(self,lang): def get_title(self,lang):
""" """

9
apps/hadis/models/transmitter.py

@ -4,6 +4,7 @@ from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from filer.fields.image import FilerImageField from filer.fields.image import FilerImageField
from django.utils.text import slugify from django.utils.text import slugify
from typing import Optional
@ -151,7 +152,8 @@ class Transmitters(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug: if not self.slug:
base_slug = slugify(self.full_name, allow_unicode=True)
name = self.full_name[0]
base_slug = slugify(name.get('text'), allow_unicode=True)
slug = base_slug slug = base_slug
counter = 1 counter = 1
while Transmitters.objects.filter(slug=slug).exclude(pk=self.pk).exists(): while Transmitters.objects.filter(slug=slug).exclude(pk=self.pk).exists():
@ -160,7 +162,7 @@ class Transmitters(models.Model):
self.slug = slug self.slug = slug
super().save(*args, **kwargs) super().save(*args, **kwargs)
def _get_json_field(self, field_name: str, lang: str | None = None, fallback: str = "en"):
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. Generic getter for JSONField in our [{text, language_code}] format.
Usage: self._get_json_field('title', 'fa') Usage: self._get_json_field('title', 'fa')
@ -211,7 +213,8 @@ class Transmitters(models.Model):
def __str__(self): def __str__(self):
return self.full_name
name = self.full_name[0]
return name.get('text')

2
config/urls.py

@ -102,6 +102,7 @@ urlpatterns = [
# path('test/', include('apps.api.urls')) # path('test/', include('apps.api.urls'))
path('oneapi-translation/', oneapi_translate), path('oneapi-translation/', oneapi_translate),
path('admin/filer/', include('filer.urls')), path('admin/filer/', include('filer.urls')),
path('filer/', include('filer.urls')),
] ]
# Protected swagger URL patterns # Protected swagger URL patterns
@ -122,6 +123,7 @@ urlpatterns+= i18n_patterns(
path('docs/', CustomAPIDocumentationView.as_view(), name='docs-index'), path('docs/', CustomAPIDocumentationView.as_view(), name='docs-index'),
*swagger_urlpatterns, *swagger_urlpatterns,
path('admin/filer/', include('filer.urls')), path('admin/filer/', include('filer.urls')),
path('filer/', include('filer.urls')),
) )
if settings.DEBUG: if settings.DEBUG:

Loading…
Cancel
Save