use Django's Admin FilteredSelectMultiple for Group Membership

This commit is contained in:
Jens Langhammer 2019-03-10 18:06:06 +01:00
parent 5f861189e4
commit 2b8c2b2346
4 changed files with 190 additions and 4 deletions

View File

@ -2,10 +2,20 @@
{% load i18n %} {% load i18n %}
{% load utils %} {% load utils %}
{% load static %}
{% block head %} {% block head %}
{{ block.super }} {{ block.super }}
{{ form.media.css }} {{ form.media.css }}
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/actions.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/urlify.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/prepopulate.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/SelectBox.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/SelectFilter2.js' %}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@ -2,12 +2,14 @@
from django import forms from django import forms
from passbook.core.models import Group, User from passbook.core.models import Group, User
from django.contrib.admin.widgets import FilteredSelectMultiple
class GroupForm(forms.ModelForm): class GroupForm(forms.ModelForm):
"""Group Form""" """Group Form"""
members = forms.ModelMultipleChoiceField(User.objects.all(), required=False) members = forms.ModelMultipleChoiceField(
User.objects.all(), required=False, widget=FilteredSelectMultiple('users', False))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -18,7 +20,7 @@ class GroupForm(forms.ModelForm):
instance = super().save(*args, **kwargs) instance = super().save(*args, **kwargs)
if instance.pk: if instance.pk:
instance.user_set.clear() instance.user_set.clear()
instance.user_set.add(*self.cleaned_data['users']) instance.user_set.add(*self.cleaned_data['members'])
return instance return instance
class Meta: class Meta:

View File

@ -1,4 +1,4 @@
# Generated by Django 2.1.7 on 2019-03-08 14:17 # Generated by Django 2.1.7 on 2019-03-10 16:15
import django.contrib.postgres.fields.hstore import django.contrib.postgres.fields.hstore
from django.contrib.postgres.operations import HStoreExtension from django.contrib.postgres.operations import HStoreExtension
@ -8,7 +8,7 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('passbook_core', '0016_auto_20190227_1355'), ('passbook_core', '0018_provider_property_mappings'),
] ]
operations = [ operations = [

View File

@ -21,3 +21,177 @@
.dynamic-array-widget .remove:hover { .dynamic-array-widget .remove:hover {
cursor: pointer; cursor: pointer;
} }
/* Selector */
.selector {
display: flex;
width: 100%;
height: 45vh;
}
.selector .selector-filter {
display: flex;
align-items: center;
}
.selector .selector-filter label {
margin: 0 8px 0 0;
}
.selector .selector-filter input {
width: auto;
min-height: 0;
flex: 1 1;
}
.selector-available, .selector-chosen {
width: auto;
flex: 1 1;
display: flex;
flex-direction: column;
}
.selector select {
width: 100%;
flex: 1 0 auto;
margin-bottom: 5px;
}
.selector ul.selector-chooser {
width: 26px;
height: 52px;
padding: 2px 0;
margin: auto 15px;
border-radius: 20px;
transform: translateY(-10px);
list-style: none;
}
.selector-add, .selector-remove {
width: 20px;
height: 20px;
background-size: 20px auto;
}
.selector-add {
background-position: 0 -120px;
}
.selector-remove {
background-position: 0 -80px;
}
a.selector-chooseall, a.selector-clearall {
align-self: center;
}
.stacked {
flex-direction: column;
max-width: 480px;
}
.stacked > * {
flex: 0 1 auto;
}
.stacked select {
margin-bottom: 0;
}
.stacked .selector-available, .stacked .selector-chosen {
width: auto;
}
.stacked ul.selector-chooser {
width: 52px;
height: 26px;
padding: 0 2px;
margin: 15px auto;
transform: none;
}
.stacked .selector-chooser li {
padding: 3px;
}
.stacked .selector-add, .stacked .selector-remove {
background-size: 20px auto;
}
.stacked .selector-add {
background-position: 0 -40px;
}
.stacked .active.selector-add {
background-position: 0 -60px;
}
.stacked .selector-remove {
background-position: 0 0;
}
.stacked .active.selector-remove {
background-position: 0 -20px;
}
.help-tooltip, .selector .help-icon {
display: none;
}
form .form-row p.datetime {
width: 100%;
}
.datetime input {
width: 50%;
max-width: 120px;
}
.datetime span {
font-size: 13px;
}
.datetime .timezonewarning {
display: block;
font-size: 11px;
color: #999;
}
.datetimeshortcuts {
color: #ccc;
}
.inline-group {
overflow: auto;
}
.selector-add, .selector-remove {
width: 16px;
height: 16px;
display: block;
text-indent: -3000px;
overflow: hidden;
cursor: default;
opacity: 0.3;
}
.active.selector-add, .active.selector-remove {
opacity: 1;
}
.active.selector-add:hover, .active.selector-remove:hover {
cursor: pointer;
}
.selector-add {
background: url(../admin/img/selector-icons.svg) 0 -96px no-repeat;
}
.active.selector-add:focus, .active.selector-add:hover {
background-position: 0 -112px;
}
.selector-remove {
background: url(../admin/img/selector-icons.svg) 0 -64px no-repeat;
}