from django import forms from django.conf import settings from django.contrib import admin, messages from django.contrib.admin import helpers from django.contrib.sites.models import Site from django.http import HttpResponseRedirect from django.shortcuts import render from django.urls import path from django.utils.translation import gettext_lazy as _ from django.utils.translation import ngettext from .forms import UploadZipForm from .models import Gallery, Photo, PhotoEffect, PhotoSize, Watermark MULTISITE = getattr(settings, 'PHOTOLOGUE_MULTISITE', False) class GalleryAdminForm(forms.ModelForm): class Meta: model = Gallery if MULTISITE: exclude = [] else: exclude = ['sites'] class GalleryAdmin(admin.ModelAdmin): search_fields = ['title', 'slug', 'description'] list_display = ('title', 'date_added', 'photo_count', 'is_public') list_filter = ['date_added', 'is_public'] if MULTISITE: list_filter.append('sites') date_hierarchy = 'date_added' prepopulated_fields = {'slug': ('title',)} form = GalleryAdminForm if MULTISITE: filter_horizontal = ['sites'] if MULTISITE: actions = [ 'add_to_current_site', 'add_photos_to_current_site', 'remove_from_current_site', 'remove_photos_from_current_site' ] def formfield_for_manytomany(self, db_field, request, **kwargs): """ Set the current site as initial value. """ if db_field.name == "sites": kwargs["initial"] = [Site.objects.get_current()] return super().formfield_for_manytomany(db_field, request, **kwargs) def save_related(self, request, form, *args, **kwargs): """ If the user has saved a gallery with a photo that belongs only to different Sites - it might cause much confusion. So let them know. """ super().save_related(request, form, *args, **kwargs) orphaned_photos = form.instance.orphaned_photos() if orphaned_photos: msg = ngettext( 'The following photo does not belong to the same site(s)' ' as the gallery, so will never be displayed: %(photo_list)s.', 'The following photos do not belong to the same site(s)' ' as the gallery, so will never be displayed: %(photo_list)s.', len(orphaned_photos) ) % {'photo_list': ", ".join([photo.title for photo in orphaned_photos])} messages.warning(request, msg) def add_to_current_site(modeladmin, request, queryset): current_site = Site.objects.get_current() current_site.gallery_set.add(*queryset) msg = ngettext( "The gallery has been successfully added to %(site)s", "The galleries have been successfully added to %(site)s", len(queryset) ) % {'site': current_site.name} messages.success(request, msg) add_to_current_site.short_description = \ _("Add selected galleries to the current site") def remove_from_current_site(modeladmin, request, queryset): current_site = Site.objects.get_current() current_site.gallery_set.remove(*queryset) msg = ngettext( "The gallery has been successfully removed from %(site)s", "The selected galleries have been successfully removed from %(site)s", len(queryset) ) % {'site': current_site.name} messages.success(request, msg) remove_from_current_site.short_description = \ _("Remove selected galleries from the current site") def add_photos_to_current_site(modeladmin, request, queryset): photos = Photo.objects.filter(galleries__in=queryset) current_site = Site.objects.get_current() current_site.photo_set.add(*photos) msg = ngettext( 'All photos in gallery %(galleries)s have been successfully added to %(site)s', 'All photos in galleries %(galleries)s have been successfully added to %(site)s', len(queryset) ) % {'site': current_site.name, 'galleries': ", ".join([f"'{gallery.title}'" for gallery in queryset])} messages.success(request, msg) add_photos_to_current_site.short_description = \ _("Add all photos of selected galleries to the current site") def remove_photos_from_current_site(modeladmin, request, queryset): photos = Photo.objects.filter(galleries__in=queryset) current_site = Site.objects.get_current() current_site.photo_set.remove(*photos) msg = ngettext( 'All photos in gallery %(galleries)s have been successfully removed from %(site)s', 'All photos in galleries %(galleries)s have been successfully removed from %(site)s', len(queryset) ) % {'site': current_site.name, 'galleries': ", ".join([f"'{gallery.title}'" for gallery in queryset])} messages.success(request, msg) remove_photos_from_current_site.short_description = \ _("Remove all photos in selected galleries from the current site") admin.site.register(Gallery, GalleryAdmin) class PhotoAdminForm(forms.ModelForm): class Meta: model = Photo if MULTISITE: exclude = [] else: exclude = ['sites'] class PhotoAdmin(admin.ModelAdmin): list_display = ('title', 'date_taken', 'date_added', 'is_public', 'view_count', 'admin_thumbnail') list_filter = ['date_added', 'is_public'] if MULTISITE: list_filter.append('sites') search_fields = ['title', 'slug', 'caption'] list_per_page = 10 prepopulated_fields = {'slug': ('title',)} readonly_fields = ('date_taken', 'admin_thumbnail') form = PhotoAdminForm if MULTISITE: filter_horizontal = ['sites'] if MULTISITE: actions = ['add_photos_to_current_site', 'remove_photos_from_current_site'] def formfield_for_manytomany(self, db_field, request, **kwargs): """ Set the current site as initial value. """ if db_field.name == "sites": kwargs["initial"] = [Site.objects.get_current()] return super().formfield_for_manytomany(db_field, request, **kwargs) def add_photos_to_current_site(modeladmin, request, queryset): current_site = Site.objects.get_current() current_site.photo_set.add(*queryset) msg = ngettext( 'The photo has been successfully added to %(site)s', 'The selected photos have been successfully added to %(site)s', len(queryset) ) % {'site': current_site.name} messages.success(request, msg) add_photos_to_current_site.short_description = \ _("Add selected photos to the current site") def remove_photos_from_current_site(modeladmin, request, queryset): current_site = Site.objects.get_current() current_site.photo_set.remove(*queryset) msg = ngettext( 'The photo has been successfully removed from %(site)s', 'The selected photos have been successfully removed from %(site)s', len(queryset) ) % {'site': current_site.name} messages.success(request, msg) remove_photos_from_current_site.short_description = \ _("Remove selected photos from the current site") def get_urls(self): urls = super().get_urls() custom_urls = [ path('upload_zip/', self.admin_site.admin_view(self.upload_zip), name='photologue_upload_zip') ] return custom_urls + urls def upload_zip(self, request): context = { 'title': _('Upload a zip archive of photos'), 'app_label': self.model._meta.app_label, 'opts': self.model._meta, 'has_change_permission': self.has_change_permission(request) } # Handle form request if request.method == 'POST': form = UploadZipForm(request.POST, request.FILES) if form.is_valid(): form.save(request=request) return HttpResponseRedirect('..') else: form = UploadZipForm() context['form'] = form context['adminform'] = helpers.AdminForm(form, list([(None, {'fields': form.base_fields})]), {}) return render(request, 'admin/photologue/photo/upload_zip.html', context) admin.site.register(Photo, PhotoAdmin) class PhotoEffectAdmin(admin.ModelAdmin): list_display = ('name', 'description', 'color', 'brightness', 'contrast', 'sharpness', 'filters', 'admin_sample') fieldsets = ( (None, { 'fields': ('name', 'description') }), ('Adjustments', { 'fields': ('color', 'brightness', 'contrast', 'sharpness') }), ('Filters', { 'fields': ('filters',) }), ('Reflection', { 'fields': ('reflection_size', 'reflection_strength', 'background_color') }), ('Transpose', { 'fields': ('transpose_method',) }), ) admin.site.register(PhotoEffect, PhotoEffectAdmin) class PhotoSizeAdmin(admin.ModelAdmin): list_display = ('name', 'width', 'height', 'crop', 'pre_cache', 'effect', 'increment_count') fieldsets = ( (None, { 'fields': ('name', 'width', 'height', 'quality') }), ('Options', { 'fields': ('upscale', 'crop', 'pre_cache', 'increment_count') }), ('Enhancements', { 'fields': ('effect', 'watermark',) }), ) admin.site.register(PhotoSize, PhotoSizeAdmin) class WatermarkAdmin(admin.ModelAdmin): list_display = ('name', 'opacity', 'style') admin.site.register(Watermark, WatermarkAdmin)