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?
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
                        You can use getattr to return a default value if the field does not exist.. like below
getattr(table, field, False)
                        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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With