Django: Get list of model object fields depending on their type?

467 Views Asked by At

Listing fields of models and their objects has been answered successfully here. But i want a generalized way of processing on object fields depending on their types, so that i can serialize them manually in dictionary. e.g: ManyToMany,OneToMany...,FileField,...,Relations_field(Field not present in the model but defined as foreign key in some other model).

I don't know how much of a reasonable demand it is to manually serialize your model objects, but my purposes are more pedagogical than performance oriented.

This is a small function where i am converting model objects to JSON serializable dictionaries.

def obj_to_dict(obj):
    
    fields = obj._meta.get_fields()
    obj_dict = {}
    # Here I want to process fields depending upon their type:

    for field in fields:
        
        if field is a relation:
            ## DO SOMETHING
      

        elif Field is ManyToMany or OneToMany ... :
            ## DO SOMETHING

        elif field is image field:
            ## DO SOMETHING
        else:
            ## DO SOMETHING
    return obj_dict

The answer here, does give a way but not quite what i want, way for more generalization depending upon fields.

1

There are 1 best solutions below

0
On BEST ANSWER

Short Answer: get_internal_type() method is exactly what is required here. It returns a string of Field Type, e.g: "FileField".

Caveat: Reverse relations not locally defined in a model and fields defined as a foreign key to some other model, both are returned as "ForeignKey" with this method.

Detailed:

  1. To process over fields you may need to access the field value,you can do so in all cases through getattr(model_object,field.name) inside the loop.
  2. To differentiate between reverse relations and foreign key you can use auto_created property. As ReverseRelations return True on auto_created property and ForeignKey field don't.
  3. ImageField is just a file field, but it has properties such as width,height,url etc. so it can be checked through getattr(obj,field.name).width property.

You can iterate over the fields as:

def obj_to_dict(obj):

fields = obj._meta.get_fields()

obj_dict = {}
# Here I want to process fields depending upon their type:

for field in fields:

    field_val = getattr(obj,field.name)

    if field.get_internal_type()=="ForeignKey" and not field.auto_created:
        ## for foreign key defined in model class

    elif field.get_internal_type()=="ForeignKey" and field.auto_created:
        ## for reverse relations not actually defined in model class.

    elif field.get_internal_type()=="ManyToMany"/ "OneToMany" ... :
        DO SOMETHING

    # for image field
    elif field.get_internal_type() == "FileField" and field_val.width:
        ## DO SOMETHING

    else:(for other locally defined fields not requiring special treatment)
        ## DO SOMETHING
return obj_dict