[Django]-Django: list all reverse relations of a model

28👍

This was changed (in 1.8 I think) and Olivier’s answer doesn’t work anymore. According to the docs, the new way is

[f for f in Item._meta.get_fields()
    if f.auto_created and not f.concrete]

This includes one-to-one, many-to-one, and many-to-many.

👤Dan

3👍

I’ve found out that there are methods of Model._meta that can give me what I want.

my_model = get_model('app_name','model_name')
# Reverse foreign key relations
reverse_fks = my_model._meta.get_all_related_objects()
# Reverse M2M relations
reverse_m2ms = my_model._meta.get_all_related_many_to_many_objects()

By parsing the content of the relations, I can guess whether the “direct” field was a OneToOneField or whatever.

2👍

I was looking into this answer as a starting point to identify reversed relationships for a model instance.

So, I noticed that when you get all the fields using instance._meta.get_fields(), those that are direct relationships, which are 3 types (ForeignKey, ManyToMany, OneTone), their parent class (field.__class__.__bases__) is django.db.models.fields.related.ForeignKey.

However, those that are reverse relationships inherit from django.db.models.fields.reverse_related.ForeignObjectRel. And if you take a look at this class, it has:

auto_created = True
concrete = False

So you could identify those by the attributes mentioned in the top-rated answer or by asking isinstance(field, ForeignObjectRel.

Another thing I could notice is that those reverse relationships have a field attribute which points to the direct relationship generating that reverse relationship.

Additionally, in order to exclude the fields instantiating the through table, those have through and through_fields attributes

0👍

And what about this :

oneToOneFieldNames = [
    field_name 
    for field_name in Item._meta.get_all_field_names() 
    if isinstance(
        getattr(
            Item._meta.get_field_by_name(field_name)[0], 
            'field', 
            None
        ), 
        models.OneToOneField
    )
]

RelatedObject may have a Field attribute for relations. You just have to check if this is a OneToOne field and you can retrieve only what you want

0👍

if you are using Django Rest Framework, you could use something like that for your obj:

from rest_framework.utils import model_meta
info = model_meta.get_field_info(obj)
for field in obj.__class__.__dict__.keys():
    if field in info.relations and info.relations[field].to_many and info.relations[field].reverse:
        #print all reverse relations
        print(field)

Leave a comment