Get model's fields in Django

Viewed 164331

Given a Django model, I'm trying to list all of its fields. I've seen some examples of doing this using the _meta model attribute, but doesn't the underscore in front of meta indicate that the _meta attribute is a private attribute and shouldn't be accessed directly? ... Because, for example, the layout of _meta could change in the future and not be a stable API?

Is _meta an exception to this rule? Is it stable and ready to use or is it considered bad practice to access it? Or is there a function or some other way to introspect the fields of a model without using the _meta attribute? Below is a list of some links showing how to do this using the _meta attribute

Any advice is much appreciated.

django object get/set field

http://www.djangofoo.com/80/get-list-model-fields

How to introspect django model fields?

11 Answers

get_fields() returns a tuple and each element is a Model field type, which can't be used directly as a string. So, field.name will return the field name

my_model_fields = [field.name for field in MyModel._meta.get_fields()]
The above code will return a list conatining all fields name

Example

In [11]: from django.contrib.auth.models import User

In [12]: User._meta.get_fields()
Out[12]: 
(<ManyToOneRel: admin.logentry>,
 <django.db.models.fields.AutoField: id>,
 <django.db.models.fields.CharField: password>,
 <django.db.models.fields.DateTimeField: last_login>,
 <django.db.models.fields.BooleanField: is_superuser>,
 <django.db.models.fields.CharField: username>,
 <django.db.models.fields.CharField: first_name>,
 <django.db.models.fields.CharField: last_name>,
 <django.db.models.fields.EmailField: email>,
 <django.db.models.fields.BooleanField: is_staff>,
 <django.db.models.fields.BooleanField: is_active>,
 <django.db.models.fields.DateTimeField: date_joined>,
 <django.db.models.fields.related.ManyToManyField: groups>,
 <django.db.models.fields.related.ManyToManyField: user_permissions>)

In [13]: [field.name for field in User._meta.get_fields()]
Out[13]: 
['logentry',
 'id',
 'password',
 'last_login',
 'is_superuser',
 'username',
 'first_name',
 'last_name',
 'email',
 'is_staff',
 'is_active',
 'date_joined',
 'groups',
 'user_permissions']

If you need this for your admin site, there is also the ModelAdmin.get_fields method (docs), which returns a list of field name strings.

For example:

class MyModelAdmin(admin.ModelAdmin):
    # extending change_view, just as an example
    def change_view(self, request, object_id=None, form_url='', extra_context=None):
        # get the model field names
        field_names = self.get_fields(request)
        # use the field names
        ...

As per the django documentation 2.2 you can use:

To get all fields: Model._meta.get_fields()

To get an individual field: Model._meta.get_field('field name')

ex. Session._meta.get_field('expire_date')

fields = [f"{f.name}_id" if f.is_relation else f.name for f in model._meta.fields]

Another way is add functions to the model and when you want to override the date you can call the function.

class MyModel(models.Model):
    name = models.CharField(max_length=256)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    def set_created_date(self, created_date):
        field = self._meta.get_field('created')
        field.auto_now_add = False
        self.created = created_date

    def set_modified_date(self, modified_date):
        field = self._meta.get_field('modified')
        field.auto_now = False
        self.modified = modified_date

my_model = MyModel(name='test')
my_model.set_modified_date(new_date)
my_model.set_created_date(new_date)
my_model.save()
Related