Django Activity Feed(Feedly 集成?)

Posted

技术标签:

【中文标题】Django Activity Feed(Feedly 集成?)【英文标题】:Django Activity Feed (Feedly Integration?) 【发布时间】:2013-12-20 03:26:26 【问题描述】:

我已经构建了一个简单的 Django 照片应用程序。用户可以上传照片、关注其他用户和喜欢照片。为了处理用户之间的关系(关注和取消关注),我使用 coleifer 的一个名为 django-relationships 的包。这是一个很棒的软件包,使用起来非常简单。

一切正常。我目前有一个工作活动提要。

我将提要过滤为两个部分:关注(我关注的用户的所有活动)和您(发生在我身上的所有活动)。我从我的 ios 应用程序中发布了下面两张图片,该应用程序使用我的 Django 照片应用程序作为后端:

我想做的是将聚合添加到以下 Feed。如您所见,用户 alexperri 已点赞 5 次。我想将所有这些项目汇总到一行中。我不需要为“你”提要添加聚合,因为我希望看到发生在我身上的每个单独的操作。但是对于以下提要,添加聚合是有意义的。有几个应用程序可以很好地进行聚合。 Fashionlista、Pinterest 和 Instagram 在这方面做得很好。这是 Instagram 的一个示例,展示了我想要实现的目标:

在上面的示例中,您可以看到以下提要,并且 lovetoronto 赞了 5 张照片。我开始在 Instagram 上玩转,看看它是如何工作的。 Instagram 以下供稿最多显示 35 个活动条目,每个条目最多可以有 5 个该操作类型的活动。 “lovetoronto赞了5张照片”是一个活动条目,它显示了他最近点赞的5张照片。自从lovetoronto执行了最新的动作,他就位居榜首。

我想实现相同的设置。

这是我当前的模型设置:

models.py

from django.db import models
from django.contrib.auth.models import User

