Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Coursera: What we do Thursday, August 30, 12

Slide 3

Slide 3 text

Our Backend Thursday, August 30, 12

Slide 4

Slide 4 text

Why We Need Admin Thursday, August 30, 12

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

☹: 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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

In conclusion... Thursday, August 30, 12

Slide 16

Slide 16 text

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