Reputation: 2408
I would like to reflect on a model and list all its backward generic relations.
My model looks like this:
class Service(models.Model):
host = models.ForeignKey(Host)
statuses = generic.GenericRelation(Status)
The Status object looks like this:
class Status(TrackedModel):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
class Meta:
verbose_name_plural = 'statuses'
I would like to programatically learn that statuses
is a generic relation for the Service model. Is this possible? Status._meta.fields
does not show statuses
, but Status._meta.get_all_field_names()
does, only it shows other unwanted things too.
I thought that this might be a possible solution, but it seems really messy to me. I'd love to hear of a better one.
from django.db.models.fields import FieldDoesNotExist
from django.contrib.contenttypes import generic
generic_relations = []
for field_name in Service._meta.get_all_field_names():
try:
field = Service._meta.get_field(field_name)
except FieldDoesNotExist:
continue
if isinstance(field, generic.GenericRelation):
generic_relations.append(field)
Thank you!
Upvotes: 4
Views: 1323
Reputation: 1817
UPDATE 2021:
To list all the GenericRelations()
fields:
print(Service._meta.private_fields)
Output:
[<django.contrib.contenttypes.fields.GenericRelation: statuses>]
Nevertheless, if you have more fields with GenericRelations()
relationship they will be shown into the output list.
Check the documentation:
https://docs.djangoproject.com/en/3.2/releases/1.10/#id3
Or you can return all of the fields that have a GenericRelation()
field type.
ex:
# models.py
class MyModel(models.Model):
. . .
my_model_field = GenericRelation(OtherPolyModel)
def get_generic_relation_fields(self):
"""
This function returns all the GenericRelation
fields needed to return the values that are
related to a polymorphic model.
"""
fields = [f.attname for f in self.Meta.model._meta.get_fields()]
file_fields = []
for field in fields:
get_type = self.Meta.model._meta.get_field(field)
field_type = get_type.__class__.__name__
if field_type == "GenericRelation":
file_fields.append(field)
return file_fields
Output:
['my_model_field']
Upvotes: 1
Reputation: 23871
The GenericRelation
works similarly as ManyToManyField
. You could find it in Service._meta.many_to_many
:
filter(lambda f:isinstance(f, generic.GenericRelation), Service._meta.many_to_many)
Upvotes: 3