Show labels next to ManyToMany raw_id_fields

218 views
Skip to first unread message

João Olavo Baião de Vasconcelos

unread,
Feb 17, 2009, 9:44:19 AM2/17/09
to django...@googlegroups.com
Hello all,

when I save an object that has a ForeignKey raw_id_field, it shows the label (Unicode representation) of the related object next to the field, instead of just the field with object's PK.

I'd like to do the same thing with a ManyToMany raw_id_field (for now, just the objects' PK appear).

I found out that the class responsible for this is "ManyToManyRawIdField", inside file /usr/lib/python2.4/site-packages/django/contrib/admin/widgets.py.

"""
class ForeignKeyRawIdWidget(forms.TextInput):
    [...]
    def render(self, name, value, attrs=None):
        [...]
        if value:
            output.append(self.label_for_value(value))
        return mark_safe(u''.join(output))
              
    def label_for_value(self, value):
        key = self.rel.get_related_field().name
        obj = self.rel.to._default_manager.get(**{key: value})
        return '&nbsp;<strong>Label: %s</strong>' % truncate_words(obj, 14)

class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
    [...]
    def render(self, name, value, attrs=None):
        attrs['class'] = 'vManyToManyRawIdAdminField'
        if value:
            value = ','.join([str(v) for v in value])
        else:
            value = ''
        return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
   
    def label_for_value(self, value):
        return ''
    [...]
"""

I've to return the desired string (a concatenation of the related objects unicode representations) in method label_for_value and append it to the return of method render. But I dunno how to manipulate the object 'value' neither how to append it to the result of render, as it's done in class ForeignKeyRawIdWidget.

How can I do it? Is there another way to accomplish this?

Cheers!
--
João Olavo Baião de Vasconcelos
Bacharel em Ciência da Computação
Analista de Sistemas - Infraestrutura
joaoolavo.wordpress.com

Alex Gaynor

unread,
Feb 17, 2009, 9:47:23 AM2/17/09
to django...@googlegroups.com
I think value is a list in that case, of the primary keys, but the best way to find out is through expirementation, have that method return nothing but a string representation of value and look at that page, or use some other form of logging, once you know what it is you can make it do just what you want.

Alex
--
"I disapprove of what you say, but I will defend to the death your right to say it." --Voltaire
"The people's good is the highest law."--Cicero

João Olavo Baião de Vasconcelos

unread,
Feb 17, 2009, 1:26:23 PM2/17/09
to django...@googlegroups.com
On Tue, Feb 17, 2009 at 11:47 AM, Alex Gaynor <alex....@gmail.com> wrote:
I think value is a list in that case, of the primary keys, but the best way to find out is through expirementation, have that method return nothing but a string representation of value and look at that page, or use some other form of logging, once you know what it is you can make it do just what you want.

Yeap, value is actually a list of large integers. But in none variable come an object that allows me access the related objects'

"""
class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):

    def render(self, name, value, attrs=None):
        attrs['class'] = 'vManyToManyRawIdAdminField'
        if value:
            value = ','.join([str(v) for v in value])
        else:
            value = ''
        output = [super(ManyToManyRawIdWidget, self).render(name, value, attrs)]
        return mark_safe(u''.join(output))
   
    def url_parameters(self):
        return self.base_url_parameters()
   
    def label_for_value(self, value):
        return '&nbsp;<strong>%s</strong>' % self.rel.__dict__

João Olavo Baião de Vasconcelos

unread,
Feb 17, 2009, 1:54:30 PM2/17/09
to django...@googlegroups.com
On Tue, Feb 17, 2009 at 11:47 AM, Alex Gaynor <alex....@gmail.com> wrote:
I think value is a list in that case, of the primary keys, but the best way to find out is through expirementation, have that method return nothing but a string representation of value and look at that page, or use some other form of logging, once you know what it is you can make it do just what you want.

Yeap, value is actually a list of large integers. But in none variable come an object that allows me access the related objects.
In a ForeignKeyRawIdWidget, there's the object self.rel (of type django.db.models.fields.related.manytoonerel), which has the method get_related_field() that helps to bring the related object unicode representation.
But in a ManyToManyRawIdWidget, the object self.rel's type is a
django.db.models.fields.related.manytomanyrel, which doesn't have such method! Check the result of the command 'dir(self.rel)':
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__str__', '__weakref__', 'limit_choices_to', 'multiple', 'related_name', 'symmetrical', 'through', 'to']
And the result of the command 'self.rel.__dict__':
{'limit_choices_to': {}, 'related_name': None, 'multiple': True, 'to': <class PROJECT_NAME.APP_NAME.models.RELATED_MODEL_NAME="">, 'through': None, 'symmetrical': True}</class>
It's a bit weird this <class> tag...

Is there a way out?

Thanks!!

Alex Gaynor

unread,
Feb 17, 2009, 3:15:20 PM2/17/09
to django...@googlegroups.com
Sure, what you're doing will be similar to the way it works for a foreign key, but you're dealing with multiple values, so it'll be something like this:

http://dpaste.com/121833/

You'll need to test this out to make sure it works, but it should :).

João Olavo Baião de Vasconcelos

unread,
Feb 17, 2009, 4:50:23 PM2/17/09
to django...@googlegroups.com
On Tue, Feb 17, 2009 at 5:15 PM, Alex Gaynor <alex....@gmail.com> wrote:
Sure, what you're doing will be similar to the way it works for a foreign key, but you're dealing with multiple values, so it'll be something like this:
http://dpaste.com/121833/
You'll need to test this out to make sure it works, but it should :).

Great, Alex!! =D
It was almost correct! It was missing just 1 line:
"""
def label_for_value(self, value):
        value = [int(v) for v in value.split(',')]
        objs = self.rel.to._default_manager.filter(pk__in=value)
        return '&nbsp;<strong>%s</strong>' % ',&nbsp;'.join(truncate_words(obj, 14) for obj in objs)
"""

Now i think it's perfect!

Does it worth a new ticket? ;D

Alex Gaynor

unread,
Feb 17, 2009, 4:52:25 PM2/17/09
to django...@googlegroups.com
Feel free to file one, the worst thing that could happen is it will get closed :) .

Tim Graham

unread,
Mar 3, 2016, 1:29:46 PM3/3/16
to Django users, alex....@gmail.com
Reply all
Reply to author
Forward
0 new messages