Aam*_*amu 12 django django-queryset
我想构建一个像Quora或Medium这样的webapp ,用户可以在其中关注用户或某些主题.
例如:userA跟随(userB,userC,tag-Health,tag-Finance).
这些是模型:
class Relationship(models.Model):
user = AutoOneToOneField('auth.user')
follows_user = models.ManyToManyField('Relationship', related_name='followed_by')
follows_tag = models.ManyToManyField(Tag)
class Activity(models.Model):
actor_type = models.ForeignKey(ContentType, related_name='actor_type_activities')
actor_id = models.PositiveIntegerField()
actor = GenericForeignKey('actor_type', 'actor_id')
verb = models.CharField(max_length=10)
target_type = models.ForeignKey(ContentType, related_name='target_type_activities')
target_id = models.PositiveIntegerField()
target = GenericForeignKey('target_type', 'target_id')
tags = models.ManyToManyField(Tag)
Run Code Online (Sandbox Code Playgroud)
现在,这将给出以下列表:
following_user = userA.relationship.follows_user.all()
following_user
[<Relationship: userB>, <Relationship: userC>]
following_tag = userA.relationship.follows_tag.all()
following_tag
[<Tag: tag-job>, <Tag: tag-finance>]
Run Code Online (Sandbox Code Playgroud)
要过滤我试过这种方式:
Activity.objects.filter(Q(actor__in=following_user) | Q(tags__in=following_tag))
Run Code Online (Sandbox Code Playgroud)
但由于actor是GenericForeignKey,我收到一个错误:
FieldError:字段'actor'不生成自动反向关系,因此不能用于反向查询.如果是GenericForeignKey,请考虑添加GenericRelation.
如何使用用户列表和用户遵循的标记列表过滤唯一的活动?具体来说,我将如何使用对象列表过滤GenericForeignKey以获取以下用户的活动.
你应该只按ID过滤.
首先获取要过滤的对象ID
following_user = userA.relationship.follows_user.all().values_list('id', flat=True)
following_tag = userA.relationship.follows_tag.all()
Run Code Online (Sandbox Code Playgroud)
您还需要过滤actor_type.例如,可以这样做.
actor_type = ContentType.objects.get_for_model(userA.__class__)
Run Code Online (Sandbox Code Playgroud)
或者@Todor在评论中建议.因为get_for_model接受模型类和模型实例
actor_type = ContentType.objects.get_for_model(userA)
Run Code Online (Sandbox Code Playgroud)
而且你可以像这样过滤.
Activity.objects.filter(Q(actor_id__in=following_user, actor_type=actor_type) | Q(tags__in=following_tag))
Run Code Online (Sandbox Code Playgroud)
他们docs所建议的并不是一件坏事。
问题是,当您创建时,Activities您正在使用auth.Useras actor,因此您无法添加GenericRelation到auth.User (也许您可以通过猴子修补它,但这不是一个好主意)。
@Sardorbek Imomaliev解决方案非常好,如果将所有这些逻辑放入自定义QuerySet类中,您可以使其变得更好。(这个想法是实现 DRY 性和可重用性)
class ActivityQuerySet(models.QuerySet):
def for_user(self, user):
return self.filter(
models.Q(
actor_type=ContentType.objects.get_for_model(user),
actor_id__in=user.relationship.follows_user.values_list('id', flat=True)
)|models.Q(
tags__in=user.relationship.follows_tag.all()
)
)
class Activity(models.Model):
#..
objects = ActivityQuerySet.as_manager()
#usage
user_feed = Activity.objects.for_user(request.user)
Run Code Online (Sandbox Code Playgroud)
1.你真的需要GenericForeignKey吗actor?我不知道你的业务逻辑,所以你可能知道,但是只使用FKactor 的常规(就像tags)将可以像 那样做工作人员actor__in=users_following。
2.您是否检查过是否有相应的应用程序?已经解决您问题的软件包的一个示例是django-activity-steam检查它。
3.如果您不使用auth.Useras ,actor您可以按照docs建议进行操作 -> 添加GenericRelation字段。事实上,您的Relationship课程适合此目的,但我真的会将其重命名为类似UserProfile或至少UserRelation. 考虑一下我们已经重命名Relation为UserProfile,并且我们创建了新的Activities使用userprofile。这个想法是:
class UserProfile(models.Model):
user = AutoOneToOneField('auth.user')
follows_user = models.ManyToManyField('UserProfile', related_name='followed_by')
follows_tag = models.ManyToManyField(Tag)
activies_as_actor = GenericRelation('Activity',
content_type_field='actor_type',
object_id_field='actor_id',
related_query_name='userprofile'
)
class ActivityQuerySet(models.QuerySet):
def for_userprofile(self, userprofile):
return self.filter(
models.Q(
userprofile__in=userprofile.follows_user.all()
)|models.Q(
tags__in=userprofile.relationship.follows_tag.all()
)
)
class Activity(models.Model):
#..
objects = ActivityQuerySet.as_manager()
#usage
#1st when you create activity use UserProfile
Activity.objects.create(actor=request.user.userprofile, ...)
#2nd when you fetch.
#Check how `for_userprofile` is implemented this time
Activity.objects.for_userprofile(request.user.userprofile)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4222 次 |
| 最近记录: |