Created
August 18, 2017 12:30
-
-
Save s-boardman/811ad38613f3eb9cfea214bcce10f918 to your computer and use it in GitHub Desktop.
Django 1.11 Using ModelMultipleChoiceField outside Admin interface with Crispy-Forms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# How to use the ModelMultipleChoiceField widget outside the Django admin interface | |
# when processing forms with Crispy-forms | |
## Prerequisites | |
django-crispy-forms installed and included in settings (as per crispy docs) | |
## Edited files: | |
### urls.py (root, not app/urls.py) | |
Note that this must be the first entry in the urlpatterns list. | |
``` | |
from django.views.i18n import JavaScriptCatalog | |
urlpatterns = [ | |
url(r'^app/admin/jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'), | |
... | |
] | |
``` | |
### app/forms.py | |
``` | |
from django import forms | |
from django.contrib.admin.widgets import FilteredSelectMultiple | |
from crispy_forms.helper import FormHelper | |
class MultiForm(forms.ModelForm): | |
class Meta: | |
model = MultiModel | |
fields = ('name', ) | |
name = forms.ModelChoiceField(required=True) | |
multi = (forms.ModelMultipleChoiceField(label='Multi', | |
queryset=Multi.objects.none(), | |
widget=FilteredSelectMultiple( | |
verbose_name='Multis', | |
is_stacked=False, | |
), | |
required=False)) | |
class Media: | |
css = {'all': ('/static/admin/css/widgets.css', ), | |
'/static/css/adminoverrides.css', ), } # custom css | |
def __init__(self, *args, **kwargs): | |
self.helper = FormHelper() | |
self.helper.layout = Layout( | |
Div('name', 'mutli', ), | |
Submit('submit', 'Save Genes', | |
css_class="save btn btn-success") | |
) | |
super(SampleGeneForm, self).__init__(*args, **kwargs) | |
``` | |
### template.html | |
Assumes you have a base template which contains blocks for extrastyle (inserted between `<head></head>` tags) and content. | |
``` | |
{% extends 'base.html' %} | |
{% block extrastyle %} | |
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script> | |
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script> | |
{% endblock %} | |
{% block content %} | |
{% load crispy_forms_tags %} | |
{% crispy form %} | |
{% endblock %} | |
``` | |
### app/static/css/adminoverrides.css | |
To make it play nicely with bootstrap | |
``` | |
/* overrides to default admin styles */ | |
/* SELECTOR (FILTER INTERFACE) */ | |
.selector .selector-filter { | |
border: 0px solid #ccc; | |
border-width: 0 0px; | |
padding: 4px 0px 4px 0px; | |
} | |
.selector .selector-filter label { | |
display: none; | |
} | |
.selector select { | |
height: 17.2em; | |
width: 100%; /* fix offscreen scroll-bar on selector-chosen */ | |
border: 1px #ccc solid; | |
} | |
.selector .selector-chosen select { | |
border-top: 0; | |
} | |
/* fix offscreen scroll-bar on selector-chosen */ | |
.selector-available, .selector-chosen { | |
width: 47%; | |
} | |
/* selector object list */ | |
.selector > .selector-available > select, .selector > .selector-chosen > select { | |
font-size: 12px; | |
color: #666; | |
background-color: #fff; | |
background-image: none; | |
border: 1px solid #ccc; | |
border-radius: 0px 0px 4px 4px; | |
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.075) inset; | |
transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; | |
} | |
/* selector object list items */ | |
.selector > .selector-available > select > option, .selector > .selector-chosen > select > option { | |
padding: 6px; | |
border-bottom-width: 1px; | |
border-bottom-color: rgba(211, 211, 211, 0.35); | |
border-bottom-style: solid | |
} | |
/* selector field title */ | |
.selector > .selector-available > h2, .selector > .selector-chosen > h2 { | |
text-align: left; | |
background: rgba(211, 211, 211, 0.2); | |
color: #777; | |
border: 1px solid #ccc; | |
border-bottom: none; | |
font-size: 100%; | |
font-weight: 600; | |
margin: 0px; | |
padding: 10px 0px 6px 10px; | |
height: 36px; | |
border-radius: 4px 4px 0px 0px; | |
} | |
/* selector filter box bootstrapping */ | |
.selector .selector-available input { | |
width: 80%; | |
height: 34px; | |
padding: 6px 12px; | |
font-size: 14px; | |
line-height: 1.42857; | |
color: #777; | |
background-color: #fff; | |
background-image: none; | |
border: 1px solid #ccc; | |
border-radius: 4px; | |
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset; | |
transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; | |
} | |
.selector .selector-available p { | |
background: rgba(211, 211, 211, 0.2); | |
border-left: 1px solid #ccc; | |
border-right: 1px solid #ccc; | |
padding: 0px 0px 7px 6px; | |
} | |
/* selector chooseall and clearall button spacing */ | |
a.selector-chooseall { | |
padding: 0px 20px 3px 0; | |
} | |
a.selector-clearall { | |
padding: 0px 0 3px 20px; | |
} | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks a LOT
Works perfect!