Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save LuisHCK/72f1fb1d6e594ae9d02a371f285926eb to your computer and use it in GitHub Desktop.
Save LuisHCK/72f1fb1d6e594ae9d02a371f285926eb to your computer and use it in GitHub Desktop.
Django 1.11 Using ModelMultipleChoiceField outside Admin interface with Crispy-Forms

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