{"id":366,"date":"2012-07-23T11:12:18","date_gmt":"2012-07-23T15:12:18","guid":{"rendered":"http:\/\/dashdrum.com\/blog\/?p=366"},"modified":"2012-12-18T12:41:46","modified_gmt":"2012-12-18T16:41:46","slug":"relatedfieldwidgetwrapper","status":"publish","type":"post","link":"https:\/\/dashdrum.com\/blog\/2012\/07\/relatedfieldwidgetwrapper\/","title":{"rendered":"RelatedFieldWidgetWrapper"},"content":{"rendered":"<p>The RelatedFieldWidgetWrapper (found in django.contrib.admin.widgets) is used in the Admin pages to include the capability on a Foreign Key control to add a new related record. (In English: puts the little green plus sign to the right of the control.) In a new application of the <a href=\"http:\/\/dashdrum.com\/blog\/2012\/05\/using-the-filterselectmultiple-widget\/\" title=\"Using the FilterSelectMultiple Widget\">FilteredSelectMultiple widget I discussed recently<\/a>, I needed to add this functionality.<\/p>\n<p>This wrapper is a little\u00c2\u00a0complicated, but it didn&#8217;t take too much Google searching to find an example. \u00c2\u00a0A <a title=\"Crimson Online admin.py\" href=\"http:\/\/crimson-online.googlecode.com\/svn-history\/r4601\/branches\/adminfun\/content\/admin.py\" target=\"_blank\">Google Code file from something called Crimson Online<\/a> helped me understand the concept.<\/p>\n<p>The wrapper takes three required parameters plus one optional:<\/p>\n<ol>\n<li>The widget to be wrapped. In my case the FilteredSelectMultiple widget<\/li>\n<li>A relation that defines the two models involved<\/li>\n<li>A reference to the admin site<\/li>\n<li>The Boolean can&#95;add&#95;related (optional)<\/li>\n<\/ol>\n<p>For the first parameter, I used the widget with its parameters:<\/p>\n<p><code>FilteredSelectMultiple(('entities'),False,)<\/code><\/p>\n<p>The relation confused me at first, but the example made it easy. \u00c2\u00a0The model linked to the form, in this case Item, provides it.<\/p>\n<p><code>Item._meta.get_field('entities').re<\/code>l<\/p>\n<p>The third parameter, the admin site object, is used along with the relation to determine if the user has permission to add this related model. \u00c2\u00a0The example used django.contrib.admin.site, which I found doesn&#8217;t work. \u00c2\u00a0Instead, I captured the admin&#95;site value from the ModelAdmin class in my admin.py and set it as a variable for the form. \u00c2\u00a0Then I referenced that variable in the &#92;_&#95;init&#95;_ method of the form to include it in the widget. \u00c2\u00a0This means that the widget has to be assigned within the &#95;&#95;init&#95;&#95; method of the form.<\/p>\n<p><code>self.admin_site<\/code><\/p>\n<p>The fourth parameter can be used to override the permission check performed by the widget. \u00c2\u00a0However, when a user without the permission to add clicks that little green plus sign, an ugly 500 error is returned.<\/p>\n<p>Here is the code used:<\/p>\n<h1>in admin.py:<\/h1>\n<pre>class ItemAdmin(admin.ModelAdmin):\n    form = ItemAdminForm\n\n    def __init__(self, model, admin_site):\n        super(ItemAdmin,self).__init__(model,admin_site)\n        self.form.admin_site = admin_site # capture the admin_site\n\nadmin.site.register(Item, ItemAdmin)<\/pre>\n<h1>in forms.py<\/h1>\n<pre>from django.contrib.admin.widgets import FilteredSelectMultiple, RelatedFieldWidgetWrapper\n\nclass ItemAdminForm(forms.ModelForm):\n    entities = forms.ModelMultipleChoiceField(queryset=None,label=('Select Entities'),)\n\n    def __init__(self, *args, **kwargs):\n        super(ItemAdminForm,self).__init__(*args, **kwargs)\n        # set the widget with wrapper\n        self.fields['entities'].widget = RelatedFieldWidgetWrapper(\n                                                FilteredSelectMultiple(('entities'),False,),\n                                                Item._meta.get_field('entities').rel,\n                                                self.admin_site)\n        self.fields['entities'].queryset = Entity.objects.all()\n\n    class Media:\n        ## media for the FilteredSelectMultiple widget\n        css = {\n            'all':('\/media\/css\/widgets.css',),\n        }\n        # jsi18n is required by the widget\n        js = ('\/admin\/jsi18n\/',)\n\n    class Meta:\n        model = Item<\/pre>\n<h2>UPDATE:<\/h2>\n<p>I&#8217;ve published a follow up post that covers using this wrapper outside of the admin application. See <a href=\"http:\/\/dashdrum.com\/blog\/2012\/12\/more-relatedfieldwidgetwrapper-the-popup\/\">More RelatedFieldWidgetWrapper &#8211; My Very Own Popup<\/a>.<\/p>\n<p>\u00c2\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The RelatedFieldWidgetWrapper (found in django.contrib.admin.widgets) is used in the Admin pages to include the capability on a Foreign Key control to add a new related record. (In English: puts the little green plus sign to the right of the control.) In a new application of the FilteredSelectMultiple widget I discussed recently, I needed to add &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/dashdrum.com\/blog\/2012\/07\/relatedfieldwidgetwrapper\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;RelatedFieldWidgetWrapper&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-366","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/366","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/comments?post=366"}],"version-history":[{"count":13,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/366\/revisions"}],"predecessor-version":[{"id":430,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/366\/revisions\/430"}],"wp:attachment":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/media?parent=366"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/categories?post=366"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/tags?post=366"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}