Django: Get list of model fields?

mpen Source

I've defined a User class which (ultimately) inherits from models.Model. I want to get a list of all the fields defined for this model. For example, phone_number = CharField(max_length=20). Basically, I want to retrieve anything that inherits from the Field class.

I thought I'd be able to retrieve these by taking advantage of inspect.getmembers(model), but the list it returns doesn't contain any of these fields. It looks like Django has already gotten a hold of the class and added all its magic attributes and stripped out what's actually been defined. So... how can I get these fields? They probably have a function for retrieving them for their own internal purposes?

djangodjango-models

Answers

answered 8 years ago rossipedia #1

For Django versions 1.8 and later:

The get_all_field_names() method is deprecated starting from Django 1.8 and will be removed in 1.10.

The documentation page linked above provides a fully backwards-compatible implementation of get_all_field_names(), but for most purposes [f.name for f in MyModel._meta.get_fields()] should work just fine.

For Django versions before 1.8:

model._meta.get_all_field_names()

That should do the trick.

That requires an actual model instance. If all you have is a subclass of django.db.models.Model, then you should call myproject.myapp.models.MyModel._meta.get_all_field_names()

answered 5 years ago bjw #2

I find adding this to django models quite helpful:

def __iter__(self):
    for field_name in self._meta.get_all_field_names():
        value = getattr(self, field_name, None)
        yield (field_name, value)

This lets you do:

for field, val in object:
    print field, val

answered 3 years ago Rockallite #3

This does the trick. I only test it in Django 1.7.

your_fields = YourModel._meta.local_fields
your_field_names = [f.name for f in your_fields]

Model._meta.local_fields does not contain many-to-many fields. You should get them using Model._meta.local_many_to_many.

answered 3 years ago Wil #4

The get_all_related_fields() method mentioned herein has been deprecated in 1.8. From now on it's get_fields().

>> from django.contrib.auth.models import User
>> User._meta.get_fields()

answered 2 years ago aboutaaron #5

MyModel._meta.get_all_field_names() was deprecated several versions back and removed in Django 1.10.

Here's the backwards-compatible suggestion from the docs:

from itertools import chain

list(set(chain.from_iterable(
    (field.name, field.attname) if hasattr(field, 'attname') else (field.name,)
    for field in MyModel._meta.get_fields()
    # For complete backwards compatibility, you may want to exclude
    # GenericForeignKey from the results.
    if not (field.many_to_one and field.related_model is None)
)))

answered 1 year ago arrt_ #6

Just to add, I am using self object, this worked for me:

[f.name for f in self.model._meta.get_fields()]

answered 6 months ago Nader Alexan #7

It is not clear whether you have an instance of the class or the class itself and trying to retrieve the fields, but either way, consider the following code

Using an instance

instance = User.objects.get(username="foo")
instance.__dict__ # returns a dictionary with all fields and their values
instance.__dict__.keys() # returns a dictionary with all fields
list(instance.__dict__.keys()) # returns list with all fields

Using a class

User._meta.__dict__.get("fields") # returns the fields

# to get the field names consider looping over the fields and calling __str__()
for field in User._meta.__dict__.get("fields"):
    field.__str__() # e.g. 'auth.User.id'

answered 4 months ago Kanak #8

At least with Django 1.9.9 -- the version I'm currently using --, note that .get_fields() actually also "considers" any foreign model as a field, which may be problematic. Say you have:

class Parent(models.Model):
    id = UUIDField(primary_key=True)

class Child(models.Model):
    parent = models.ForeignKey(Parent)

It follows that

>>> map(lambda field:field.name, Parent._model._meta.get_fields())
['id', 'child']

while, as shown by @Rockallite

>>> map(lambda field:field.name, Parent._model._meta.local_fields)
['id']

answered 4 months ago Vivek Anand #9

def __iter__(self):
    field_names = [f.name for f in self._meta.fields]
    for field_name in field_names:
        value = getattr(self, field_name, None)
        yield (field_name, value)

This worked for me in django==1.11.8

comments powered by Disqus