Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if model field exists in Django

Tags:

python

django

This is the solution I came up, in my models.py:

from django.db import models

@classmethod
def model_field_exists(cls, field):
    try:
        cls._meta.get_field(field)
        return True
    except models.FieldDoesNotExist:
        return False

models.Model.field_exists = model_field_exists

And use it like:

Post.field_exists('title') # > True or False

The problem comes with foreign keys, my Post model belongs to a Category, this check works:

Post.field_exists('category') # > True

But this one doesn't:

Post.field_exists('category_id') # > False

This is the actual field name in db and I need to check for it like this. How can I do it in django?

like image 813
lucaswxp Avatar asked Mar 13 '15 14:03

lucaswxp


4 Answers

hasattr(cls,field) will not work in all cases, for example where mixins are used. A safe test is:

            try:
                model._meta.get_field(field)
                .. do stuff here
            except FieldDoesNotExist:
                pass

or

            field = None
            try:
                field = model._meta.get_field(field)
            except FieldDoesNotExist:
                pass

            if field:
              .. do stuff here
like image 186
PhoebeB Avatar answered Oct 13 '22 06:10

PhoebeB


You can use getattr to return a default value if the field does not exist.. like below

getattr(table, field, False)
like image 24
SuperNova Avatar answered Oct 13 '22 06:10

SuperNova


Your 'category_id' field is a hidden field in the terminology of https://docs.djangoproject.com/en/1.10/ref/models/meta/ . It can't be retrieved by get_field.

Maybe loop over all the fields and check their names; get_fields can return hidden fields:

for field in cls._meta.get_fields(include_hidden=True):
    if field.name == field:
        return True
return False

If you need to care about fields that have their db_column changed from their default, you can test field.db_column too (but it is unset if it wasn't set explicitly).

like image 7
RemcoGerlich Avatar answered Oct 13 '22 07:10

RemcoGerlich


But this one doesn't:

Post.field_exists('category_id') # > False

This is the actual field name in db and I need to check for it like this. How can I do it in django?

The case for everything aside from the _id part is sufficiently answered in the other answer. For handling the _id cases, you would basically need a special conditional in addition to that answer to appropriately deal with these cases. Something resembling this:

if field_name.endswith('_id'):
    try:
        field = model._meta.get_field(field_name.strip('_id'))
    except FieldDoesNotExist:
        return False
    if not f.is_relation:
        return False
    return True

The additional check is needed to assure that the field minus _id returns a ForeignKey, as opposed to some other type of field that just happens to have the same name, which would mean the name_id field on the model is invalid.

like image 6
AlanSE Avatar answered Oct 13 '22 05:10

AlanSE