简体   繁体   中英

Introspect property types on Django model without 'objects' throwing AttributeError

This sounds like a duplicate, but I absolutely could not find someone with a duplicate of my problem.

My model:

class SuperCoolModel(models.Model):
    large = models.ImageField()
    small = models.ImageField()
    blah = some.OtherClass()  # Not a Field type, but is a subclass of ImageFile

What I want to do is "iterate" (somehow) over the properties on an instance of this model, and do something for properties that are an instance of ImageField.

Eg, here's code that works :

from django.db.models.fields.files import ImageFile
a = SuperCoolModel.objects.get(pk=1)
for attrname in dir(a):
    # Ignore attr names that we obviously don't care about:
    # E.g., anything that starts with an underscore-or-two:
    if attrname.startswith('_'):
        continue
    try:
        if isinstance(getattr(a, attrname), ImageFile):
            field = getattr(a, attrname)
            # Manipulate some stuff, based on the file, 
            # e.g., using `field.path`.
            pass 
    except AttributeError as e:
        # Hopefully this is JUST the 'objects' reference?
        pass

In the example above, as it traverses method/property names, when it gets to 'object' it would raise:

  File "<console>", line 3, in <module>   File "/path/to/lib/python2.7/site-packages/django/db/models/manager.py", line 206, in __get__
    raise AttributeError("Manager isn't accessible via %s instances" % type.__name__)
AttributeError: Manager isn't accessible via SuperCoolModel instances

... So I've started watching for the AttributeError exception. Alternatively, I could hard-code "objects" in my loop, as I do when checking for underscore names.

I cannot use a._meta.fields , a._meta.get_all_field_names() , etc, because I am also trying to check the type of some arbitrary properties that are not Fields but are of a certain subclass and/or type.

Am I doing this right, or is there a better way to skip "objects" (and other potential "gotchas") here?

I don't understand your explanation of why you can't use the _meta methods: you can use a._meta.get_all_field_names() to get a list of the actual fields, then add whatever arbitrary properties you have to the resulting list.

In the upcoming 1.8 release this has been deprecated, you would need to use [f.name for f in a._meta.get_fields()]

Note that none of the properties will be an instance of ImageField. The instance doesn't have ImageFields (or CharFields, or any fields) as properties; it has actual strings, ints etc, and in the case of images it uses FieldFile .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM