pythondjango-modelsdjango-ormjson-serializable

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


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.


Solution

  • 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