Get the name attribute of a GenericForeign key object - django

I have the following model in a Django app:
How can I get the "name" attribute of any selected content_object in this model and display it in list_display of the modelAdmin class, instead of just displaying the keys of the GenericForeign Key objects. Please I really need help with this.
class Checkout(models.Model):
checkout_date = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
check_in_complete = models.BooleanField(default=False, editable=False)
content_type = models.ForeignKey(ContentType,
limit_choices_to={"model__in": ('Facilitator', 'Enumerator', 'Tutor')})
object_id = models.PositiveIntegerField(verbose_name='Receiver')
content_object = GenericForeignKey('content_type', 'object_id')

Since GenericForeignKey is not a normal field object, you can not use it in filters:
Checkout.objects.filter(content_object=other_obj) # this will fail
But if you want to access the name property of the object your checkout is associated with using GenericForeignKey you can do it like following:
name = checkout_obj.content_object.name

Related

Trying to access 'content_object' fields in Django under ContentType

I am trying to access the Item model through the Thing queryset, and keep getting the error:
django.core.exceptions.FieldError: Field 'content_object' does not generate an automatic reverse relation and therefore cannot be used for reverse querying. If it is a GenericForeignKey, consider adding a GenericRelation.
class ThingContent(models.Model):
content_id = models.AutoField(primary_key=True, null=False)
thing = models.ForeignKey('Thing', on_delete=models.SET_NULL, null=True)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
I have tried updating the fields on Item by adding a related_query_name to no success.
self.queryset.filter(items__item_date=exact_item_date))
class Item(models.Model):
id = models.AutoField(primary_key=True, null=False)
item_date = models.DateField(**options)
thing_content = GenericRelation('ThingContent', related_query_name='items')
content_object is generic. You must filter by object_id and content_type for know what object you FK generic.
You try again with query like this:
ThingContent.objects.filter(
items__item_date=item_date,
content_type=ContentType.objects.get_for_model(Item)
)
this query mean: find all ThingContent have mapping with Item, and have item_date like what you want filter.

Generic Foreign Key with computed content type instead of fk to content type model

The simplest case of creating a generic foreign key is like this:
class ModelWithGFK(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
But in my case there are other fields which I can infer the content type from, so adding a content_type FK is both redundant and prone to cause inconsistency over time. So I tried this:
class ModelWithGFK(models.
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
#property
def content_type(self):
# Figure out wich content type this instance should have FK to
return ContentType.objects.get(..........)
but seems like GFK class only accepts the content type argument to be a foreign key:
def _check_content_type_field(self):
"""
Check if field named `field_name` in model `model` exists and is a
valid content_type field (is a ForeignKey to ContentType).
"""
Is there a workaround (perhaps via overriding GFK and some of its methods like get_content_type) or I shall give in, add the FK and live in a constant fear of inconsistency and agony of knowing about this (tiny) inevitable redundancy?

Create a relationship model where a user can follow any of two models

How do I setup a model for a follow relationship, where a user can follow another user or a tag.
eg: userA is following (userB, userC, tag-Health, tag-Finance).
This was how I thought:
class Relationship(models.Model):
user = AutoOneToOneField(User)
content_type = models.ManyToManyField(ContentType, related_name='followed_by')
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Tag(models.Model):
name = models.CharField(max_length=10, unique=True)
But since ContentType only works for ForeignKey, how do I create a model so that a user can follow any of the two model (i.e. users and tags?

Django tastypie save reverse GenericForeignKeyField

Django Tastypie can save related objects even with reverse relationship.
But is it able for Django Tastypie to save reverse relationship of GenericForeignKeyField?
My resources (not full, but the important only),
class AreaResource(ModelResource):
tripl3user = fields.ManyToManyField(
'tripl3sales.api.resources.area.Tripl3UserResource',
'tripl3user',
related_name='area',
full=True
)
class Tripl3UserResource(ModelResource):
content_type = fields.ForeignKey(
'tripl3sales.api.resources.contenttype.ContentTypeResource',
'content_type'
)
content_object = GenericForeignKeyField({
Area : AreaResource
}, 'content_object')
My models.py,
class Area(models.Model):
name = models.CharField(max_length=50, unique=True)
tripl3user = generic.GenericRelation('Tripl3User')
class Tripl3User(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
Is it possible to save reverse relationship of generic foreign key? If so, then how to do it? What does the data look like?
Finally I got the answer.
In a resource that has content_type and object_id, there is no need to declare content_type because content_object is enough. And for related_name, instead of using area, we use content_object.
So, my resources.py should be,
class AreaResource(ModelResource):
tripl3user = fields.ManyToManyField(
'tripl3sales.api.resources.area.Tripl3UserResource',
'tripl3user',
related_name='content_object',
full=True
)
class Tripl3UserResource(ModelResource):
content_object = GenericForeignKeyField({
Area : AreaResource
}, 'content_object')
Hope this will help others.

Accessing referring object with GenericForeignKey in django

I have the following models:
Class A(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
thumbnail = models.ImageField(...)
class B(models.Model)
title = models.CharField()
def save(*args, **kwargs):
# Based on the title field I want to fetch some picture and then save the thumbnail in A
I have more classes like B which should be referenced from A (this is why I use GenericForeignKey). The problem I am trying to figure out is how to save the thumbnail field (on A) when I am in the save() method in B. Inserting many if statement in A to check the type of the referenced class and save the thumbnail accordingly is pretty cumbersome.
Looking at the docs, you can add a reverse generic relation from B to A:
If you know which models you’ll be using most often, you can also add a “reverse” generic relationship to enable an additional API
class A_Model(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
thumbnail = models.ImageField(...)
class B_Models(models.Model)
title = models.CharField()
a_models = generic.GenericRelation(A_Model)
and now you can do:
b = B_Model()
a = A_Model(content_object=b, thumbnail=...)
a.save()
b.a_models.all()