class Photographer(models.Model):
    user = models.OneToOneField(User, primary_key=True
    likes = models.ManyToManyField('Photo', through = 'Likes', 
                                   related_name = 'likedby', blank = True)

class Photo(models.Model):
    photographer = models.ForeignKey(Photographer, related_name = 'shot_owner')
    created = models.DateTimeField(auto_now_add=True)
    url = models.CharField(max_length=128)

class Likes(models.Model):
    liked_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
    photographer = models.ForeignKey(Photographer, related_name = 'liked_by')
    photo = models.ForeignKey(Photo, null=True)

class Activity(models.Model):
    actor = models.ForeignKey(Photographer, related_name = 'actor')
    receiver = models.ForeignKey(Photographer, related_name = 'receiver')
    action = models.CharField(max_length=12)
    post = models.ForeignKey(Photo, null=True, blank=True)
    time = models.DateTimeField(auto_now_add=True)

每次创建“Like”对象时,我也会创建一个 Activity 对象,actor 是执行该操作的人,接收者是执行该操作的人,该操作(在本例中为string, 'liked'), post(照片) 和活动对象的创建时间。

我使用 django-tastypie 来获取和创建“Like”和“Activity”对象。

api.py

from tastypie.resources import ModelResource, ALL, ALL_WITH_RELATIONS
from tastypie.authentication import BasicAuthentication
from tastypie.authorization import DjangoAuthorization, Authorization
from photoapp.photodb.models import *
from tastypie.serializers import Serializer
from relationships.utils import positive_filter
from relationships.models import Relationship
from relationships.models import RelationshipStatus

class LikeResource(ModelResource):
    user = fields.ForeignKey(BasicUserResource, 'user', full=True)
    class Meta:
        queryset = Photographer.objects.all()
        allowed_methods = ['put']
        resource_name = 'like'
        fields = ['user']
        default_format = 'application/json'
        authorization = Authorization()
        authentication = BasicAuthentication()
        serializer = Serializer(formats=['json'])
        always_return_data = True
        include_resource_uri = False

        def hydrate(self, bundle):
            shot = Photo.objects.all().get(id = bundle.data['photo id'])
            user = Photographer.objects.all().get(user = bundle.request.user)
            if(bundle.obj.likes.filter(id = bundle.data['photo id']).exists()):
                Likes.objects.all().filter(photographer=user).filter(photo=shot).delete()

                Activity.objects.filter(actor__user = bundle.request.user,
                    post = shot, action = 'liked').delete()

            else:
                like = Likes(photographer = user, photo=shot)
                like.save()
                user_doing_the_liking = User.objects.get(
                    username=bundle.request.user.username)
                user = Photographer.objects.all().get(user = bundle.request.user)
                user_getting_liked = shot.photographer.user
                photographer_getting_liked = shot.photographer
                newActivity = Activity()
                newActivity.actor = user
                newActivity.receiver = photographer_getting_liked
                newActivity.action = 'liked'
                newActivity.post = shot
                newActivity.save()

    return bundle 

class FollowingFeed(ModelResource):
    actor = fields.ForeignKey(BasicPhotographerResource, 'actor', full=True)
    receiver = fields.ForeignKey(BasicPhotographerResource, 'receiver', full=True)
    post = fields.ForeignKey(BasicPostResource, attribute = 'post', full=True, null=True)
    class Meta:
        queryset = Activity.objects.all()
        allowed_methods = ['get']
        resource_name = 'following-feed'
        fields = ['actor', 'receiver', 'action', 'post', 'id', 'time']
        default_format = "application/json"
        authorization = Authorization()
        authentication = BasicAuthentication()
        serializer = Serializer(formats=['json'])
        always_return_data = True
        include_resource_uri = False

    def get_object_list(self, request):
        return super(FollowingFeed, self).get_object_list(request)\
            .filter(actor__user__in = request.user.relationships.following())\
            .exclude(receiver__user = request.user)\
            .exclude(actor__user = request.user).order_by('-time') 

如何修改 FollowFeed 资源以聚合活动对象?我遇到了Feedly 项目。如何在我当前的设置中使用它?

【问题讨论】:

你还需要按action 分组吗?除了liked,还有其他动作类型吗? @mariodev 感谢您的快速回复。是的,我想按用户分组,然后按他们所做的操作进行分组。此外还有其他动作。有追随、评论和提及。差不多就是这样。因此,我不想让提要显示每个 alexperri 的类似活动,而是汇总它们。 “Alexperri 点赞了 5 张照片”(显示最近一小时内最新的 5 张照片……即使 Alexperri 在过去一小时内点赞的照片超过 5 张,我也只想显示最新的 5 张)。 @mariodev,如果 alexperri 点赞了 10 张图片,并且 alexperri 在最后一小时关注了 bob 和 kyle。我想按最近执行的操作进行排序。因此,如果 alexperri 的最新动作是“点赞”,并且如果他是我关注的所有人中最新做出动作的人,我会检查我关注的所有人的最后 100 条活动,获取最新的 5喜欢该列表中来自 alexperri 的操作并将其汇总(alexperri 喜欢 5 张照片)。然后我会检查我关注的人中的下一个人是谁做了第二次最新的行动。运行相同的逻辑。等等…… 那么其余的操作是如何工作的.. 如果关注,您是否列出最新关注的用户?对于每种操作类型,您会列出什么?在我看来,Activity 表仅用于喜欢.. @mariodev 查看 LikeResource,我在其中创建了 newActivity = Activity()。我对 FollowResource、CommentResource 和 MentioningResource 做同样的事情。我只是没有将这些资源添加到问题中,因为问题太大了。我想让这个问题变得简单。例如,在 MentioningResource 中,我执行提及所需的逻辑,然后执行 newActivity = Activity()。 newActivity.action 将是“提及”。 NewActivity 接收者 = user_being_提到。 newActivity.post= 拍摄。 newActivity.save() 这有意义吗?如果我不清楚,请告诉我 【参考方案1】:

我认为您不想进行任何数据库级别的聚合,因为您可能想要显示各个详细信息以及计数,例如“X 喜欢 5 张照片”并显示 5 张照片。根据定义,聚合将排除单个数据。

相反,您应该使用 Python 代码(或 javascript,因为我认为您使用的是 HTTP API,但我更喜欢已经组织好的服务器端 API)进行分组和排序。

itertools.groupby 可能会有所帮助。我认为您需要按(用户和操作)分组,然后按每个组中第一项的时间戳排序,这样您可能会看到“乔喜欢 5 张照片”、“安妮发布了 2 张照片”、“乔发布了照片”、“克莱尔点赞了 3 张照片”等。

【讨论】:

【参考方案2】:

设置聚合时间,例如你想聚合 10 分钟内或过去 24 小时内的所有“赞”吗?

然后您可以按此时间范围过滤您的对象。

然后您可以使用 .values('model__field') 方法应用分组。 Django 生成包含 'GROUP BY' 的 sql

然后最后添加一个聚合限制,这样当点赞数超过此限制时,您会显示聚合视图而不是单个活动视图。

以下示例(伪,非实际):

if (activity.object.filter(time__gt=yourlowertime, time__lt=youruppertime).values(‘activity__action').count() > aggregation_limit) :
     # show aggregated view
else:
     # show normal view

【讨论】:

【参考方案3】:

我认为最好的方法是修改 Activity 表以存储分组的活动。发生新操作时,请检查现有的相同类型的操作,然后编辑记录以使其“分组”,或添加新记录。您可以将 ManyToMany 关系添加到包含相关记录的所有潜在表中,或者仅将数据存储在包含足够信息的 json 字段中,以便在提要中呈现活动,而无需查询其他表对象。

如果资源过于密集,您可以排队添加/编辑新活动。您最好将活动表保持为直接提要,在呈现时不需要任何处理。这不是最容易实施的解决方案,但我认为从长远来看它是有意义的。

【讨论】:

【参考方案4】:

在您的提要资源中,您已经覆盖了 get_object_list,我建议更改逻辑以执行聚合逻辑的原始查询。

def get_object_list(self, request):
        query = "Your aggregation query logic here"
        feed_model = self._meta.object_class
        return feed_model.objects.raw(query)

这应该可以满足要求。但是,您需要考虑您的查询逻辑。如果您遇到任何其他问题,请告诉我。

谢谢!

【讨论】:

@Rahual Tanwani,感谢您的快速响应,让我摸不着头脑的是查询逻辑,这就是我要找的东西

以上是关于Django Activity Feed(Feedly 集成?)的主要内容,如果未能解决你的问题,请参考以下文章

AMADdjango-activity-stream

Django - 聚合内容 RSS/Atom

django 聚合内容 RSS/Atom

Android Fragment找不到ID的视图?

django开源项目bootcamp个别问题分析

TeamCity NuGet Feed:配置Feed网址