From 201608c49c16a89705536fe785a2e0371b0f7123 Mon Sep 17 00:00:00 2001 From: Marc Aymerich Date: Tue, 23 Feb 2016 11:49:10 +0000 Subject: [PATCH] Improved admin performance --- TODO.md | 12 +---- orchestra/contrib/bills/admin.py | 28 +++++----- orchestra/contrib/bills/models.py | 3 +- orchestra/contrib/domains/admin.py | 3 ++ orchestra/contrib/lists/admin.py | 3 ++ orchestra/contrib/mailboxes/admin.py | 2 + .../management/commands/orchestrate.py | 6 +-- orchestra/contrib/orders/admin.py | 51 ++++++++++++++++++- orchestra/contrib/payments/admin.py | 4 ++ 9 files changed, 81 insertions(+), 31 deletions(-) diff --git a/TODO.md b/TODO.md index 7ad9bd01..8590a3fc 100644 --- a/TODO.md +++ b/TODO.md @@ -435,7 +435,7 @@ mkhomedir_helper or create ssh homes with bash.rc and such # DOmain show implicit records -# if not database_ready(): schedule a retry in 60 seconds, otherwise resources and other dynamic content gets fucked, maybe attach some 'signal' when first query goes trough +# if not database_ready(): schedule a retry in 60 seconds, otherwise resources and other dynamic content gets fucked, maybe attach some 'signal' when first query goes trough with database_ready: shit_happend, otherwise schedule for first query # Entry.objects.filter()[:1].first() (LIMIT 1) @@ -443,24 +443,14 @@ mkhomedir_helper or create ssh homes with bash.rc and such # put "Coordinate Apache restart" inside a bash function for clarity -# mailscanner phishing, spam, whitelist choices - - # show base and total desglosed - # Reverse lOgHistory order by date (lastest first) - * setuppostgres use porject_name for db name and user instead of orchestra - # POSTFIX web traffic monitor '": uid=" from=<%(user)s>' # Automatically re-run backends until success? only timedout executions? # TODO save serialized versions ob backendoperation.instance in order to allow backend reexecution of deleted objects - -# INDEXES for most used queries: account FK - - diff --git a/orchestra/contrib/bills/admin.py b/orchestra/contrib/bills/admin.py index 65d0c9c8..4631b15d 100644 --- a/orchestra/contrib/bills/admin.py +++ b/orchestra/contrib/bills/admin.py @@ -64,10 +64,10 @@ class BillLineInline(admin.TabularInline): kwargs['widget'] = forms.TextInput(attrs={'size':'50'}) elif db_field.name not in ('start_on', 'end_on'): kwargs['widget'] = forms.TextInput(attrs={'size':'6'}) - return super(BillLineInline, self).formfield_for_dbfield(db_field, **kwargs) + return super().formfield_for_dbfield(db_field, **kwargs) def get_queryset(self, request): - qs = super(BillLineInline, self).get_queryset(request) + qs = super().get_queryset(request) return qs.prefetch_related('sublines').select_related('order') @@ -141,7 +141,7 @@ class BillLineAdmin(admin.ModelAdmin): display_total.admin_order_field = 'computed_total' def get_queryset(self, request): - qs = super(BillLineAdmin, self).get_queryset(request) + qs = super().get_queryset(request) qs = qs.annotate( subline_total=Sum('sublines__total'), computed_total=(F('subtotal') + Sum(Coalesce('sublines__total', 0))) * (1+F('tax')/100), @@ -151,7 +151,7 @@ class BillLineAdmin(admin.ModelAdmin): class BillLineManagerAdmin(BillLineAdmin): def get_queryset(self, request): - qset = super(BillLineManagerAdmin, self).get_queryset(request) + qset = super().get_queryset(request) if self.bill_ids: return qset.filter(bill_id__in=self.bill_ids) return qset @@ -182,7 +182,7 @@ class BillLineManagerAdmin(BillLineAdmin): 'title': title, } context.update(extra_context or {}) - return super(BillLineManagerAdmin, self).changelist_view(request, context) + return super().changelist_view(request, context) class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): @@ -288,7 +288,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): def get_urls(self): """ Hook bill lines management URLs on bill admin """ - urls = super(BillAdmin, self).get_urls() + urls = super().get_urls() admin_site = self.admin_site extra_urls = [ url("^manage-lines/$", @@ -298,13 +298,13 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): return extra_urls + urls def get_readonly_fields(self, request, obj=None): - fields = super(BillAdmin, self).get_readonly_fields(request, obj) + fields = super().get_readonly_fields(request, obj) if obj and not obj.is_open: fields += self.add_fields return fields def get_fieldsets(self, request, obj=None): - fieldsets = super(BillAdmin, self).get_fieldsets(request, obj) + fieldsets = super().get_fieldsets(request, obj) if obj: # Switches between amend_of_link and amend_links fields if obj.amend_of_id: @@ -316,7 +316,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): return fieldsets def get_change_view_actions(self, obj=None): - actions = super(BillAdmin, self).get_change_view_actions(obj) + actions = super().get_change_view_actions(obj) exclude = [] if obj: if not obj.is_open: @@ -326,7 +326,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): return [action for action in actions if action.__name__ not in exclude] def get_inline_instances(self, request, obj=None): - inlines = super(BillAdmin, self).get_inline_instances(request, obj) + inlines = super().get_inline_instances(request, obj) if obj and not obj.is_open: return [inline for inline in inlines if type(inline) != BillLineInline] return [inline for inline in inlines if type(inline) != ClosedBillLineInline] @@ -337,13 +337,13 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4}) elif db_field.name == 'html': kwargs['widget'] = forms.Textarea(attrs={'cols': 150, 'rows': 20}) - formfield = super(BillAdmin, self).formfield_for_dbfield(db_field, **kwargs) + formfield = super().formfield_for_dbfield(db_field, **kwargs) if db_field.name == 'amend_of': formfield.queryset = formfield.queryset.filter(is_open=False) return formfield def get_queryset(self, request): - qs = super(BillAdmin, self).get_queryset(request) + qs = super().get_queryset(request) qs = qs.annotate( models.Count('lines'), # FIXME https://code.djangoproject.com/ticket/10060 @@ -360,7 +360,7 @@ class BillAdmin(AccountAdminMixin, ExtendedModelAdmin): # TODO raise404, here and everywhere bill = self.get_object(request, unquote(object_id)) actions.validate_contact(request, bill, error=False) - return super(BillAdmin, self).change_view(request, object_id, **kwargs) + return super().change_view(request, object_id, **kwargs) admin.site.register(Bill, BillAdmin) @@ -384,7 +384,7 @@ class BillContactInline(admin.StackedInline): kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 2}) if db_field.name == 'email_usage': kwargs['widget'] = paddingCheckboxSelectMultiple(45) - return super(BillContactInline, self).formfield_for_dbfield(db_field, **kwargs) + return super().formfield_for_dbfield(db_field, **kwargs) def has_bill_contact(account): diff --git a/orchestra/contrib/bills/models.py b/orchestra/contrib/bills/models.py index 69f56342..d0bc3d6d 100644 --- a/orchestra/contrib/bills/models.py +++ b/orchestra/contrib/bills/models.py @@ -404,7 +404,8 @@ class BillLine(models.Model): start_on = models.DateField(_("start")) end_on = models.DateField(_("end"), null=True, blank=True) order = models.ForeignKey(settings.BILLS_ORDER_MODEL, null=True, blank=True, - help_text=_("Informative link back to the order"), on_delete=models.SET_NULL) + related_name='lines', on_delete=models.SET_NULL, + help_text=_("Informative link back to the order")) order_billed_on = models.DateField(_("order billed"), null=True, blank=True) order_billed_until = models.DateField(_("order billed until"), null=True, blank=True) created_on = models.DateField(_("created"), auto_now_add=True) diff --git a/orchestra/contrib/domains/admin.py b/orchestra/contrib/domains/admin.py index 09d61c57..e735c1da 100644 --- a/orchestra/contrib/domains/admin.py +++ b/orchestra/contrib/domains/admin.py @@ -104,6 +104,9 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin): fieldsets += ( (_("SOA"), { 'classes': ('collapse',), + 'description': _( + "SOA (Start of Authority) records are used to determine how your " + "zone propagates to the secondary nameservers."), 'fields': ('serial', 'refresh', 'retry', 'expire', 'min_ttl'), }), ) diff --git a/orchestra/contrib/lists/admin.py b/orchestra/contrib/lists/admin.py index 0ddc1cc8..15c6ff9a 100644 --- a/orchestra/contrib/lists/admin.py +++ b/orchestra/contrib/lists/admin.py @@ -10,6 +10,7 @@ from orchestra.contrib.accounts.actions import list_accounts from orchestra.contrib.accounts.admin import SelectAccountAdminMixin from orchestra.contrib.accounts.filters import IsActiveListFilter +from . import settings from .forms import ListCreationForm, ListChangeForm from .models import List @@ -39,6 +40,8 @@ class ListAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModel }), (_("Address"), { 'classes': ('wide',), + 'description': _("Additional address besides the default <name>@%s" + ) % settings.LISTS_DEFAULT_DOMAIN, 'fields': (('address_name', 'address_domain'),) }), (_("Admin"), { diff --git a/orchestra/contrib/mailboxes/admin.py b/orchestra/contrib/mailboxes/admin.py index f22308c7..8ec1ed36 100644 --- a/orchestra/contrib/mailboxes/admin.py +++ b/orchestra/contrib/mailboxes/admin.py @@ -49,6 +49,8 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo }), (_("Custom filtering"), { 'classes': ('collapse',), + 'description': _("Please remember to select custom filtering " + "if you want this filter to be applied."), 'fields': ('custom_filtering',), }), (_("Addresses"), { diff --git a/orchestra/contrib/orchestration/management/commands/orchestrate.py b/orchestra/contrib/orchestration/management/commands/orchestrate.py index cb545dea..8fb7def3 100644 --- a/orchestra/contrib/orchestration/management/commands/orchestrate.py +++ b/orchestra/contrib/orchestration/management/commands/orchestrate.py @@ -78,16 +78,16 @@ class Command(BaseCommand): for instance in queryset: manager.collect(instance, action, operations=operations, route_cache=route_cache) scripts, serialize = manager.generate(operations) - servers = [] + servers = set() # Print scripts for key, value in scripts.items(): route, __, __ = key backend, operations = value - servers.append(str(route.host)) + servers.add(str(route.host)) self.stdout.write('# Execute %s on %s' % (backend.get_name(), route.host)) for method, commands in backend.scripts: script = '\n'.join(commands) - self.stdout.write(script) + self.stdout.write(script.encode('ascii', errors='replace').decode()) if interactive: context = { 'servers': ', '.join(servers), diff --git a/orchestra/contrib/orders/admin.py b/orchestra/contrib/orders/admin.py index 77e6d27e..f2f3ac70 100644 --- a/orchestra/contrib/orders/admin.py +++ b/orchestra/contrib/orders/admin.py @@ -1,3 +1,4 @@ +from django import forms from django.contrib import admin from django.core.urlresolvers import reverse, NoReverseMatch from django.db.models import Prefetch @@ -38,8 +39,9 @@ class MetricStorageInline(admin.TabularInline): change_view = bool(self.parent_object and self.parent_object.pk) if change_view: qs = qs.order_by('-id') + parent_id = self.parent_object.pk try: - tenth_id = qs.filter(order_id=self.parent_object.pk).values_list('id', flat=True)[9] + tenth_id = qs.filter(order_id=parent_id).values_list('id', flat=True)[9] except IndexError: pass else: @@ -72,7 +74,37 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin): Prefetch('metrics', queryset=MetricStorage.objects.order_by('-id')), ) list_select_related = ('account', 'service') - readonly_fields = ('content_object_repr', 'content_object_link') + add_fieldsets = ( + (None, { + 'fields': ('account', 'service') + }), + (_("Object"), { + 'fields': ('content_type', 'object_id',), + }), + (_("State"), { + 'fields': ('registered_on', 'cancelled_on', 'billed_on', 'billed_metric', + 'billed_until' ) + }), + (None, { + 'fields': ('description', 'ignore',), + }), + ) + fieldsets = ( + (None, { + 'fields': ('account_link', 'service_link', 'content_object_link'), + }), + (_("State"), { + 'fields': ('registered_on', 'cancelled_on', 'billed_on', 'billed_metric', + 'billed_until' ) + }), + (None, { + 'fields': ('description', 'ignore', 'bills_links'), + }), + ) + readonly_fields = ( + 'content_object_repr', 'content_object_link', 'bills_links', 'account_link', + 'service_link' + ) service_link = admin_link('service') display_registered_on = admin_date('registered_on') @@ -99,6 +131,15 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin): content_object_link.allow_tags = True content_object_link.admin_order_field = 'content_object_repr' + def bills_links(self, order): + bills = [] + make_link = admin_link() + for line in order.lines.select_related('bill').distinct('bill'): + bills.append(make_link(line.bill)) + return '