Files
2021-cadpoint-ru/cadpoint/web/admin.py

147 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
from django import forms
from django.contrib import admin
from django.db import models
from django.forms import TextInput, Textarea
from django.urls import reverse
from django_select2.forms import Select2TagWidget
from web.models import TbContent
from web.add_function import safe_html_special_symbols
from cadpoint import settings
class AjaxCommaSeparatedSelect2TagWidget(Select2TagWidget):
"""
Select2-виджет для `taggit`.
Select2 в браузере работает с массивом значений, а `taggit` ждёт строку
с тегами через запятую. Поэтому здесь есть конвертация туда и обратно.
"""
def value_from_datadict(self, data, files, name):
# Select2 присылает список значений, а `taggit` ожидает строку вида
# "tag-one,tag two,tag-three".
values = super().value_from_datadict(data, files, name)
if isinstance(values, (list, tuple)):
return ",".join(values)
return values
def optgroups(self, name, value, attrs=None):
# При редактировании объекта нужно показать уже выбранные теги.
# При этом не тащим ВСЕ теги из базы — только те, что уже сохранены.
if isinstance(value, (list, tuple)):
raw_values = []
for item in value:
if not item:
continue
raw_values.extend(str(item).split(","))
else:
raw_values = str(value or "").split(",")
values = [item for item in raw_values if item]
selected = set(values)
subgroup = [
self.create_option(name, v, v, v in selected, i)
for i, v in enumerate(values)
]
return [(None, subgroup, 0)]
class AdminContentForm(forms.ModelForm):
class Meta:
model = TbContent
fields = '__all__'
class Media:
css = {
'all': ('css/admin-select2-theme.css',),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# AJAX-виджет подгружает список тегов лениво, а здесь мы оставляем
# только уже выбранные значения, чтобы не тащить все теги из базы при
# открытии формы и не провоцировать лишние запросы к SQLite.
if self.is_bound:
if hasattr(self.data, 'getlist'):
tag_values = self.data.getlist('tags')
else:
raw_values = self.data.get('tags', [])
tag_values = raw_values if isinstance(raw_values, list) else [raw_values]
tag_choices = [(value, value) for value in tag_values if value]
elif self.instance.pk:
tag_choices = [
(name, name)
for name in self.instance.tags.order_by('name').values_list('name', flat=True)
]
else:
tag_choices = []
self.fields['tags'].widget = AjaxCommaSeparatedSelect2TagWidget(
attrs={
'data-ajax--url': reverse('web_tag_autocomplete'),
'data-ajax--cache': 'true',
'data-ajax--data-type': 'json',
'data-ajax--delay': settings.SELECT2_AJAX_DELAY_MS,
'data-token-separators': settings.SELECT2_TOKEN_SEPARATORS,
'data-minimum-input-length': settings.SELECT2_MINIMUM_INPUT_LENGTH,
},
choices=tag_choices,
)
# Register your models here.
class AdminContent(admin.ModelAdmin):
form = AdminContentForm
search_fields = ['szContentHead', 'szContentIntro', 'szContentBody',
'szContentKeywords', 'szContentDescription']
list_display = ('id', 'ContentHeadSafe', 'tag_list', 'bContentPublish', 'tdContentPublishUp')
list_display_links = ('id', 'ContentHeadSafe')
list_filter = ('bContentPublish', )
list_editable = ('bContentPublish', )
# настройка длины поля TextInput в админке
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size': '100%'})},
models.TextField: {'widget': Textarea(attrs={'rows': 14, 'cols': 120})},
}
# Настройка страницы редактирования
fieldsets = [
(None, {
'fields': ('bContentPublish', 'tdContentPublishUp')
}),
('Окончание публикации', {
'fields': ('tdContentPublishDown',),
'classes': ('collapse',),
}),
(None, {
'fields': ('tags', 'szContentHead', 'imgContentPreview', 'szContentIntro', 'szContentBody')
}),
('Типограф', {
'fields': ('bTypograf', ),
'classes': ('collapse',),
}),
('Поля для SEO', {
'fields': ('szContentSlug', 'szContentKeywords', 'szContentDescription', 'iContentHits'),
'classes': ('collapse', ),
}),
]
# exclude = ('', '', )
empty_value_display = u"<b style='color:red;'>—//—</b>"
actions_on_top = False
actions_on_bottom = False
def ContentHeadSafe(self, obj) -> str:
return safe_html_special_symbols(obj.szContentHead)
def get_queryset(self, request):
queryset = super().get_queryset(request)
if request.resolver_match and request.resolver_match.url_name == 'web_tbcontent_changelist':
return queryset.prefetch_related('tags')
return queryset
def tag_list(self, obj):
return u", ".join(o.name for o in obj.tags.all())
admin.site.register(TbContent, AdminContent)