mirror of
https://github.com/django/django.git
synced 2025-07-05 18:29:11 +00:00
newforms-admin: Backwards-incompatible change: Refactored raw_id_admin. It is no longer a valid attribute for fields. Instead, specify 'raw_id_fields', a list of field names, in the 'class Admin'. Also removed raw_id functionality for ManyToManyFields, as it was hackish.
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4430 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
12ad69dbaa
commit
39e63513a8
@ -1,4 +1,4 @@
|
|||||||
// Handles related-objects functionality: lookup link for raw_id_admin=True
|
// Handles related-objects functionality: lookup link for raw_id_fields
|
||||||
// and Add Another links.
|
// and Add Another links.
|
||||||
|
|
||||||
function showRelatedObjectLookupPopup(triggeringLink) {
|
function showRelatedObjectLookupPopup(triggeringLink) {
|
||||||
|
@ -108,6 +108,7 @@ class ModelAdmin(object):
|
|||||||
ordering = None
|
ordering = None
|
||||||
js = None
|
js = None
|
||||||
fields = None
|
fields = None
|
||||||
|
raw_id_fields = ()
|
||||||
|
|
||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
self.model = model
|
self.model = model
|
||||||
@ -224,12 +225,16 @@ class ModelAdmin(object):
|
|||||||
return db_field.formfield(**kwargs)
|
return db_field.formfield(**kwargs)
|
||||||
|
|
||||||
# For ForeignKey or ManyToManyFields, use a special widget.
|
# For ForeignKey or ManyToManyFields, use a special widget.
|
||||||
if db_field.rel and isinstance(db_field.rel, (models.ManyToOneRel, models.ManyToManyRel)):
|
if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
|
||||||
# Wrap the widget's render() method with a method that adds
|
if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
|
||||||
# extra HTML to the end of the rendered output.
|
kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
|
||||||
formfield = db_field.formfield(**kwargs)
|
return db_field.formfield(**kwargs)
|
||||||
formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel)
|
else:
|
||||||
return formfield
|
# 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)
|
||||||
|
formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel)
|
||||||
|
return formfield
|
||||||
|
|
||||||
# For any other type of field, just call its formfield() method.
|
# For any other type of field, just call its formfield() method.
|
||||||
return db_field.formfield(**kwargs)
|
return db_field.formfield(**kwargs)
|
||||||
|
@ -3,6 +3,8 @@ Form Widget classes specific to the Django admin site.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django import newforms as forms
|
from django import newforms as forms
|
||||||
|
from django.newforms.util import smart_unicode
|
||||||
|
from django.utils.text import capfirst
|
||||||
|
|
||||||
class FilteredSelectMultiple(forms.SelectMultiple):
|
class FilteredSelectMultiple(forms.SelectMultiple):
|
||||||
"""
|
"""
|
||||||
@ -41,6 +43,33 @@ class AdminSplitDateTime(forms.SplitDateTimeWidget):
|
|||||||
return u'<p class="datetime">%s %s<br />%s %s</p>' % \
|
return u'<p class="datetime">%s %s<br />%s %s</p>' % \
|
||||||
(_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1])
|
(_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1])
|
||||||
|
|
||||||
|
class ForeignKeyRawIdWidget(forms.TextInput):
|
||||||
|
"""
|
||||||
|
A Widget for displaying ForeignKeys in the "raw_id" interface rather than
|
||||||
|
in a <select> box.
|
||||||
|
"""
|
||||||
|
def __init__(self, rel, attrs=None):
|
||||||
|
self.rel = rel
|
||||||
|
super(ForeignKeyRawIdWidget, self).__init__(attrs)
|
||||||
|
|
||||||
|
def render(self, name, value, attrs=None):
|
||||||
|
from django.conf import settings
|
||||||
|
related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower())
|
||||||
|
if self.rel.limit_choices_to:
|
||||||
|
url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in self.rel.limit_choices_to.items()])
|
||||||
|
else:
|
||||||
|
url = ''
|
||||||
|
attrs['class'] = 'vRawIdAdminField' # The JavaScript looks for this hook.
|
||||||
|
output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)]
|
||||||
|
# TODO: "id_" is hard-coded here. This should instead use the correct
|
||||||
|
# API to determine the ID dynamically.
|
||||||
|
output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
|
||||||
|
(related_url, url, name))
|
||||||
|
output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a>' % settings.ADMIN_MEDIA_PREFIX)
|
||||||
|
return u''.join(output)
|
||||||
|
#if self.change: # TODO
|
||||||
|
#output.append(' <strong>TODO</strong>')
|
||||||
|
|
||||||
class RelatedFieldWidgetWrapper(object):
|
class RelatedFieldWidgetWrapper(object):
|
||||||
"""
|
"""
|
||||||
This class is a wrapper whose __call__() method mimics the interface of a
|
This class is a wrapper whose __call__() method mimics the interface of a
|
||||||
@ -54,19 +83,7 @@ class RelatedFieldWidgetWrapper(object):
|
|||||||
rel_to = self.rel.to
|
rel_to = self.rel.to
|
||||||
related_url = '../../../%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower())
|
related_url = '../../../%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower())
|
||||||
output = [self.render_func(name, value, *args, **kwargs)]
|
output = [self.render_func(name, value, *args, **kwargs)]
|
||||||
if self.rel.raw_id_admin:
|
if rel_to._meta.admin: # If the related object has an admin interface:
|
||||||
if self.rel.limit_choices_to:
|
|
||||||
url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in self.rel.limit_choices_to.items()])
|
|
||||||
else:
|
|
||||||
url = ''
|
|
||||||
# TODO: "id_" is hard-coded here. This should instead use the correct
|
|
||||||
# API to determine the ID dynamically.
|
|
||||||
output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
|
|
||||||
(related_url, url, name))
|
|
||||||
output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a>' % settings.ADMIN_MEDIA_PREFIX)
|
|
||||||
#if self.change: # TODO
|
|
||||||
#output.append(' <strong>TODO</strong>')
|
|
||||||
elif rel_to._meta.admin: # If the related object has an admin interface:
|
|
||||||
# TODO: "id_" is hard-coded here. This should instead use the correct
|
# TODO: "id_" is hard-coded here. This should instead use the correct
|
||||||
# API to determine the ID dynamically.
|
# API to determine the ID dynamically.
|
||||||
output.append(u'<a href="%sadd/" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
|
output.append(u'<a href="%sadd/" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
|
||||||
|
@ -62,7 +62,7 @@ class CommentManager(models.Manager):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
class Comment(models.Model):
|
class Comment(models.Model):
|
||||||
user = models.ForeignKey(User, raw_id_admin=True)
|
user = models.ForeignKey(User)
|
||||||
content_type = models.ForeignKey(ContentType)
|
content_type = models.ForeignKey(ContentType)
|
||||||
object_id = models.IntegerField(_('object ID'))
|
object_id = models.IntegerField(_('object ID'))
|
||||||
headline = models.CharField(_('headline'), maxlength=255, blank=True)
|
headline = models.CharField(_('headline'), maxlength=255, blank=True)
|
||||||
@ -101,6 +101,7 @@ class Comment(models.Model):
|
|||||||
list_filter = ('submit_date',)
|
list_filter = ('submit_date',)
|
||||||
date_hierarchy = 'submit_date'
|
date_hierarchy = 'submit_date'
|
||||||
search_fields = ('comment', 'user__username')
|
search_fields = ('comment', 'user__username')
|
||||||
|
raw_id_fields = ('user',)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s: %s..." % (self.user.username, self.comment[:100])
|
return "%s: %s..." % (self.user.username, self.comment[:100])
|
||||||
|
@ -16,18 +16,18 @@ class GenericForeignKey(object):
|
|||||||
Provides a generic relation to any object through content-type/object-id
|
Provides a generic relation to any object through content-type/object-id
|
||||||
fields.
|
fields.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, ct_field="content_type", fk_field="object_id"):
|
def __init__(self, ct_field="content_type", fk_field="object_id"):
|
||||||
self.ct_field = ct_field
|
self.ct_field = ct_field
|
||||||
self.fk_field = fk_field
|
self.fk_field = fk_field
|
||||||
|
|
||||||
def contribute_to_class(self, cls, name):
|
def contribute_to_class(self, cls, name):
|
||||||
# Make sure the fields exist (these raise FieldDoesNotExist,
|
# Make sure the fields exist (these raise FieldDoesNotExist,
|
||||||
# which is a fine error to raise here)
|
# which is a fine error to raise here)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.model = cls
|
self.model = cls
|
||||||
self.cache_attr = "_%s_cache" % name
|
self.cache_attr = "_%s_cache" % name
|
||||||
|
|
||||||
# For some reason I don't totally understand, using weakrefs here doesn't work.
|
# For some reason I don't totally understand, using weakrefs here doesn't work.
|
||||||
dispatcher.connect(self.instance_pre_init, signal=signals.pre_init, sender=cls, weak=False)
|
dispatcher.connect(self.instance_pre_init, signal=signals.pre_init, sender=cls, weak=False)
|
||||||
|
|
||||||
@ -35,18 +35,18 @@ class GenericForeignKey(object):
|
|||||||
setattr(cls, name, self)
|
setattr(cls, name, self)
|
||||||
|
|
||||||
def instance_pre_init(self, signal, sender, args, kwargs):
|
def instance_pre_init(self, signal, sender, args, kwargs):
|
||||||
# Handle initalizing an object with the generic FK instaed of
|
# Handle initalizing an object with the generic FK instaed of
|
||||||
# content-type/object-id fields.
|
# content-type/object-id fields.
|
||||||
if kwargs.has_key(self.name):
|
if kwargs.has_key(self.name):
|
||||||
value = kwargs.pop(self.name)
|
value = kwargs.pop(self.name)
|
||||||
kwargs[self.ct_field] = self.get_content_type(value)
|
kwargs[self.ct_field] = self.get_content_type(value)
|
||||||
kwargs[self.fk_field] = value._get_pk_val()
|
kwargs[self.fk_field] = value._get_pk_val()
|
||||||
|
|
||||||
def get_content_type(self, obj):
|
def get_content_type(self, obj):
|
||||||
# Convenience function using get_model avoids a circular import when using this model
|
# Convenience function using get_model avoids a circular import when using this model
|
||||||
ContentType = get_model("contenttypes", "contenttype")
|
ContentType = get_model("contenttypes", "contenttype")
|
||||||
return ContentType.objects.get_for_model(obj)
|
return ContentType.objects.get_for_model(obj)
|
||||||
|
|
||||||
def __get__(self, instance, instance_type=None):
|
def __get__(self, instance, instance_type=None):
|
||||||
if instance is None:
|
if instance is None:
|
||||||
raise AttributeError, "%s must be accessed via instance" % self.name
|
raise AttributeError, "%s must be accessed via instance" % self.name
|
||||||
@ -77,21 +77,21 @@ class GenericForeignKey(object):
|
|||||||
setattr(instance, self.ct_field, ct)
|
setattr(instance, self.ct_field, ct)
|
||||||
setattr(instance, self.fk_field, fk)
|
setattr(instance, self.fk_field, fk)
|
||||||
setattr(instance, self.cache_attr, value)
|
setattr(instance, self.cache_attr, value)
|
||||||
|
|
||||||
class GenericRelation(RelatedField, Field):
|
class GenericRelation(RelatedField, Field):
|
||||||
"""Provides an accessor to generic related objects (i.e. comments)"""
|
"""Provides an accessor to generic related objects (i.e. comments)"""
|
||||||
|
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||||
kwargs['rel'] = GenericRel(to,
|
kwargs['rel'] = GenericRel(to,
|
||||||
related_name=kwargs.pop('related_name', None),
|
related_name=kwargs.pop('related_name', None),
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
symmetrical=kwargs.pop('symmetrical', True))
|
symmetrical=kwargs.pop('symmetrical', True))
|
||||||
|
|
||||||
# Override content-type/object-id field names on the related class
|
# Override content-type/object-id field names on the related class
|
||||||
self.object_id_field_name = kwargs.pop("object_id_field", "object_id")
|
self.object_id_field_name = kwargs.pop("object_id_field", "object_id")
|
||||||
self.content_type_field_name = kwargs.pop("content_type_field", "content_type")
|
self.content_type_field_name = kwargs.pop("content_type_field", "content_type")
|
||||||
|
|
||||||
kwargs['blank'] = True
|
kwargs['blank'] = True
|
||||||
kwargs['editable'] = False
|
kwargs['editable'] = False
|
||||||
Field.__init__(self, **kwargs)
|
Field.__init__(self, **kwargs)
|
||||||
@ -115,7 +115,7 @@ class GenericRelation(RelatedField, Field):
|
|||||||
|
|
||||||
def m2m_column_name(self):
|
def m2m_column_name(self):
|
||||||
return self.object_id_field_name
|
return self.object_id_field_name
|
||||||
|
|
||||||
def m2m_reverse_name(self):
|
def m2m_reverse_name(self):
|
||||||
return self.object_id_field_name
|
return self.object_id_field_name
|
||||||
|
|
||||||
@ -130,13 +130,13 @@ class GenericRelation(RelatedField, Field):
|
|||||||
|
|
||||||
def contribute_to_related_class(self, cls, related):
|
def contribute_to_related_class(self, cls, related):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_attributes_from_rel(self):
|
def set_attributes_from_rel(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "ManyToManyField"
|
return "ManyToManyField"
|
||||||
|
|
||||||
class ReverseGenericRelatedObjectsDescriptor(object):
|
class ReverseGenericRelatedObjectsDescriptor(object):
|
||||||
"""
|
"""
|
||||||
This class provides the functionality that makes the related-object
|
This class provides the functionality that makes the related-object
|
||||||
@ -190,12 +190,12 @@ def create_generic_related_manager(superclass):
|
|||||||
Factory function for a manager that subclasses 'superclass' (which is a
|
Factory function for a manager that subclasses 'superclass' (which is a
|
||||||
Manager) and adds behavior for generic related objects.
|
Manager) and adds behavior for generic related objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class GenericRelatedObjectManager(superclass):
|
class GenericRelatedObjectManager(superclass):
|
||||||
def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
|
def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None,
|
||||||
join_table=None, source_col_name=None, target_col_name=None, content_type=None,
|
join_table=None, source_col_name=None, target_col_name=None, content_type=None,
|
||||||
content_type_field_name=None, object_id_field_name=None):
|
content_type_field_name=None, object_id_field_name=None):
|
||||||
|
|
||||||
super(GenericRelatedObjectManager, self).__init__()
|
super(GenericRelatedObjectManager, self).__init__()
|
||||||
self.core_filters = core_filters or {}
|
self.core_filters = core_filters or {}
|
||||||
self.model = model
|
self.model = model
|
||||||
@ -209,10 +209,10 @@ def create_generic_related_manager(superclass):
|
|||||||
self.content_type_field_name = content_type_field_name
|
self.content_type_field_name = content_type_field_name
|
||||||
self.object_id_field_name = object_id_field_name
|
self.object_id_field_name = object_id_field_name
|
||||||
self.pk_val = self.instance._get_pk_val()
|
self.pk_val = self.instance._get_pk_val()
|
||||||
|
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
query = {
|
query = {
|
||||||
'%s__pk' % self.content_type_field_name : self.content_type.id,
|
'%s__pk' % self.content_type_field_name : self.content_type.id,
|
||||||
'%s__exact' % self.object_id_field_name : self.pk_val,
|
'%s__exact' % self.object_id_field_name : self.pk_val,
|
||||||
}
|
}
|
||||||
return superclass.get_query_set(self).filter(**query)
|
return superclass.get_query_set(self).filter(**query)
|
||||||
@ -252,8 +252,5 @@ class GenericRel(ManyToManyRel):
|
|||||||
self.filter_interface = None
|
self.filter_interface = None
|
||||||
self.limit_choices_to = limit_choices_to or {}
|
self.limit_choices_to = limit_choices_to or {}
|
||||||
self.edit_inline = False
|
self.edit_inline = False
|
||||||
self.raw_id_admin = False
|
|
||||||
self.symmetrical = symmetrical
|
self.symmetrical = symmetrical
|
||||||
self.multiple = True
|
self.multiple = True
|
||||||
assert not (self.raw_id_admin and self.filter_interface), \
|
|
||||||
"Generic relations may not use both raw_id_admin and filter_interface"
|
|
||||||
|
@ -483,8 +483,7 @@ class ForeignKey(RelatedField, Field):
|
|||||||
edit_inline=kwargs.pop('edit_inline', False),
|
edit_inline=kwargs.pop('edit_inline', False),
|
||||||
related_name=kwargs.pop('related_name', None),
|
related_name=kwargs.pop('related_name', None),
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
lookup_overrides=kwargs.pop('lookup_overrides', None),
|
lookup_overrides=kwargs.pop('lookup_overrides', None))
|
||||||
raw_id_admin=kwargs.pop('raw_id_admin', False))
|
|
||||||
Field.__init__(self, **kwargs)
|
Field.__init__(self, **kwargs)
|
||||||
|
|
||||||
self.db_index = True
|
self.db_index = True
|
||||||
@ -497,27 +496,20 @@ class ForeignKey(RelatedField, Field):
|
|||||||
|
|
||||||
def prepare_field_objs_and_params(self, manipulator, name_prefix):
|
def prepare_field_objs_and_params(self, manipulator, name_prefix):
|
||||||
params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
|
params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
|
||||||
if self.rel.raw_id_admin:
|
if self.radio_admin:
|
||||||
field_objs = self.get_manipulator_field_objs()
|
field_objs = [oldforms.RadioSelectField]
|
||||||
params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator))
|
params['ul_class'] = get_ul_class(self.radio_admin)
|
||||||
else:
|
else:
|
||||||
if self.radio_admin:
|
if self.null:
|
||||||
field_objs = [oldforms.RadioSelectField]
|
field_objs = [oldforms.NullSelectField]
|
||||||
params['ul_class'] = get_ul_class(self.radio_admin)
|
|
||||||
else:
|
else:
|
||||||
if self.null:
|
field_objs = [oldforms.SelectField]
|
||||||
field_objs = [oldforms.NullSelectField]
|
params['choices'] = self.get_choices_default()
|
||||||
else:
|
|
||||||
field_objs = [oldforms.SelectField]
|
|
||||||
params['choices'] = self.get_choices_default()
|
|
||||||
return field_objs, params
|
return field_objs, params
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
rel_field = self.rel.get_related_field()
|
rel_field = self.rel.get_related_field()
|
||||||
if self.rel.raw_id_admin and not isinstance(rel_field, AutoField):
|
return [oldforms.IntegerField]
|
||||||
return rel_field.get_manipulator_field_objs()
|
|
||||||
else:
|
|
||||||
return [oldforms.IntegerField]
|
|
||||||
|
|
||||||
def get_db_prep_save(self, value):
|
def get_db_prep_save(self, value):
|
||||||
if value == '' or value == None:
|
if value == '' or value == None:
|
||||||
@ -533,7 +525,7 @@ class ForeignKey(RelatedField, Field):
|
|||||||
# is *2*, not 1, because SelectFields always have an initial
|
# is *2*, not 1, because SelectFields always have an initial
|
||||||
# "blank" value. Otherwise (radio_admin=True), we check that the
|
# "blank" value. Otherwise (radio_admin=True), we check that the
|
||||||
# length is 1.
|
# length is 1.
|
||||||
if not self.blank and (not self.rel.raw_id_admin or self.choices):
|
if not self.blank and self.choices:
|
||||||
choice_list = self.get_choices_default()
|
choice_list = self.get_choices_default()
|
||||||
if self.radio_admin and len(choice_list) == 1:
|
if self.radio_admin and len(choice_list) == 1:
|
||||||
return {self.attname: choice_list[0][0]}
|
return {self.attname: choice_list[0][0]}
|
||||||
@ -573,8 +565,7 @@ class OneToOneField(RelatedField, IntegerField):
|
|||||||
edit_inline=kwargs.pop('edit_inline', False),
|
edit_inline=kwargs.pop('edit_inline', False),
|
||||||
related_name=kwargs.pop('related_name', None),
|
related_name=kwargs.pop('related_name', None),
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
lookup_overrides=kwargs.pop('lookup_overrides', None),
|
lookup_overrides=kwargs.pop('lookup_overrides', None))
|
||||||
raw_id_admin=kwargs.pop('raw_id_admin', False))
|
|
||||||
kwargs['primary_key'] = True
|
kwargs['primary_key'] = True
|
||||||
IntegerField.__init__(self, **kwargs)
|
IntegerField.__init__(self, **kwargs)
|
||||||
|
|
||||||
@ -590,19 +581,15 @@ class OneToOneField(RelatedField, IntegerField):
|
|||||||
# ManyToManyField. This works for now.
|
# ManyToManyField. This works for now.
|
||||||
def prepare_field_objs_and_params(self, manipulator, name_prefix):
|
def prepare_field_objs_and_params(self, manipulator, name_prefix):
|
||||||
params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
|
params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}
|
||||||
if self.rel.raw_id_admin:
|
if self.radio_admin:
|
||||||
field_objs = self.get_manipulator_field_objs()
|
field_objs = [oldforms.RadioSelectField]
|
||||||
params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator))
|
params['ul_class'] = get_ul_class(self.radio_admin)
|
||||||
else:
|
else:
|
||||||
if self.radio_admin:
|
if self.null:
|
||||||
field_objs = [oldforms.RadioSelectField]
|
field_objs = [oldforms.NullSelectField]
|
||||||
params['ul_class'] = get_ul_class(self.radio_admin)
|
|
||||||
else:
|
else:
|
||||||
if self.null:
|
field_objs = [oldforms.SelectField]
|
||||||
field_objs = [oldforms.NullSelectField]
|
params['choices'] = self.get_choices_default()
|
||||||
else:
|
|
||||||
field_objs = [oldforms.SelectField]
|
|
||||||
params['choices'] = self.get_choices_default()
|
|
||||||
return field_objs, params
|
return field_objs, params
|
||||||
|
|
||||||
def contribute_to_class(self, cls, name):
|
def contribute_to_class(self, cls, name):
|
||||||
@ -627,24 +614,15 @@ class ManyToManyField(RelatedField, Field):
|
|||||||
related_name=kwargs.pop('related_name', None),
|
related_name=kwargs.pop('related_name', None),
|
||||||
filter_interface=kwargs.pop('filter_interface', None),
|
filter_interface=kwargs.pop('filter_interface', None),
|
||||||
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
limit_choices_to=kwargs.pop('limit_choices_to', None),
|
||||||
raw_id_admin=kwargs.pop('raw_id_admin', False),
|
|
||||||
symmetrical=kwargs.pop('symmetrical', True))
|
symmetrical=kwargs.pop('symmetrical', True))
|
||||||
if kwargs["rel"].raw_id_admin:
|
|
||||||
kwargs.setdefault("validator_list", []).append(self.isValidIDList)
|
|
||||||
Field.__init__(self, **kwargs)
|
Field.__init__(self, **kwargs)
|
||||||
|
|
||||||
if self.rel.raw_id_admin:
|
msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
|
||||||
msg = gettext_lazy('Separate multiple IDs with commas.')
|
|
||||||
else:
|
|
||||||
msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
|
|
||||||
self.help_text = string_concat(self.help_text, ' ', msg)
|
self.help_text = string_concat(self.help_text, ' ', msg)
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
if self.rel.raw_id_admin:
|
choices = self.get_choices_default()
|
||||||
return [oldforms.RawIdAdminField]
|
return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]
|
||||||
else:
|
|
||||||
choices = self.get_choices_default()
|
|
||||||
return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]
|
|
||||||
|
|
||||||
def get_choices_default(self):
|
def get_choices_default(self):
|
||||||
return Field.get_choices(self, include_blank=False)
|
return Field.get_choices(self, include_blank=False)
|
||||||
@ -690,14 +668,11 @@ class ManyToManyField(RelatedField, Field):
|
|||||||
new_data = {}
|
new_data = {}
|
||||||
if obj:
|
if obj:
|
||||||
instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()]
|
instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()]
|
||||||
if self.rel.raw_id_admin:
|
new_data[self.name] = instance_ids
|
||||||
new_data[self.name] = ",".join([str(id) for id in instance_ids])
|
|
||||||
else:
|
|
||||||
new_data[self.name] = instance_ids
|
|
||||||
else:
|
else:
|
||||||
# In required many-to-many fields with only one available choice,
|
# In required many-to-many fields with only one available choice,
|
||||||
# select that one available choice.
|
# select that one available choice.
|
||||||
if not self.blank and not self.rel.edit_inline and not self.rel.raw_id_admin:
|
if not self.blank and not self.rel.edit_inline:
|
||||||
choices_list = self.get_choices_default()
|
choices_list = self.get_choices_default()
|
||||||
if len(choices_list) == 1:
|
if len(choices_list) == 1:
|
||||||
new_data[self.name] = [choices_list[0][0]]
|
new_data[self.name] = [choices_list[0][0]]
|
||||||
@ -741,7 +716,7 @@ class ManyToManyField(RelatedField, Field):
|
|||||||
class ManyToOneRel(object):
|
class ManyToOneRel(object):
|
||||||
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
||||||
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
|
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
|
||||||
related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False):
|
related_name=None, limit_choices_to=None, lookup_overrides=None):
|
||||||
try:
|
try:
|
||||||
to._meta
|
to._meta
|
||||||
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT
|
||||||
@ -754,7 +729,6 @@ class ManyToOneRel(object):
|
|||||||
limit_choices_to = {}
|
limit_choices_to = {}
|
||||||
self.limit_choices_to = limit_choices_to
|
self.limit_choices_to = limit_choices_to
|
||||||
self.lookup_overrides = lookup_overrides or {}
|
self.lookup_overrides = lookup_overrides or {}
|
||||||
self.raw_id_admin = raw_id_admin
|
|
||||||
self.multiple = True
|
self.multiple = True
|
||||||
|
|
||||||
def get_related_field(self):
|
def get_related_field(self):
|
||||||
@ -763,8 +737,7 @@ class ManyToOneRel(object):
|
|||||||
|
|
||||||
class OneToOneRel(ManyToOneRel):
|
class OneToOneRel(ManyToOneRel):
|
||||||
def __init__(self, to, field_name, num_in_admin=0, edit_inline=False,
|
def __init__(self, to, field_name, num_in_admin=0, edit_inline=False,
|
||||||
related_name=None, limit_choices_to=None, lookup_overrides=None,
|
related_name=None, limit_choices_to=None, lookup_overrides=None):
|
||||||
raw_id_admin=False):
|
|
||||||
self.to, self.field_name = to, field_name
|
self.to, self.field_name = to, field_name
|
||||||
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
|
||||||
self.related_name = related_name
|
self.related_name = related_name
|
||||||
@ -772,12 +745,11 @@ class OneToOneRel(ManyToOneRel):
|
|||||||
limit_choices_to = {}
|
limit_choices_to = {}
|
||||||
self.limit_choices_to = limit_choices_to
|
self.limit_choices_to = limit_choices_to
|
||||||
self.lookup_overrides = lookup_overrides or {}
|
self.lookup_overrides = lookup_overrides or {}
|
||||||
self.raw_id_admin = raw_id_admin
|
|
||||||
self.multiple = False
|
self.multiple = False
|
||||||
|
|
||||||
class ManyToManyRel(object):
|
class ManyToManyRel(object):
|
||||||
def __init__(self, to, num_in_admin=0, related_name=None,
|
def __init__(self, to, num_in_admin=0, related_name=None,
|
||||||
filter_interface=None, limit_choices_to=None, raw_id_admin=False, symmetrical=True):
|
filter_interface=None, limit_choices_to=None, symmetrical=True):
|
||||||
self.to = to
|
self.to = to
|
||||||
self.num_in_admin = num_in_admin
|
self.num_in_admin = num_in_admin
|
||||||
self.related_name = related_name
|
self.related_name = related_name
|
||||||
@ -786,8 +758,5 @@ class ManyToManyRel(object):
|
|||||||
limit_choices_to = {}
|
limit_choices_to = {}
|
||||||
self.limit_choices_to = limit_choices_to
|
self.limit_choices_to = limit_choices_to
|
||||||
self.edit_inline = False
|
self.edit_inline = False
|
||||||
self.raw_id_admin = raw_id_admin
|
|
||||||
self.symmetrical = symmetrical
|
self.symmetrical = symmetrical
|
||||||
self.multiple = True
|
self.multiple = True
|
||||||
|
|
||||||
assert not (self.raw_id_admin and self.filter_interface), "ManyToManyRels may not use both raw_id_admin and filter_interface"
|
|
||||||
|
@ -116,10 +116,7 @@ class AutomaticManipulator(oldforms.Manipulator):
|
|||||||
for f in self.opts.many_to_many:
|
for f in self.opts.many_to_many:
|
||||||
if self.follow.get(f.name, None):
|
if self.follow.get(f.name, None):
|
||||||
if not f.rel.edit_inline:
|
if not f.rel.edit_inline:
|
||||||
if f.rel.raw_id_admin:
|
new_vals = new_data.getlist(f.name)
|
||||||
new_vals = new_data.get(f.name, ())
|
|
||||||
else:
|
|
||||||
new_vals = new_data.getlist(f.name)
|
|
||||||
# First, clear the existing values.
|
# First, clear the existing values.
|
||||||
rel_manager = getattr(new_object, f.name)
|
rel_manager = getattr(new_object, f.name)
|
||||||
rel_manager.clear()
|
rel_manager.clear()
|
||||||
@ -216,8 +213,6 @@ class AutomaticManipulator(oldforms.Manipulator):
|
|||||||
for f in related.opts.many_to_many:
|
for f in related.opts.many_to_many:
|
||||||
if child_follow.get(f.name, None) and not f.rel.edit_inline:
|
if child_follow.get(f.name, None) and not f.rel.edit_inline:
|
||||||
new_value = rel_new_data[f.attname]
|
new_value = rel_new_data[f.attname]
|
||||||
if f.rel.raw_id_admin:
|
|
||||||
new_value = new_value[0]
|
|
||||||
setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value))
|
setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value))
|
||||||
if self.change:
|
if self.change:
|
||||||
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
|
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user