Implement auto-complete for /admin/ forms that reference User

We have so many users now that loading these forms take forever.
Instead, implement a textbox with autocomplete using django-selectable,
which will not load the whole list of users at once.
This commit is contained in:
Magnus Hagander
2016-06-23 17:57:38 +02:00
parent a6d3b44038
commit 27e1c73368
6 changed files with 86 additions and 2 deletions

View File

@ -1,5 +1,27 @@
from django import forms
from django.contrib import admin
from selectable.forms.widgets import AutoCompleteSelectWidget
from pgweb.core.lookups import UserLookup
from models import Contributor, ContributorType
class ContributorAdminForm(forms.ModelForm):
class Meta:
model = Contributor
exclude = ()
widgets = {
'user': AutoCompleteSelectWidget(lookup_class=UserLookup),
}
def __init__(self, *args, **kwargs):
super(ContributorAdminForm, self).__init__(*args, **kwargs)
self.fields['user'].widget.can_add_related = False
self.fields['user'].widget.can_change_related = False
class ContributorAdmin(admin.ModelAdmin):
form = ContributorAdminForm
admin.site.register(ContributorType)
admin.site.register(Contributor)
admin.site.register(Contributor, ContributorAdmin)

View File

@ -1,14 +1,33 @@
from django import forms
from django.contrib import admin
from selectable.forms.widgets import AutoCompleteSelectMultipleWidget
from pgweb.core.models import Version, OrganisationType, Organisation
from pgweb.core.models import ImportedRSSFeed, ImportedRSSItem
from pgweb.core.models import ModerationNotification
from pgweb.core.lookups import UserLookup
class OrganisationAdminForm(forms.ModelForm):
class Meta:
model = Organisation
exclude = ()
widgets = {
'managers': AutoCompleteSelectMultipleWidget(lookup_class=UserLookup),
}
def __init__(self, *args, **kwargs):
super(OrganisationAdminForm, self).__init__(*args, **kwargs)
self.fields['managers'].widget.can_add_related = False
self.fields['managers'].widget.can_change_related = False
self.fields['managers'].widget.can_delete_related = False
class OrganisationAdmin(admin.ModelAdmin):
form = OrganisationAdminForm
list_display = ('name', 'approved', 'lastconfirmed',)
list_filter = ('approved',)
ordering = ('name', )
filter_horizontal = ('managers', )
search_fields = ('name', )
class VersionAdmin(admin.ModelAdmin):

25
pgweb/core/lookups.py Normal file
View File

@ -0,0 +1,25 @@
from django.contrib.auth.models import User
from selectable.base import ModelLookup
from selectable.registry import registry
from selectable.decorators import staff_member_required
@staff_member_required
class UserLookup(ModelLookup):
model = User
search_fields = (
'username__icontains',
'first_name__icontains',
'last_name__icontains',
)
filters = {'is_active': True, }
def get_item_value(self, item):
# Display for currently selected item
return u"%s (%s)" % (item.username, item.get_full_name())
def get_item_label(self, item):
# Display for choice listings
return u"%s (%s)" % (item.username, item.get_full_name())
registry.register(UserLookup)

View File

@ -98,6 +98,7 @@ INSTALLED_APPS = [
'django.contrib.admin',
'django_markwhat',
'django.contrib.staticfiles',
'pgweb.selectable',
'pgweb.core',
'pgweb.mailqueue',
'pgweb.account',

View File

@ -135,6 +135,9 @@ urlpatterns = patterns('',
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
# We use selectable...
(r'^selectable/', include('selectable.urls')),
# This should not happen in production - serve by the webserver natively!
url(r'^(favicon.ico)$', 'django.views.static.serve', {
'document_root': 'media',

View File

@ -1,2 +1,16 @@
{%extends "admin/base.html"%}
{%block branding%}Welcome to the PostgreSQL website administration site | <b><a href="/admin/pending/">Pending</a></b> moderation | <b><a href="/admin/purge/">Purge</a></b> from frontend{%endblock%}
{%block extrahead%}
<link rel="stylesheet" href="/media/css/jquery-ui.css" type="text/css">
<link href="/media/selectable/css/dj.selectable.css" type="text/css" media="all" rel="stylesheet">
<script src="/media/js/jquery.min.js"></script>
<script src="/media/js/jquery-ui.min.js"></script>
<script type="text/javascript" src="/media/selectable/js/jquery.dj.selectable.js"></script>
<style>
ul.selectable-deck li.selectable-deck-item a.selectable-deck-remove {
float: none;
margin-left: 10px;
}
</style>
{%endblock%}