Poprzedni wpis (Prawie, prawie) | Następny wpis (Mac i Python, Python i Mac)
NFA jest wielkie!
Dziś w pracy miałem robotę głównie poszukiwawczą — było kilka rzeczy, których nie wiadomo było jak zrobić, choć wiadomo było, że się da. Na przykład na początek: jak w adminie Django wyświetlić obrazek na formularzu edycji obiektu, zamiast zwykłego linku do niego, jak to jest domyślnie? Na szczęście wiedziałem jak się to robi, więc nie miałem zbyt trudnego zadania na początek.
W nowym Django (czyli beta-1 lub nowszym) w adminie jest to o tyle proste, że dla każdego indywidualnego pola formularza można przypisać odpowiedni widget, czyli reprezentację w HTML. Wystarczyło utworzyć sobie odpowiednią klasę dla takiego widgetu:
class AdminImageWidget(forms.FileInput):
"""
Widget do wyświetlania obrazka w adminie (change form)
"""
def render(self, name, value, attrs=None):
output = []
file_name = str(value)
if value and hasattr(value, 'url'):
output.append('<img src="%(url)s" alt="image" /><br />' % {'url': value.url})
output.append('%s ' % _('Change:'))
output.append(super(AdminImageWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
i następnie użyć jej w klasie administracyjnej dla modelu:
class MovieImageAdmin(admin.ModelAdmin):
list_display = ('movie', 'width', 'height', 'shot_at')
search_fields = ['movie__title']
save_on_top = True
list_filter = ('movie', 'width')
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'image':
kwargs['widget'] = AdminImageWidget
return db_field.formfield(**kwargs)
Metoda formfield_for_dbfield jest wywoływana dla każdego pola formularza i w tym przypadku sprawdzeniu podlega nazwa pola, ale można równie dobrze sprawdzić jego typ lub inny atrybut, aby dopasować właściwy widget. W ten sposób można także dostosować wyświetlanie plików video czy reprezentację dla plików dźwiękowych.
No dobrze, to było proste i nie zajęło mi całego dnia. Ale następna robota nie była już taka oczywista. Kolega chciał, żeby główne okno aplikacji administracyjnej (to, co jest pod / w adminie) dostało kilka dodatkowych zmiennych w kontekście. W starszym Django (sprzed newforms-admin) nie byłoby to możliwe bez patchowania samego Django (co nie jest kłopotliwe, jeżeli używa się Virtualenv, ale zawsze jest uciążliwe), ale teraz dostaliśmy wszystkie potrzebne narzędzia.
Jak wiadomo, za sterowanie aplikacją administracyjną odpowiada obiekt klasy AdminSite, który jest o tyle fajny, że jest najzwyklejszym obiektem najzwyklejszej klasy. Klasy, którą oczywiście można nadpisać. Jak to może wyglądać? Na przykład tak:
class AdminSite(admin.AdminSite):
def index(self, request, extra_context=None):
if extra_context is None:
extra_context = {}
ctx = {
'my_item': u'my_value',
}
extra_context.update(ctx)
return super(AdminSite, self).index(request, extra_context)
Nieprzyjemy aspekt używania obiektu site własnej klasy AdminSite jest taki, że nie działa funkcja autodiscover() i wszystkie klasy administracyjne trzeba rejestrować własnoręcznie w tym samym miejscu, gdzie znajduje się obiekt klasy AdminSite. Ale to chyba stosunkowo mała niedogodność w porównaniu z dostarczoną mocą.
Etykiety: django praca programowanie python


