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.
 
 

314 lines
10 KiB

from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.urls import reverse
from django.utils.html import format_html
from django.db import models
from ajaxdatatable.admin import AjaxDatatable
from unfold.admin import ModelAdmin, StackedInline, TabularInline
from django.contrib.admin import SimpleListFilter
from unfold.widgets import UnfoldAdminSelectWidget
from django.shortcuts import get_object_or_404, redirect, render
from unfold.decorators import display, action
from django import forms
from django.urls import path, reverse_lazy
from utils.admin import dovoodi_admin_site
from unfold.sections import TableSection
from apps.article.models import (
ArticleCategory,
ArticleCollection,
PinnedArticleCollection,
MiddleArticleCollection,
Article,
ArticleInCollection,
ArticleContent,
ContentPart,
TextSection
)
class ArticleInCollectionInline(TabularInline):
model = ArticleInCollection
extra = 1
autocomplete_fields = ('article',)
fields = ('article', 'order')
ordering = ('order',)
verbose_name = _('Article')
verbose_name_plural = _('Articles')
tab = True
class TextSectionInline(TabularInline):
model = TextSection
extra = 1
fields = ('arabic_text', 'translation', 'order')
ordering = ('order',)
verbose_name = _('Text Section')
verbose_name_plural = _('Text Sections')
class ContentPartInline(StackedInline):
model = ContentPart
extra = 1
fields = ('order',)
ordering = ('order',)
verbose_name = _('Content Part')
verbose_name_plural = _('Content Parts')
tab = True
class ArticleContentInline(StackedInline):
model = ArticleContent
extra = 1
fields = ('title', 'content', 'priority', 'status')
ordering = ('priority',)
verbose_name = _('Article Content')
verbose_name_plural = _('Article Contents')
tab = True
class ArticleCollectionAdminBase(ModelAdmin):
list_display = ('get_title', 'get_display_position', 'status', 'order', 'count_articles')
list_filter = ('status', 'order')
search_fields = ('title',)
ordering = ('order',)
list_filter_submit = True
warn_unsaved_form = True
change_form_show_cancel_button = True
inlines = [ArticleInCollectionInline]
fieldsets = (
(None, {
'fields': ('title', 'summary', 'thumbnail', 'status', 'pin_top', 'order')
}),
)
exclude = ('display_position',)
@display(description=_('Title'))
def get_title(self, obj):
return str(obj.title)
@display(description=_('Display Position'))
def get_display_position(self, obj):
if obj.display_position == ArticleCollection.DisplayPosition.PINNED:
return format_html('<span style="color: #0066cc; font-weight: bold;">📌 Pinned (Top)</span>')
else:
return format_html('<span style="color: #666;">📋 Regular (Middle)</span>')
@display(description=_('Number of Articles'))
def count_articles(self, obj):
count = obj.related_articles.count()
if count > 0:
url = reverse('admin:article_article_changelist') + f'?collections__id__exact={obj.id}'
return format_html('<a href="{}">{}</a>', url, count)
return count
class PinnedArticleCollectionForm(forms.ModelForm):
class Meta:
model = PinnedArticleCollection
exclude = ('slug',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['thumbnail'].required = True
class PinnedArticleCollectionAdmin(ArticleCollectionAdminBase):
form = PinnedArticleCollectionForm
def get_queryset(self, request):
return super().get_queryset(request).filter(display_position=ArticleCollection.DisplayPosition.PINNED)
def save_model(self, request, obj, form, change):
obj.display_position = ArticleCollection.DisplayPosition.PINNED
super().save_model(request, obj, form, change)
@display(description=_('Title'))
def get_title(self, obj):
from django.templatetags.static import static
thumbnail_path = obj.thumbnail.url if obj.thumbnail else None
return obj.title
# Uncomment below to show thumbnail in the title column
# return [
# obj.title,
# None,
# None,
# {
# "path": thumbnail_path,
# "height": 30,
# "width": 50,
# "borderless": True,
# # "squared": True,
# },
# ]
class MiddleArticleCollectionAdmin(ArticleCollectionAdminBase):
fieldsets = (
(None, {
'fields': ('title', 'status', 'pin_top', 'order')
}),
)
def get_queryset(self, request):
return super().get_queryset(request).filter(display_position=ArticleCollection.DisplayPosition.MIDDLE)
def save_model(self, request, obj, form, change):
obj.display_position = ArticleCollection.DisplayPosition.MIDDLE
super().save_model(request, obj, form, change)
class ArticleCategoryAdmin(ModelAdmin):
list_display = ('title', 'slug', 'status', 'order', 'count_articles', 'created_at')
list_filter = ('status', 'created_at', 'updated_at')
search_fields = ('title', 'slug')
@admin.display(description=_('Number of Articles'))
def count_articles(self, obj):
count = obj.articles.count()
if count > 0:
url = reverse('admin:article_article_changelist') + f'?categories__id__exact={obj.id}'
return format_html('<a href="{}">{}</a>', url, count)
return count
def get_form(self, request, obj=None, change=False, **kwargs):
form = super().get_form(request, obj, change, **kwargs)
if form.base_fields.get('slug'):
form.base_fields['slug'].required = False
return form
class ArticleAdmin(ModelAdmin):
# change_form_before_template = 'article/change_form_before_template.html'
list_display = ('display_header', 'slug', 'status', 'view_count', 'created_at')
list_filter = ('status', 'created_at', 'updated_at')
search_fields = ('title', 'slug', 'description', 'content')
autocomplete_fields = ('categories',)
save_as = True
search_help_text = _("Search by title, slug, description or content")
search_fields_placeholder = _("Search articles")
# inlines = [ArticleContentInline]
actions_row = [
"action_contents",
]
fieldsets = (
(None, {
'fields': ('title', 'slug', 'description', 'thumbnail', 'categories')
}),
(_('File'), {
'fields': ('article_file',)
}),
(_('Status'), {
'fields': ('status',)
}),
(_('Statistics'), {
'fields': ('view_count',)
}),
)
def get_form(self, request, obj=None, change=False, **kwargs):
form = super().get_form(request, obj, change, **kwargs)
if form.base_fields.get('slug'):
form.base_fields['slug'].required = False
if form.base_fields.get('thumbnail'):
form.base_fields['thumbnail'].required = True
return form
@action(
description=_("Contents"),
url_path="actions-row-custom-url",
)
def action_contents(self, request, object_id):
article = get_object_or_404(Article, pk=object_id)
url = reverse('admin:article_articlecontent_changelist') + f'?article__id__exact={article.id}'
return redirect(url)
@display(description=_("Article"), 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 [
obj.title,
None,
None,
{
"path": thumbnail_path,
"height": 30,
"width": 50,
"borderless": True,
# "squared": True,
},
]
class ArticleContentAdmin(ModelAdmin):
list_display = ('title', 'article', 'priority', 'status', 'created_at')
list_filter = ('status', 'priority', 'created_at')
search_fields = ('title', 'content')
autocomplete_fields = ('article',)
inlines = [ContentPartInline]
actions_row = [
"action_parts",
]
fieldsets = (
(None, {
'fields': ('article', 'title', 'content', 'priority', 'status')
}),
)
def get_changeform_initial_data(self, request):
initial = super().get_changeform_initial_data(request)
if 'article__id__exact' in request.GET:
initial['article'] = request.GET.get('article__id__exact')
return initial
@action(
description=_("Parts"),
url_path="actions-row-parts-url",
)
def action_parts(self, request, object_id):
content = get_object_or_404(ArticleContent, pk=object_id)
url = reverse('admin:article_contentpart_changelist') + f'?article_content__id__exact={content.id}'
return redirect(url)
class ContentPartAdmin(ModelAdmin):
list_display = ('article_content', 'order', 'created_at')
list_filter = ('created_at',)
autocomplete_fields = ('article_content',)
inlines = [TextSectionInline]
fieldsets = (
(None, {
'fields': ('article_content', 'order')
}),
)
def get_changeform_initial_data(self, request):
initial = super().get_changeform_initial_data(request)
if 'article_content__id__exact' in request.GET:
initial['article_content'] = request.GET.get('article_content__id__exact')
return initial
# Register models with admin site
dovoodi_admin_site.register(ArticleCategory, ArticleCategoryAdmin)
dovoodi_admin_site.register(PinnedArticleCollection, PinnedArticleCollectionAdmin)
dovoodi_admin_site.register(MiddleArticleCollection, MiddleArticleCollectionAdmin)
dovoodi_admin_site.register(Article, ArticleAdmin)
dovoodi_admin_site.register(ArticleContent, ArticleContentAdmin)
dovoodi_admin_site.register(ContentPart, ContentPartAdmin)