$30 off During Our Annual Pro Sale. View Details »

Django Admin: Widgetry & Witchery

Pamela Fox
August 31, 2012

Django Admin: Widgetry & Witchery

Why we chose to use Django admin, and how it worked, and, well, how it didn't work.

Pamela Fox

August 31, 2012
Tweet

More Decks by Pamela Fox

Other Decks in Technology

Transcript

  1. Django Admin
    Widgetry & Witchery
    Pamela Fox
    @pamelafox
    Thursday, August 30, 12

    View Slide

  2. Coursera: What we do
    Thursday, August 30, 12

    View Slide

  3. Our Backend
    Thursday, August 30, 12

    View Slide

  4. Why We Need Admin
    Thursday, August 30, 12

    View Slide

  5. Why Django Admin?
    Creates forms for adding/editing/searching models
    Restricts fields based on admin roles
    Thursday, August 30, 12

    View Slide

  6. How Django Admin Works
    https://docs.djangoproject.com/en/dev/ref/contrib/admin/
    from django.contrib import admin
    from app import admin
    from app.courses.models import Course
    from app.courses.forms import CourseAdminForm
    class CourseAdmin(ModelAdmin):
    base_model = Course
    restrict_fields = ['instructors', 'teaching_assistants', ]
    form = CourseAdminForm
    fieldsets = [
    (None, {
    'fields': [
    'name',
    'topic',
    'active',
    ]
    }),
    ('Dates', {
    'fields': [
    'start_date',
    'end_date',
    'start_date_string',
    'duration_string',
    ]
    })
    ]
    admin.site.register(Course, CourseAdmin)
    Thursday, August 30, 12

    View Slide

  7. ...And a few words on
    how it doesn’t work.
    Thursday, August 30, 12

    View Slide

  8. ☹: The Look & Feel
    !=
    Thursday, August 30, 12

    View Slide

  9. Solution:
    Twitter Bootstrap
    https://github.com/gkuhn1/django-admin-templates-twitter-bootstrap
    Thursday, August 30, 12

    View Slide

  10. ☹: The Default Widgets
    BooleanField
    CharField
    ChoiceField
    TypedChoiceField
    DateField
    DateTimeField
    DecimalField
    EmailField
    FileField
    FilePathField
    FloatField
    ImageField
    IntegerField
    IPAddressField
    GenericIPAddressField
    MultipleChoiceField
    TypedMultipleChoiceField
    NullBooleanField
    RegexField
    SlugField
    TimeField
    URLField
    ComboField
    MultiValueField
    SplitDateTimeField
    ModelChoiceField
    ModelMultipleChoiceField
    Thursday, August 30, 12

    View Slide

  11. Solution:
    Custom Widgets
    WysiHTMLEditor
    TransloaditUpload
    UniqueShortName
    NumberField NumberRangeField
    AutoCompleteTextInput
    Thursday, August 30, 12

    View Slide

  12. Custom Widgets
    class NumberField(HiddenInput):
    class Media:
    js = (
    settings.ADMIN_MEDIA_PREFIX + 'js/numberfields.js',
    )
    def render(self, name, value, attrs=None):
    input = super(NumberField, self).render(name, value, attrs=attrs)
    final_attrs = self.build_attrs(attrs)
    units = final_attrs.get('units', '')
    html = u"""

    %(input)s

    %(units)s

    """ % {'input': input, 'units': units}
    return mark_safe(html)
    admin/common/widgets.py:
    from django.forms import ModelForm
    from app.common.widgets import NumberField
    class CourseAdminForm(ModelForm):
    class Meta:
    widgets = {
    'duration_string': NumberField(
    attrs={'units': 'weeks'})
    }
    course/forms.py
    from app import admin
    from app.courses.models import Course
    from app.courses.forms import CourseAdminForm
    class CourseAdmin(ModelAdmin):
    base_model = Course
    form = CourseAdminForm
    course/admin.py
    Thursday, August 30, 12

    View Slide

  13. ☹: Default Save Options
    !=
    Thursday, August 30, 12

    View Slide

  14. Solution:
    Horrible Hacks
    var topicPageRegEx = /\/topics\/topic\//i;
    var isTopicPage = topicPageRegEx.exec(window.location.href);
    if (isTopicPage) {
    var previewHosts = {'admin': 'site', 'admin.coursera.org': 'www.coursera.org'};
    var previewUrl = 'http://' + previewHosts[window.location.host] + '/course/' + $
    ('input[name="short_name"]').val();
    var $previewUrl = $('').val(previewUrl);
    var $previewButton = $('');
    var $saveButton = $('.form-actions input[name="_save"]')
    $saveButton.after(' ').after($previewButton)
    .after(' ').after($previewUrl);
    }
    templates/admin/change_form.html
    if "_saveandpreview" in request.POST:
    return HttpResponseRedirect(request.POST['_previewurl'])
    admin/options.py
    Thursday, August 30, 12

    View Slide

  15. In conclusion...
    Thursday, August 30, 12

    View Slide

  16. Our Future Admin Stack?
    https://github.com/PaulUithol/backbone-tastypie https://github.com/joshbohde/django-backbone-example
    Thursday, August 30, 12

    View Slide