Django

Code

Changeset 8823

Show
Ignore:
Timestamp:
09/01/08 17:43:38 (3 months ago)
Author:
brosner
Message:

Fixed #8648 -- Admin no longer ignores to_field. Thanks for the help Karen Tracey and SmileyChris?.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/contrib/admin/templatetags/admin_list.py

    r8388 r8823  
    223223            # Convert the pk to something that can be used in Javascript. 
    224224            # Problem cases are long ints (23L) and non-ASCII strings. 
    225             result_id = repr(force_unicode(getattr(result, pk)))[1:] 
     225            if cl.to_field: 
     226                attr = str(cl.to_field) 
     227            else: 
     228                attr = pk 
     229            result_id = repr(force_unicode(getattr(result, attr)))[1:] 
    226230            yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ 
    227231                (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag)) 
  • django/trunk/django/contrib/admin/views/main.py

    r8700 r8823  
    2525PAGE_VAR = 'p' 
    2626SEARCH_VAR = 'q' 
     27TO_FIELD_VAR = 't' 
    2728IS_POPUP_VAR = 'pop' 
    2829ERROR_FLAG = 'e' 
     
    5354        self.show_all = ALL_VAR in request.GET 
    5455        self.is_popup = IS_POPUP_VAR in request.GET 
     56        self.to_field = request.GET.get(TO_FIELD_VAR) 
    5557        self.params = dict(request.GET.items()) 
    5658        if PAGE_VAR in self.params: 
    5759            del self.params[PAGE_VAR] 
     60        if TO_FIELD_VAR in self.params: 
     61            del self.params[TO_FIELD_VAR] 
    5862        if ERROR_FLAG in self.params: 
    5963            del self.params[ERROR_FLAG] 
  • django/trunk/django/contrib/admin/widgets.py

    r8764 r8823  
    4242class AdminDateWidget(forms.TextInput): 
    4343    class Media: 
    44         js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",  
     44        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js", 
    4545              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js") 
    46          
     46 
    4747    def __init__(self, attrs={}): 
    4848        super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'}) 
     
    5050class AdminTimeWidget(forms.TextInput): 
    5151    class Media: 
    52         js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",  
     52        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js", 
    5353              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js") 
    5454 
    5555    def __init__(self, attrs={}): 
    5656        super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'}) 
    57      
     57 
    5858class AdminSplitDateTime(forms.SplitDateTimeWidget): 
    5959    """ 
     
    8787    def __init__(self, attrs={}): 
    8888        super(AdminFileWidget, self).__init__(attrs) 
    89          
     89 
    9090    def render(self, name, value, attrs=None): 
    9191        output = [] 
     
    106106 
    107107    def render(self, name, value, attrs=None): 
     108        from django.contrib.admin.views.main import TO_FIELD_VAR 
    108109        related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower()) 
     110        params = {} 
    109111        if self.rel.limit_choices_to: 
    110             url = '?' + '&amp;'.join(['%s=%s' % (k, ','.join(v)) for k, v in self.rel.limit_choices_to.items()]
    111         else: 
    112             url = '' 
     112            params.update(dict([(k, ','.join(v)) for k, v in self.rel.limit_choices_to.items()])
     113        params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) 
     114        url = '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in params.items()]) 
    113115        if not attrs.has_key('class'): 
    114116          attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook. 
     
    122124            output.append(self.label_for_value(value)) 
    123125        return mark_safe(u''.join(output)) 
    124      
     126 
    125127    def label_for_value(self, value): 
    126         return '&nbsp;<strong>%s</strong>' % \ 
    127             truncate_words(self.rel.to.objects.get(pk=value), 14) 
    128              
     128        key = self.rel.get_related_field().name 
     129        obj = self.rel.to.objects.get(**{key: value}) 
     130        return '&nbsp;<strong>%s</strong>' % truncate_words(obj, 14) 
     131 
    129132class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 
    130133    """ 
     
    134137    def __init__(self, rel, attrs=None): 
    135138        super(ManyToManyRawIdWidget, self).__init__(rel, attrs) 
    136      
     139 
    137140    def render(self, name, value, attrs=None): 
    138141        attrs['class'] = 'vManyToManyRawIdAdminField' 
     
    142145            value = '' 
    143146        return super(ManyToManyRawIdWidget, self).render(name, value, attrs) 
    144      
     147 
    145148    def label_for_value(self, value): 
    146149        return '' 
     
    153156            return [value] 
    154157        return None 
    155      
     158 
    156159    def _has_changed(self, initial, data): 
    157160        if initial is None: 
  • django/trunk/django/db/models/fields/related.py

    r8814 r8823  
    692692 
    693693    def formfield(self, **kwargs): 
    694         defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)} 
     694        defaults = { 
     695            'form_class': forms.ModelChoiceField, 
     696            'queryset': self.rel.to._default_manager.complex_filter( 
     697                                                    self.rel.limit_choices_to), 
     698            'to_field_name': self.rel.field_name, 
     699        } 
    695700        defaults.update(kwargs) 
    696701        return super(ForeignKey, self).formfield(**defaults) 
  • django/trunk/django/forms/models.py

    r8822 r8823  
    551551            if self.field.choice_cache is None: 
    552552                self.field.choice_cache = [ 
    553                     (obj.pk, self.field.label_from_instance(obj)) 
    554                     for obj in self.queryset.all() 
     553                    self.choice(obj) for obj in self.queryset.all() 
    555554                ] 
    556555            for choice in self.field.choice_cache: 
     
    558557        else: 
    559558            for obj in self.queryset.all(): 
    560                 yield (obj.pk, self.field.label_from_instance(obj)) 
     559                yield self.choice(obj) 
     560 
     561    def choice(self, obj): 
     562        if self.field.to_field_name: 
     563            key = getattr(obj, self.field.to_field_name) 
     564        else: 
     565            key = obj.pk 
     566        return (key, self.field.label_from_instance(obj)) 
     567 
    561568 
    562569class ModelChoiceField(ChoiceField): 
     
    571578    def __init__(self, queryset, empty_label=u"---------", cache_choices=False, 
    572579                 required=True, widget=None, label=None, initial=None, 
    573                  help_text=None, *args, **kwargs): 
     580                 help_text=None, to_field_name=None, *args, **kwargs): 
    574581        self.empty_label = empty_label 
    575582        self.cache_choices = cache_choices 
     
    581588        self.queryset = queryset 
    582589        self.choice_cache = None 
     590        self.to_field_name = to_field_name 
    583591 
    584592    def _get_queryset(self): 
     
    623631            return None 
    624632        try: 
    625             value = self.queryset.get(pk=value) 
     633            key = self.to_field_name or 'pk' 
     634            value = self.queryset.get(**{key: value}) 
    626635        except self.queryset.model.DoesNotExist: 
    627636            raise ValidationError(self.error_messages['invalid_choice']) 
  • django/trunk/tests/modeltests/model_forms/models.py

    r8819 r8823  
    7979    writer = models.OneToOneField(Writer, primary_key=True) 
    8080    age = models.PositiveIntegerField() 
    81      
     81 
    8282    def __unicode__(self): 
    8383        return "%s is %s" % (self.writer, self.age) 
     
    138138    status = models.CharField(max_length=2, choices=ARTICLE_STATUS_CHAR, blank=True, null=True) 
    139139 
    140  
     140class Inventory(models.Model): 
     141   barcode = models.PositiveIntegerField(unique=True) 
     142   parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True) 
     143   name = models.CharField(blank=False, max_length=20) 
     144 
     145   def __unicode__(self): 
     146      return self.name 
     147       
    141148__test__ = {'API_TESTS': """ 
    142149>>> from django import forms 
     
    11361143... 
    11371144ValidationError: [u'Enter only digits separated by commas.'] 
    1138 >>> f.clean(',,,,')  
     1145>>> f.clean(',,,,') 
    11391146u',,,,' 
    11401147>>> f.clean('1.2') 
     
    12051212ValidationError: [u'Select a valid choice. z is not one of the available choices.'] 
    12061213 
     1214# Foreign keys which use to_field ############################################# 
     1215 
     1216>>> apple = Inventory.objects.create(barcode=86, name='Apple') 
     1217>>> pear = Inventory.objects.create(barcode=22, name='Pear') 
     1218>>> core = Inventory.objects.create(barcode=87, name='Core', parent=apple) 
     1219 
     1220>>> field = ModelChoiceField(Inventory.objects.all(), to_field_name='barcode') 
     1221>>> for choice in field.choices: 
     1222...     print choice 
     1223(u'', u'---------') 
     1224(86, u'Apple') 
     1225(22, u'Pear') 
     1226(87, u'Core') 
     1227 
     1228>>> class InventoryForm(ModelForm): 
     1229...     class Meta: 
     1230...         model = Inventory 
     1231>>> form = InventoryForm(instance=core) 
     1232>>> print form['parent'] 
     1233<select name="parent" id="id_parent"> 
     1234<option value="">---------</option> 
     1235<option value="86" selected="selected">Apple</option> 
     1236<option value="22">Pear</option> 
     1237<option value="87">Core</option> 
     1238</select> 
     1239 
     1240>>> data = model_to_dict(core) 
     1241>>> data['parent'] = '22' 
     1242>>> form = InventoryForm(data=data, instance=core) 
     1243>>> core = form.save() 
     1244>>> core.parent 
     1245<Inventory: Pear> 
    12071246"""} 
  • django/trunk/tests/regressiontests/admin_widgets/models.py

    r8277 r8823  
    66class Member(models.Model): 
    77    name = models.CharField(max_length=100) 
    8      
     8 
    99    def __unicode__(self): 
    1010        return self.name 
     
    1313    name = models.CharField(max_length=100) 
    1414    members = models.ManyToManyField(Member) 
    15      
     15 
    1616    def __unicode__(self): 
    1717        return self.name 
     
    2121    name = models.CharField(max_length=100) 
    2222    cover_art = models.FileField(upload_to='albums') 
    23      
     23 
    2424    def __unicode__(self): 
    2525        return self.name 
     26 
     27class Inventory(models.Model): 
     28   barcode = models.PositiveIntegerField(unique=True) 
     29   parent = models.ForeignKey('self', to_field='barcode', blank=True, null=True) 
     30   name = models.CharField(blank=False, max_length=20) 
     31 
     32   def __unicode__(self): 
     33      return self.name 
    2634 
    2735__test__ = {'WIDGETS_TESTS': """ 
     
    8593True 
    8694 
     95# Check that ForeignKeyRawIdWidget works with fields which aren't related to 
     96# the model's primary key. 
     97>>> apple = Inventory.objects.create(barcode=86, name='Apple') 
     98>>> pear = Inventory.objects.create(barcode=22, name='Pear') 
     99>>> core = Inventory.objects.create(barcode=87, name='Core', parent=apple) 
     100>>> rel = Inventory._meta.get_field('parent').rel 
     101>>> w = ForeignKeyRawIdWidget(rel) 
     102>>> print w.render('test', core.parent_id, attrs={}) 
     103<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="../../../admin_widgets/inventory/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="/admin_media/img/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Apple</strong> 
    87104""" % { 
    88105    'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX,