extensions-website/extensions/admin.py
Oleg Komarov db67d94507 Use a materialized Extension.latest_version field instead of a dynamic property (#152)
Original reason for this change is #128: we need an efficient way to query tags of a latest_version.

We could potentially avoid converting this property to a field if we had a proper search engine,
but we would still need to define the same explicit triggers for reindexing - i.e. recompute the latest_version change.

This PR also takes a stab at simplifying data flow,
but more work is needed to improve the management of `is_listed` and `status` fields.

Reviewed-on: #152
Reviewed-by: Anna Sirota <railla@noreply.localhost>
2024-05-27 17:58:54 +02:00

260 lines
6.4 KiB
Python

import functools
import logging
from django.contrib import admin
from . import models
from common.admin import NoAddDeleteMixin
from extensions.models import Extension, Maintainer, Version, Tag
log = logging.getLogger(__name__)
class MaintainerInline(admin.TabularInline):
model = Maintainer
autocomplete_fields = ('user',)
extra = 0
class PreviewInline(NoAddDeleteMixin, admin.TabularInline):
model = Extension.previews.through
autocomplete_fields = ('file',)
show_change_link = True
can_add = False
extra = 0
class VersionInline(NoAddDeleteMixin, admin.TabularInline):
model = Version
fields = ('version', 'blender_version_min', 'blender_version_max', 'file')
raw_id_fields = ('file',)
show_change_link = True
extra = 0
class ExtensionAdmin(admin.ModelAdmin):
save_on_top = True
date_hierarchy = 'date_created'
list_display = (
'__str__',
'type',
'status',
'date_created',
'download_count',
'view_count',
'average_score',
)
list_filter = (
'type',
'status',
'is_listed',
'date_approved',
'date_created',
'date_modified',
'date_status_changed',
)
search_fields = (
'id',
'^slug',
'name',
'authors__email',
'authors__full_name',
'authors__username',
'team__name',
'versions__file__user__email',
'versions__file__user__full_name',
'versions__file__user__username',
)
inlines = (MaintainerInline, PreviewInline, VersionInline)
readonly_fields = (
'id',
'type',
'slug',
'date_created',
'date_status_changed',
'date_approved',
'date_modified',
'average_score',
'text_ratings_count',
'total_ratings_count',
'download_count',
'view_count',
'website',
'icon',
'featured_image',
'latest_version',
)
autocomplete_fields = ('team',)
fieldsets = (
(
'Details',
{
'fields': (
('team',),
('id', 'type', 'extension_id'),
(
'date_created',
'date_status_changed',
'date_approved',
'date_modified',
),
'name',
'slug',
'description',
('icon', 'featured_image'),
'status',
'latest_version',
),
},
),
(
'Support',
{
'fields': ('website', 'support'),
},
),
(
'Stats',
{
'fields': (
('average_score', 'text_ratings_count', 'download_count', 'view_count'),
),
},
),
)
def get_urls(self):
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return functools.update_wrapper(wrapper, view)
urlpatterns = super().get_urls()
custom_urlpatterns = []
return custom_urlpatterns + urlpatterns
class VersionAdmin(admin.ModelAdmin):
save_on_top = True
date_hierarchy = 'date_created'
list_display = (
'__str__',
'extension',
'download_count',
'average_score',
)
list_filter = (
'file__status',
'blender_version_min',
'blender_version_max',
'permissions',
'date_created',
'date_modified',
'licenses',
'tags',
'platforms',
)
search_fields = (
'id',
'extension__slug',
'extension__name',
'extension__extension_id',
'file__user__email',
'file__user__full_name',
'file__user__username',
)
autocomplete_fields = ('extension', 'file')
readonly_fields = (
'id',
'tagline',
'date_created',
'date_modified',
'average_score',
'download_count',
)
fieldsets = (
(
'Details',
{
'fields': (
'id',
'tagline',
('date_created', 'date_modified'),
'extension',
'version',
'blender_version_min',
'blender_version_max',
'release_notes',
'licenses',
'tags',
'file',
'permissions',
'platforms',
),
},
),
(
'Stats',
{
'fields': (
'average_score',
'download_count',
),
},
),
)
def get_urls(self):
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return functools.update_wrapper(wrapper, view)
urlpatterns = super().get_urls()
custom_urlpatterns = []
return custom_urlpatterns + urlpatterns
class MaintainerAdmin(admin.ModelAdmin):
model = Maintainer
list_display = ('extension', 'user')
readonly_fields = ('extension', 'user')
class LicenseAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'url')
class PlatformAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
class TagAdmin(admin.ModelAdmin):
model = Tag
list_display = ('name', 'slug', 'type')
def get_readonly_fields(self, request, ob=None):
"""Allow to edit all fields when adding a new tag, but not when editing an existing one"""
if ob:
return ('name', 'type')
else:
return ()
class VersionPermissionAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
admin.site.register(models.Extension, ExtensionAdmin)
admin.site.register(models.Version, VersionAdmin)
admin.site.register(models.Maintainer, MaintainerAdmin)
admin.site.register(models.License, LicenseAdmin)
admin.site.register(models.Platform, PlatformAdmin)
admin.site.register(models.Tag, TagAdmin)
admin.site.register(models.VersionPermission, VersionPermissionAdmin)