Changeset 4430
- Timestamp:
- 01/25/07 12:05:10 (2 years ago)
- Files:
-
- django/branches/newforms-admin/django/contrib/admin/media/js/admin/RelatedObjectLookups.js (modified) (1 diff)
- django/branches/newforms-admin/django/contrib/admin/options.py (modified) (2 diffs)
- django/branches/newforms-admin/django/contrib/admin/widgets.py (modified) (3 diffs)
- django/branches/newforms-admin/django/contrib/comments/models.py (modified) (2 diffs)
- django/branches/newforms-admin/django/db/models/fields/generic.py (modified) (10 diffs)
- django/branches/newforms-admin/django/db/models/fields/related.py (modified) (12 diffs)
- django/branches/newforms-admin/django/db/models/manipulators.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/newforms-admin/django/contrib/admin/media/js/admin/RelatedObjectLookups.js
r3517 r4430 1 // Handles related-objects functionality: lookup link for raw_id_ admin=True1 // Handles related-objects functionality: lookup link for raw_id_fields 2 2 // and Add Another links. 3 3 django/branches/newforms-admin/django/contrib/admin/options.py
r4427 r4430 109 109 js = None 110 110 fields = None 111 raw_id_fields = () 111 112 112 113 def __init__(self, model): … … 225 226 226 227 # For ForeignKey or ManyToManyFields, use a special widget. 227 if db_field.rel and isinstance(db_field.rel, (models.ManyToOneRel, models.ManyToManyRel)): 228 # Wrap the widget's render() method with a method that adds 229 # extra HTML to the end of the rendered output. 230 formfield = db_field.formfield(**kwargs) 231 formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel) 232 return formfield 228 if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): 229 if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields: 230 kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel) 231 return db_field.formfield(**kwargs) 232 else: 233 # Wrap the widget's render() method with a method that adds 234 # extra HTML to the end of the rendered output. 235 formfield = db_field.formfield(**kwargs) 236 formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel) 237 return formfield 233 238 234 239 # For any other type of field, just call its formfield() method. django/branches/newforms-admin/django/contrib/admin/widgets.py
r4416 r4430 4 4 5 5 from django import newforms as forms 6 from django.newforms.util import smart_unicode 7 from django.utils.text import capfirst 6 8 7 9 class FilteredSelectMultiple(forms.SelectMultiple): … … 42 44 (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1]) 43 45 46 class ForeignKeyRawIdWidget(forms.TextInput): 47 """ 48 A Widget for displaying ForeignKeys in the "raw_id" interface rather than 49 in a <select> box. 50 """ 51 def __init__(self, rel, attrs=None): 52 self.rel = rel 53 super(ForeignKeyRawIdWidget, self).__init__(attrs) 54 55 def render(self, name, value, attrs=None): 56 from django.conf import settings 57 related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower()) 58 if self.rel.limit_choices_to: 59 url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in self.rel.limit_choices_to.items()]) 60 else: 61 url = '' 62 attrs['class'] = 'vRawIdAdminField' # The JavaScript looks for this hook. 63 output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] 64 # TODO: "id_" is hard-coded here. This should instead use the correct 65 # API to determine the ID dynamically. 66 output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \ 67 (related_url, url, name)) 68 output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a>' % settings.ADMIN_MEDIA_PREFIX) 69 return u''.join(output) 70 #if self.change: # TODO 71 #output.append(' <strong>TODO</strong>') 72 44 73 class RelatedFieldWidgetWrapper(object): 45 74 """ … … 55 84 related_url = '../../../%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower()) 56 85 output = [self.render_func(name, value, *args, **kwargs)] 57 if self.rel.raw_id_admin: 58 if self.rel.limit_choices_to: 59 url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in self.rel.limit_choices_to.items()]) 60 else: 61 url = '' 62 # TODO: "id_" is hard-coded here. This should instead use the correct 63 # API to determine the ID dynamically. 64 output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \ 65 (related_url, url, name)) 66 output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup"></a>' % settings.ADMIN_MEDIA_PREFIX) 67 #if self.change: # TODO 68 #output.append(' <strong>TODO</strong>') 69 elif rel_to._meta.admin: # If the related object has an admin interface: 86 if rel_to._meta.admin: # If the related object has an admin interface: 70 87 # TODO: "id_" is hard-coded here. This should instead use the correct 71 88 # API to determine the ID dynamically. django/branches/newforms-admin/django/contrib/comments/models.py
r4265 r4430 63 63 64 64 class Comment(models.Model): 65 user = models.ForeignKey(User , raw_id_admin=True)65 user = models.ForeignKey(User) 66 66 content_type = models.ForeignKey(ContentType) 67 67 object_id = models.IntegerField(_('object ID')) … … 102 102 date_hierarchy = 'submit_date' 103 103 search_fields = ('comment', 'user__username') 104 raw_id_fields = ('user',) 104 105 105 106 def __repr__(self): django/branches/newforms-admin/django/db/models/fields/generic.py
r4265 r4430 17 17 fields. 18 18 """ 19 19 20 20 def __init__(self, ct_field="content_type", fk_field="object_id"): 21 21 self.ct_field = ct_field 22 22 self.fk_field = fk_field 23 23 24 24 def contribute_to_class(self, cls, name): 25 # Make sure the fields exist (these raise FieldDoesNotExist, 25 # Make sure the fields exist (these raise FieldDoesNotExist, 26 26 # which is a fine error to raise here) 27 27 self.name = name 28 28 self.model = cls 29 29 self.cache_attr = "_%s_cache" % name 30 30 31 31 # For some reason I don't totally understand, using weakrefs here doesn't work. 32 32 dispatcher.connect(self.instance_pre_init, signal=signals.pre_init, sender=cls, weak=False) … … 36 36 37 37 def instance_pre_init(self, signal, sender, args, kwargs): 38 # Handle initalizing an object with the generic FK instaed of 39 # content-type/object-id fields. 38 # Handle initalizing an object with the generic FK instaed of 39 # content-type/object-id fields. 40 40 if kwargs.has_key(self.name): 41 41 value = kwargs.pop(self.name) 42 42 kwargs[self.ct_field] = self.get_content_type(value) 43 43 kwargs[self.fk_field] = value._get_pk_val() 44 44 45 45 def get_content_type(self, obj): 46 46 # Convenience function using get_model avoids a circular import when using this model 47 47 ContentType = get_model("contenttypes", "contenttype") 48 48 return ContentType.objects.get_for_model(obj) 49 49 50 50 def __get__(self, instance, instance_type=None): 51 51 if instance is None: … … 78 78 setattr(instance, self.fk_field, fk) 79 79 setattr(instance, self.cache_attr, value) 80 80 81 81 class GenericRelation(RelatedField, Field): 82 82 """Provides an accessor to generic related objects (i.e. comments)""" … … 84 84 def __init__(self, to, **kwargs): 85 85 kwargs['verbose_name'] = kwargs.get('verbose_name', None) 86 kwargs['rel'] = GenericRel(to, 86 kwargs['rel'] = GenericRel(to, 87 87 related_name=kwargs.pop('related_name', None), 88 88 limit_choices_to=kwargs.pop('limit_choices_to', None), 89 89 symmetrical=kwargs.pop('symmetrical', True)) 90 90 91 91 # Override content-type/object-id field names on the related class 92 92 self.object_id_field_name = kwargs.pop("object_id_field", "object_id") 93 self.content_type_field_name = kwargs.pop("content_type_field", "content_type") 94 93 self.content_type_field_name = kwargs.pop("content_type_field", "content_type") 94 95 95 kwargs['blank'] = True 96 96 kwargs['editable'] = False … … 116 116 def m2m_column_name(self): 117 117 return self.object_id_field_name 118 118 119 119 def m2m_reverse_name(self): 120 120 return self.object_id_field_name … … 131 131 def contribute_to_related_class(self, cls, related): 132 132 pass 133 133 134 134 def set_attributes_from_rel(self): 135 135 pass … … 137 137 def get_internal_type(self): 138 138 return "ManyToManyField" 139 139 140 140 class ReverseGenericRelatedObjectsDescriptor(object): 141 141 """ … … 191 191 Manager) and adds behavior for generic related objects. 192 192 """ 193 193 194 194 class GenericRelatedObjectManager(superclass): 195 195 def __init__(self, model=None, core_filters=None, instance=None, symmetrical=None, 196 196 join_table=None, source_col_name=None, target_col_name=None, content_type=None, 197 197 content_type_field_name=None, object_id_field_name=None): 198 198 199 199 super(GenericRelatedObjectManager, self).__init__() 200 200 self.core_filters = core_filters or {} … … 210 210 self.object_id_field_name = object_id_field_name 211 211 self.pk_val = self.instance._get_pk_val() 212 212 213 213 def get_query_set(self): 214 214 query = { 215 '%s__pk' % self.content_type_field_name : self.content_type.id, 215 '%s__pk' % self.content_type_field_name : self.content_type.id, 216 216 '%s__exact' % self.object_id_field_name : self.pk_val, 217 217 } … … 253 253 self.limit_choices_to = limit_choices_to or {} 254 254 self.edit_inline = False 255 self.raw_id_admin = False256 255 self.symmetrical = symmetrical 257 256 self.multiple = True 258 assert not (self.raw_id_admin and self.filter_interface), \259 "Generic relations may not use both raw_id_admin and filter_interface"django/branches/newforms-admin/django/db/models/fields/related.py
r4390 r4430 484 484 related_name=kwargs.pop('related_name', None), 485 485 limit_choices_to=kwargs.pop('limit_choices_to', None), 486 lookup_overrides=kwargs.pop('lookup_overrides', None), 487 raw_id_admin=kwargs.pop('raw_id_admin', False)) 486 lookup_overrides=kwargs.pop('lookup_overrides', None)) 488 487 Field.__init__(self, **kwargs) 489 488 … … 498 497 def prepare_field_objs_and_params(self, manipulator, name_prefix): 499 498 params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname} 500 if self.rel.raw_id_admin: 501 field_objs = self.get_manipulator_field_objs() 502 params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator)) 503 else: 504 if self.radio_admin: 505 field_objs = [oldforms.RadioSelectField] 506 params['ul_class'] = get_ul_class(self.radio_admin) 499 if self.radio_admin: 500 field_objs = [oldforms.RadioSelectField] 501 params['ul_class'] = get_ul_class(self.radio_admin) 502 else: 503 if self.null: 504 field_objs = [oldforms.NullSelectField] 507 505 else: 508 if self.null: 509 field_objs = [oldforms.NullSelectField] 510 else: 511 field_objs = [oldforms.SelectField] 512 params['choices'] = self.get_choices_default() 506 field_objs = [oldforms.SelectField] 507 params['choices'] = self.get_choices_default() 513 508 return field_objs, params 514 509 515 510 def get_manipulator_field_objs(self): 516 511 rel_field = self.rel.get_related_field() 517 if self.rel.raw_id_admin and not isinstance(rel_field, AutoField): 518 return rel_field.get_manipulator_field_objs() 519 else: 520 return [oldforms.IntegerField] 512 return [oldforms.IntegerField] 521 513 522 514 def get_db_prep_save(self, value): … … 534 526 # "blank" value. Otherwise (radio_admin=True), we check that the 535 527 # length is 1. 536 if not self.blank and (not self.rel.raw_id_admin or self.choices):528 if not self.blank and self.choices: 537 529 choice_list = self.get_choices_default() 538 530 if self.radio_admin and len(choice_list) == 1: … … 574 566 related_name=kwargs.pop('related_name', None), 575 567 limit_choices_to=kwargs.pop('limit_choices_to', None), 576 lookup_overrides=kwargs.pop('lookup_overrides', None), 577 raw_id_admin=kwargs.pop('raw_id_admin', False)) 568 lookup_overrides=kwargs.pop('lookup_overrides', None)) 578 569 kwargs['primary_key'] = True 579 570 IntegerField.__init__(self, **kwargs) … … 591 582 def prepare_field_objs_and_params(self, manipulator, name_prefix): 592 583 params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname} 593 if self.rel.raw_id_admin: 594 field_objs = self.get_manipulator_field_objs() 595 params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator)) 596 else: 597 if self.radio_admin: 598 field_objs = [oldforms.RadioSelectField] 599 params['ul_class'] = get_ul_class(self.radio_admin) 584 if self.radio_admin: 585 field_objs = [oldforms.RadioSelectField] 586 params['ul_class'] = get_ul_class(self.radio_admin) 587 else: 588 if self.null: 589 field_objs = [oldforms.NullSelectField] 600 590 else: 601 if self.null: 602 field_objs = [oldforms.NullSelectField] 603 else: 604 field_objs = [oldforms.SelectField] 605 params['choices'] = self.get_choices_default() 591 field_objs = [oldforms.SelectField] 592 params['choices'] = self.get_choices_default() 606 593 return field_objs, params 607 594 … … 628 615 filter_interface=kwargs.pop('filter_interface', None), 629 616 limit_choices_to=kwargs.pop('limit_choices_to', None), 630 raw_id_admin=kwargs.pop('raw_id_admin', False),631 617 symmetrical=kwargs.pop('symmetrical', True)) 632 if kwargs["rel"].raw_id_admin:633 kwargs.setdefault("validator_list", []).append(self.isValidIDList)634 618 Field.__init__(self, **kwargs) 635 619 636 if self.rel.raw_id_admin: 637 msg = gettext_lazy('Separate multiple IDs with commas.') 638 else: 639 msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.') 620 msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.') 640 621 self.help_text = string_concat(self.help_text, ' ', msg) 641 622 642 623 def get_manipulator_field_objs(self): 643 if self.rel.raw_id_admin: 644 return [oldforms.RawIdAdminField] 645 else: 646 choices = self.get_choices_default() 647 return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)] 624 choices = self.get_choices_default() 625 return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)] 648 626 649 627 def get_choices_default(self): … … 691 669 if obj: 692 670 instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()] 693 if self.rel.raw_id_admin: 694 new_data[self.name] = ",".join([str(id) for id in instance_ids]) 695 else: 696 new_data[self.name] = instance_ids 671 new_data[self.name] = instance_ids 697 672 else: 698 673 # In required many-to-many fields with only one available choice, 699 674 # select that one available choice. 700 if not self.blank and not self.rel.edit_inline and not self.rel.raw_id_admin:675 if not self.blank and not self.rel.edit_inline: 701 676 choices_list = self.get_choices_default() 702 677 if len(choices_list) == 1: … … 742 717 def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None, 743 718 max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, 744 related_name=None, limit_choices_to=None, lookup_overrides=None , raw_id_admin=False):719 related_name=None, limit_choices_to=None, lookup_overrides=None): 745 720 try: 746 721 to._meta … … 755 730 self.limit_choices_to = limit_choices_to 756 731 self.lookup_overrides = lookup_overrides or {} 757 self.raw_id_admin = raw_id_admin758 732 self.multiple = True 759 733 … … 764 738 class OneToOneRel(ManyToOneRel): 765 739 def __init__(self, to, field_name, num_in_admin=0, edit_inline=False, 766 related_name=None, limit_choices_to=None, lookup_overrides=None, 767 raw_id_admin=False): 740 related_name=None, limit_choices_to=None, lookup_overrides=None): 768 741 self.to, self.field_name = to, field_name 769 742 self.num_in_admin, self.edit_inline = num_in_admin, edit_inline … … 773 746 self.limit_choices_to = limit_choices_to 774 747 self.lookup_overrides = lookup_overrides or {} 775 self.raw_id_admin = raw_id_admin776 748 self.multiple = False 777 749 778 750 class ManyToManyRel(object): 779 751 def __init__(self, to, num_in_admin=0, related_name=None, 780 filter_interface=None, limit_choices_to=None, raw_id_admin=False,symmetrical=True):752 filter_interface=None, limit_choices_to=None, symmetrical=True): 781 753 self.to = to 782 754 self.num_in_admin = num_in_admin … … 787 759 self.limit_choices_to = limit_choices_to 788 760 self.edit_inline = False 789 self.raw_id_admin = raw_id_admin790 761 self.symmetrical = symmetrical 791 762 self.multiple = True 792 793 assert not (self.raw_id_admin and self.filter_interface), "ManyToManyRels may not use both raw_id_admin and filter_interface"django/branches/newforms-admin/django/db/models/manipulators.py
r4265 r4430 117 117 if self.follow.get(f.name, None): 118 118 if not f.rel.edit_inline: 119 if f.rel.raw_id_admin: 120 new_vals = new_data.get(f.name, ()) 121 else: 122 new_vals = new_data.getlist(f.name) 119 new_vals = new_data.getlist(f.name) 123 120 # First, clear the existing values. 124 121 rel_manager = getattr(new_object, f.name) … … 217 214 if child_follow.get(f.name, None) and not f.rel.edit_inline: 218 215 new_value = rel_new_data[f.attname] 219 if f.rel.raw_id_admin:220 new_value = new_value[0]221 216 setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value)) 222 217 if self.change:
