def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if hasattr(db_field, 'through' ) and not db_field.remote_field.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget( db_field.remote_field, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple( db_field.verbose_name, db_field.name in self.filter_vertical) if 'queryset' not in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset form_field = db_field.formfield(**kwargs) if isinstance(form_field.widget, SelectMultiple) and not isinstance( form_field.widget, CheckboxSelectMultiple): msg = _( 'Hold down "Control", or "Command" on a Mac, to select more than one.' ) help_text = form_field.help_text form_field.help_text = string_concat(help_text, ' ', msg) if help_text else msg return form_field
def test_render(self): band = models.Band.objects.create(name='Linkin Park') m1 = models.Member.objects.create(name='Chester') m2 = models.Member.objects.create(name='Mike') band.members.add(m1, m2) rel = models.Band._meta.get_field('members').rel w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) self.assertEqual( conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={})), '<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="/static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk) ) self.assertEqual( conditional_escape(w.render('test', [m1.pk])), '<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % dict(admin_media_prefix(), m1pk=m1.pk) ) self.assertEqual(w._has_changed(None, None), False) self.assertEqual(w._has_changed([], None), False) self.assertEqual(w._has_changed(None, [u'1']), True) self.assertEqual(w._has_changed([1, 2], [u'1', u'2']), False) self.assertEqual(w._has_changed([1, 2], [u'1']), True) self.assertEqual(w._has_changed([1, 2], [u'1', u'3']), True)
def adminform_formfield(db_field, **kwargs): """ Enables admin form widgets when used as formfield_callback. Use with CAUTION as using admin widgets is at your risk :) """ if db_field.choices: return db_field.formfield(**kwargs) if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): if isinstance(db_field, models.ForeignKey): kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel) elif isinstance(db_field, models.ManyToManyField): kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel) formfield = db_field.formfield(**kwargs) if formfield: # related_modeladmin = admin.site._registry.get(db_field.rel.to) # can_add_related = bool(related_modeladmin and # related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, admin.site, can_add_related=True) for klass in db_field.__class__.mro(): if klass in FORMFIELD_FOR_DBFIELD_DEFAULTS: kwargs = dict(FORMFIELD_FOR_DBFIELD_DEFAULTS[klass], **kwargs) return db_field.formfield(**kwargs) return db_field.formfield(**kwargs)
class ManyToManyRawIdWidgetForm(forms.Form): description = "ManyToManyRawIdWidget" field1 = forms.ModelMultipleChoiceField( help_text='default', queryset=Permission.objects.all(), widget=widgets.ManyToManyRawIdWidget( rel=Group._meta.get_field('permissions').remote_field, admin_site=admin_site))
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(pretty_name(db_field.name), (db_field.name in self.filter_vertical)) return db_field.formfield(**kwargs)
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model, don't show field in admin. if db_field.rel.through is not None: return None if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple( db_field.verbose_name, (db_field.name in self.filter_vertical)) return db_field.formfield(**kwargs)
def formfield_for_manytomany_modified(self, db_field, request, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.remote_field.through._meta.auto_created: # pylint: disable=W0212 return None db = kwargs.get('using') # pylint: disable=C0103 autocomplete_fields = self.get_autocomplete_fields(request) # just added this line... if 'widget' not in kwargs: if db_field.name in autocomplete_fields: kwargs['widget'] = AutocompleteSelectMultiple( db_field.remote_field, self.admin_site, using=db) elif db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget( db_field.remote_field, self.admin_site, using=db) elif db_field.name in [ *self.filter_vertical, *self.filter_horizontal ]: kwargs['widget'] = widgets.FilteredSelectMultiple( db_field.verbose_name, db_field.name in self.filter_vertical) if 'queryset' not in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset form_field = db_field.formfield(**kwargs) if isinstance(form_field.widget, SelectMultiple) and not isinstance( form_field.widget, (CheckboxSelectMultiple, AutocompleteSelectMultiple)): msg = _( 'Hold down "Control", or "Command" on a Mac, to select more than one.' ) help_text = form_field.help_text form_field.help_text = format_lazy('{0} {1}', help_text, msg) if help_text else msg return form_field
def test_m2m_related_model_not_in_admin(self): # M2M relationship with model not registered with admin site. Raw ID # widget should have no magnifying glass link. See #16542 consultor1 = models.Advisor.objects.create(name='Rockstar Techie') c1 = models.Company.objects.create(name='Doodle') c2 = models.Company.objects.create(name='Pear') consultor1.companies.add(c1, c2) rel = models.Advisor._meta.get_field('companies').rel w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) self.assertEqual( conditional_escape(w.render('company_widget1', [c1.pk, c2.pk], attrs={})), '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" />' % {'c1pk': c1.pk, 'c2pk': c2.pk} ) self.assertEqual( conditional_escape(w.render('company_widget2', [c1.pk])), '<input type="text" name="company_widget2" value="%(c1pk)s" />' % {'c1pk': c1.pk} )
def test_render(self): band = models.Band.objects.create(name='Linkin Park') m1 = models.Member.objects.create(name='Chester') m2 = models.Member.objects.create(name='Mike') band.members.add(m1, m2) rel = models.Band._meta.get_field('members').rel w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) self.assertHTMLEqual( w.render('test', [m1.pk, m2.pk], attrs={}), ( '<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" />' '<a href="/admin_widgets/member/" class="related-lookup" id="lookup_id_test" title="Lookup"></a>' ) % dict(m1pk=m1.pk, m2pk=m2.pk) ) self.assertHTMLEqual( w.render('test', [m1.pk]), ( '<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField">' '<a href="/admin_widgets/member/" class="related-lookup" id="lookup_id_test" title="Lookup"></a>' ) % dict(m1pk=m1.pk) )
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ # For DateTimeFields, use a special field and widget. if isinstance(db_field, models.DateTimeField): kwargs['form_class'] = forms.SplitDateTimeField kwargs['widget'] = widgets.AdminSplitDateTime() return db_field.formfield(**kwargs) # For DateFields, add a custom CSS class. if isinstance(db_field, models.DateField): kwargs['widget'] = widgets.AdminDateWidget return db_field.formfield(**kwargs) # For TimeFields, add a custom CSS class. if isinstance(db_field, models.TimeField): kwargs['widget'] = widgets.AdminTimeWidget return db_field.formfield(**kwargs) # For FileFields and ImageFields add a link to the current file. if isinstance(db_field, models.ImageField) or isinstance( db_field, models.FileField): kwargs['widget'] = widgets.AdminFileWidget return db_field.formfield(**kwargs) # For ForeignKey or ManyToManyFields, use a special widget. if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): if isinstance( db_field, models.ForeignKey) and db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel) elif isinstance( db_field, models.ForeignKey) and db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = db_field.blank and _('None') or None else: if isinstance(db_field, models.ManyToManyField): if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget( db_field.rel) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple( db_field.verbose_name, (db_field.name in self.filter_vertical)) # Wrap the widget's render() method with a method that adds # extra HTML to the end of the rendered output. formfield = db_field.formfield(**kwargs) # Don't wrap raw_id fields. Their add function is in the popup window. if not db_field.name in self.raw_id_fields: formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site) return formfield if db_field.choices and db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect( choices=db_field.get_choices(include_blank=db_field.blank, blank_choice=[('', _('None'))]), attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: if db_field.name in self.radio_fields: # If the field is named as a radio_field, use a RadioSelect kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))]) return db_field.formfield(**kwargs) else: # Otherwise, use the default select widget. return db_field.formfield(**kwargs) # For DateTimeFields, use a special field and widget. if isinstance(db_field, models.DateTimeField): kwargs['form_class'] = forms.SplitDateTimeField kwargs['widget'] = widgets.AdminSplitDateTime() return db_field.formfield(**kwargs) # For DateFields, add a custom CSS class. if isinstance(db_field, models.DateField): kwargs['widget'] = widgets.AdminDateWidget return db_field.formfield(**kwargs) # For TimeFields, add a custom CSS class. if isinstance(db_field, models.TimeField): kwargs['widget'] = widgets.AdminTimeWidget return db_field.formfield(**kwargs) # For TextFields, add a custom CSS class. if isinstance(db_field, models.TextField): kwargs['widget'] = widgets.AdminTextareaWidget return db_field.formfield(**kwargs) # For URLFields, add a custom CSS class. if isinstance(db_field, models.URLField): kwargs['widget'] = widgets.AdminURLFieldWidget return db_field.formfield(**kwargs) # For IntegerFields, add a custom CSS class. if isinstance(db_field, models.IntegerField): kwargs['widget'] = widgets.AdminIntegerFieldWidget return db_field.formfield(**kwargs) # For CommaSeparatedIntegerFields, add a custom CSS class. if isinstance(db_field, models.CommaSeparatedIntegerField): kwargs['widget'] = widgets.AdminCommaSeparatedIntegerFieldWidget return db_field.formfield(**kwargs) # For TextInputs, add a custom CSS class. if isinstance(db_field, models.CharField): kwargs['widget'] = widgets.AdminTextInputWidget return db_field.formfield(**kwargs) # For FileFields and ImageFields add a link to the current file. if isinstance(db_field, models.ImageField) or isinstance( db_field, models.FileField): kwargs['widget'] = widgets.AdminFileWidget return db_field.formfield(**kwargs) # For ForeignKey or ManyToManyFields, use a special widget. if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): if isinstance( db_field, models.ForeignKey) and db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel) elif isinstance( db_field, models.ForeignKey) and db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = db_field.blank and _('None') or None else: if isinstance(db_field, models.ManyToManyField): # If it uses an intermediary model, don't show field in admin. if db_field.rel.through is not None: return None elif db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget( db_field.rel) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple( db_field.verbose_name, (db_field.name in self.filter_vertical)) # Wrap the widget's render() method with a method that adds # extra HTML to the end of the rendered output. formfield = db_field.formfield(**kwargs) # Don't wrap raw_id fields. Their add function is in the popup window. if not db_field.name in self.raw_id_fields: # formfield can be None if it came from a OneToOneField with # parent_link=True if formfield is not None: formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site) return formfield # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_manytomany(self, db_field, request, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.remote_field.through._meta.auto_created: return None db = kwargs.get("using") if "widget" not in kwargs: autocomplete_fields = self.get_autocomplete_fields(request) if db_field.name in autocomplete_fields: # BEGIN CUSTOMIZATION kwargs["widget"] = SemanticAutocompleteSelectMultiple( db_field, self.admin_site, using=db, ) # END CUSTOMIZATION elif db_field.name in self.raw_id_fields: kwargs["widget"] = widgets.ManyToManyRawIdWidget( db_field.remote_field, self.admin_site, using=db, ) elif db_field.name in [ *self.filter_vertical, *self.filter_horizontal ]: # TODO kwargs["widget"] = widgets.FilteredSelectMultiple( db_field.verbose_name, db_field.name in self.filter_vertical) if "queryset" not in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs["queryset"] = queryset # BEGIN CUSTOMIZATION if "widget" not in kwargs: kwargs["widget"] = SemanticSelectMultiple() # END CUSTOMIZATION form_field = db_field.formfield(**kwargs) # BEGIN CUSTOMIZATION # if isinstance(form_field.widget, SemanticSelectMultiple) and not isinstance( # form_field.widget, # (SemanticCheckboxSelectMultiple, SemanticAutocompleteSelectMultiple), # ): # msg = _( # "Hold down “Control”, or “Command” on a Mac, to select more than one." # ) # help_text = form_field.help_text # form_field.help_text = ( # format_lazy("{} {}", help_text, msg) if help_text else msg # ) # END CUSTOMIZATION return form_field