I am trying to build activity logs by a User or any other model object, to which a user can follow or subscribe to.
These are the models related with logging the activities:
class Activity(models.Model):
"""
An activity log : Actor acts on target
Actor can be a User or a model Object
"""
actor_content_type = models.ForeignKey(
ContentType, on_delete=models.CASCADE, related_name="actor_type")
actor_object_id = models.PositiveIntegerField()
actor = GenericForeignKey('actor_content_type', 'actor_object_id')
description = models.TextField()
target_content_type = models.ForeignKey(
ContentType, on_delete=models.CASCADE, related_name="target_type")
target_object_id = models.PositiveIntegerField()
target = GenericForeignKey('target_content_type', 'target_object_id')
class Follow(models.Model):
"""
A user can follow any User or model objects.
"""
user = models.ForeignKey(User, on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
follow_object = GenericForeignKey('content_type', 'object_id')
Suppose:
- Thor follows user Loki // User follows User
- Thor follows user Stark // User follows User
- Thor follows project Avenger // User follows Project
And suppose these are activities:
- Nick Fury Created a project "Shield"
- Nick Fury Created a project "Avengers"
- Stark created a project "Mark II"
- Avengers added Vision
- Dr Strange created a project Dormammu
I can get the user Thor:
thor = User.objects.get(email="thor@gmail.com")
And get the list of users/objects followed by Thor:
thor.follow_set.all()
<QuerySet [<Follow: thor@gmail.com follows loki@gmail.com>, <Follow: thor@gmail.com follows Stark@gmail.com>, <Follow: thor@gmail.com follows Avengers>]>
Now to get the list of activities followed by the user Thor, I tried this:
q = (Q(actor__in=thor.follow_set.all())| Q(target__in=thor.follow_set.all())
Activity.objects.filter(q)
But its throwing an error:
FieldError: Field 'actor' does not generate an automatic reverse relation and therefore cannot be used for reverse querying. If it is a GenericForeignKey, consider adding a GenericRelation.
I can get all the activities for a single object followed by user Thor:
followed_last = thor.follow_set.last().follow_object
q = (Q(actor_content_type=ContentType.objects.get_for_model(followed_last), actor_object_id=followed_last.id)| Q(target_content_type=ContentType.objects.get_for_model(followed_last), target_object_id=followed_last.id))
Activity.objects.filter(q)
<QuerySet [<Activity: Avengers Added vision@gmail.com>, <Activity: nickfury@gmail.om Created Avengers>]>
But how can I get all the activities Thor is following from the above activities:
- Nick Fury Created a project "Avengers"
- Stark created a project "Mark II"
- Avengers added Vision
Update
Added User model as requested:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
fullname = models.CharField(max_length=255, validators=[validate_fullname])
is_active = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["fullname"]
def __str__(self):
return self.email