Strange value_from_object() return value (2L returned instead of unicode string)

138 views
Skip to first unread message

Jeff Blaine

unread,
Jun 20, 2011, 8:53:23 PM6/20/11
to django...@googlegroups.com
I can't seem to figure out what is causing this:  According to the following 2 models
and the 'python manage.py shell' session shown after them, I am getting 2L as a
return value from a certain call when I would expect u'redhat 5.6' or similar.

If anyone has any ideas, please let me know.  I am very stumped at this point.

I include (and query) "Status" just to show normal/expected output from a very
similar query for a field value.

class Status(models.Model):
    name            = models.CharField('Status',
                                       max_length=30,
                                       primary_key=True)

    def __unicode__(self):
        return self.name

class Distro(models.Model):
    # don't make name the primary key, because then it has to be
    # unique and we want to allow multiple items with the same
    # 'name', like ubuntu 10.10 and ubuntu 11.04
    name            = models.CharField('Distro Brand',
                                       help_text='redhat, ubuntu, etc',
                                       max_length=30)

    version         = models.CharField('Distro Version',
                                       help_text='Not kernel version',
                                       max_length=10)

    def __unicode__(self):
        return u"%s %s" % (self.name, self.version)

=============================================================

>>> from hostdb.models import Device, Interface
>>> hostname = 'beijing.mitre.org'
>>> dev = Interface.objects.get(fqdn=hostname).device
>>> dev.status
<Status: Online>
>>> f = dev._meta.get_field('status')
>>> f.value_from_object(dev)
u'Online'
>>> # Super -- this is exactly what I would expect.  Now trouble
>>> dev.distro
<Distro: redhat 5.6>
>>> print dev.distro
redhat 5.6
>>> f = dev._meta.get_field('distro')
>>> f.value_from_object(dev)
2L
>>> # what the hell?

Jeff Blaine

unread,
Jun 20, 2011, 8:54:20 PM6/20/11
to django...@googlegroups.com
PS: Django 1.3

Daniel Roseman

unread,
Jun 21, 2011, 4:57:55 AM6/21/11
to django...@googlegroups.com
On Tuesday, 21 June 2011 01:53:23 UTC+1, Jeff Blaine wrote:
I can't seem to figure out what is causing this:  According to the following 2 models
and the 'python manage.py shell' session shown after them, I am getting 2L as a
return value from a certain call when I would expect u'redhat 5.6' or similar.

What does the Device model look like? 
-- 
DR.

Malcolm Box

unread,
Jun 21, 2011, 7:08:15 AM6/21/11
to django...@googlegroups.com
On 21 Jun 2011, at 01:53, Jeff Blaine wrote:

> >>> from hostdb.models import Device, Interface
> >>> hostname = 'beijing.mitre.org'
> >>> dev = Interface.objects.get(fqdn=hostname).device
> >>> dev.status
> <Status: Online>
> >>> f = dev._meta.get_field('status')
> >>> f.value_from_object(dev)
> u'Online'
> >>> # Super -- this is exactly what I would expect. Now trouble
> >>> dev.distro
> <Distro: redhat 5.6>
> >>> print dev.distro
> redhat 5.6
> >>> f = dev._meta.get_field('distro')
> >>> f.value_from_object(dev)
> 2L
> >>> # what the hell?

Psychic debugging since you didn't post the Device model:

dev.distro is a foreign key to the Distro model. When you ask for the value via the get_field, you actually end up with the PK of the Distro rather than the distro instance.

Malcolm

Jeff Blaine

unread,
Jun 21, 2011, 8:34:35 AM6/21/11
to django...@googlegroups.com
Yes, seems that way, Malcom, but *why*

class Device(models.Model):
# ...
    status          = models.ForeignKey(Status,
                                        blank=True,
                                        null=True,
                                        verbose_name="Status",
                                        on_delete=models.DO_NOTHING)

    distro          = models.ForeignKey(Distro,
                                        blank=True,
                                        null=True,
                                        verbose_name="Distro",
                                        on_delete=models.DO_NOTHING)
# ...

Jeff Blaine

unread,
Jun 21, 2011, 10:47:32 AM6/21/11
to django...@googlegroups.com
Okay, here's the problem.

>>> f = dev._meta.get_field('distro')
>>> f.value_from_object(dev)
2L

value_from_object is defined as:

========================================================
    def value_from_object(self, obj):
        "Returns the value of this field in the given model instance."
        return getattr(obj, self.attname)
========================================================

>>> f.attname
'distro_id'
>>>

As others guessed, value_from_object() is returning the pk ID in this
case.

Model "Distro" is the only model of mine showing this behavior, as it is the
only foreign key "target" model I have defined without named primary key.

From what I can tell, value_from_object() is actually mis-named, and should
be named pkvalue_from_object(), no?  Or is there some case where self.attname
for a field is *not* set to the primary key attribute name?

Any ideas?  I really want (concept) "myfield.unicode_representation_of_object(myobject)"

Tom Evans

unread,
Jun 21, 2011, 11:00:37 AM6/21/11
to django...@googlegroups.com
On Tue, Jun 21, 2011 at 3:47 PM, Jeff Blaine <cjbl...@gmail.com> wrote:
> Any ideas?  I really want (concept)
> "myfield.unicode_representation_of_object(myobject)"
>

unicode(myobject.myfield) // unicode(getattr(myobject, 'myfield'))

Am I being dense?

Tom

Malcolm Box

unread,
Jun 21, 2011, 11:17:10 AM6/21/11
to django...@googlegroups.com
On 21 June 2011 15:47, Jeff Blaine <cjbl...@gmail.com> wrote:
Okay, here's the problem.

>>> f = dev._meta.get_field('distro')
>>> f.value_from_object(dev)
2L
>>> f.attname
'distro_id'
>>>

As others guessed, value_from_object() is returning the pk ID in this
case.


Model "Distro" is the only model of mine showing this behavior, as it is the
only foreign key "target" model I have defined without named primary key.


No, I think you're seeing the same behaviour for all fields - ie you're retrieving the value of the key for the related item. However for the Status model, that value is a string since you've defined a charfield as the primary key.
 
Under the hood, related fields store the key of the related item, not the item itself. Clever Stuff (TM) in the ORM then reifies those objects as needed.


Malcolm

Daniel Roseman

unread,
Jun 21, 2011, 11:33:45 AM6/21/11
to django...@googlegroups.com
But why do you need to get that value via the *field* object? The usual way to do it is simply to access the attribute directly on the model instance:

    unicode(dev.distro)

or, if you have the field name as a string as you imply originally, use `getattr`:

    unicode(getattr(dev, 'distro'))
--
DR.

Jeff Blaine

unread,
Jun 21, 2011, 12:16:29 PM6/21/11
to django...@googlegroups.com
Nope, you're just dealing with a newbie.  The second form works perfectly
for my needs.  Thanks! 

Jeff Blaine

unread,
Jun 21, 2011, 12:18:31 PM6/21/11
to django...@googlegroups.com
But why do you need to get that value via the *field* object? The usual way to do it is simply to access the attribute directly on the model instance:

    unicode(dev.distro)

or, if you have the field name as a string as you imply originally, use `getattr`:

    unicode(getattr(dev, 'distro'))

Indeed, that's what I am doing now:

        for field in Device._meta.fields:
            vname = field.verbose_name
            val = unicode(getattr(dev, field.name))
            val = sanitized_value(val)
            self.stdout.write("%s: %s\n" % (vname, val))
 
Thank you all.
Reply all
Reply to author
Forward
0 new messages