19

シンプルな Django 写真アプリを作成しました。ユーザーは、写真をアップロードしたり、他のユーザーをフォローしたり、写真を気に入ったりすることができます。ユーザー間の関係 (フォローとフォロー解除) を処理するために、coleifer によるdjango-relationshipsというパッケージを使用します。それは素晴らしいパッケージであり、非常に使いやすいです。

すべてが正常に機能します。現在、作業アクティビティ フィードがあります。

フィードを 2 つのセクションにフィルター処理します: フォロー中 (私がフォローしているユーザーからのすべてのアクティビティ) とあなた (私に起こったすべてのアクティビティ)。Django フォト アプリをバックエンドとして使用する iOS アプリから、以下の 2 つの写真を投稿しました。

ここに画像の説明を入力 ここに画像の説明を入力

私がやりたいことは、次のフィードに集計を追加することです。ご覧のとおり、ユーザー alexperri は 5 ショットを気に入りました。これらすべての項目を 1 行にまとめたいと思います。「あなた」フィードの集計を追加する必要はありません。個々のアクションが自分に起こっていることを確認したいからです。ただし、次のフィードの場合、集計を追加することは理にかなっています。集計を非常にうまく行うアプリケーションがいくつかあります。Fashionlista、Pinterest、Instagram はこれをうまく行っています。これは、私が達成しようとしていることを示すInstagramの例です。

ここに画像の説明を入力

上記の例では、次のフィードと、lovetoronto が 5 枚の写真を気に入ったことがわかります。Instagramの次のフィードをいじって、それがどのように機能するかを確認し始めました. Instagram のフォロー フィードには最大 35 のアクティビティ エントリが表示され、各エントリにはそのアクション タイプのアクティビティを最大 5 つ含めることができます。「lovetoronto いいね 5 枚の写真」は 1 つのアクティビティ エントリで、彼が最近気に入った 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 オブジェクトも作成します。アクターはアクションを実行した人、レシーバーはアクションが実行された人、つまりアクション (この場合は文字列 ' 「いいね!」)、投稿(写真)、とりあえず活動オブジェクトの作成。

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') 

アクティビティ オブジェクトを集約するように、FollowingFeed リソースを変更するにはどうすればよいですか? Feedlyプロジェクトに出会いました。現在のセットアップでどのように使用できますか?

4

4 に答える 4

2

データベース レベルの集計を行う必要はないと思います。おそらく、個々の詳細とカウントを表示したいからです。たとえば、「X は 5 枚の写真が好き」と 5 枚の写真を表示します。集計は、定義上、個々のデータを除外します。

代わりに、Python コード (または HTTP API を使用していると思われるので Javascript でグループ化と並べ替えを行う必要がありますが、既に整理されたサーバー側 API を使用することをお勧めします)。

itertools.groupbyが役立つかもしれません。(ユーザーとアクション) でグループ化し、各グループの最初のアイテムのタイムスタンプで並べ替える必要があると思います。これにより、「Joe が 5 枚の写真を気に入った」、「Anne が 2 枚の写真を投稿した」、「Joe が 1 枚の写真を投稿した」と表示されるようになります。写真」、「クレアが 3 枚の写真を気に入りました」など。

于 2014-08-08T11:15:33.200 に答える
0

集計時間を設定します。たとえば、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
于 2014-01-24T14:41:17.210 に答える
0

これを行う最善の方法は、Activity テーブルを変更して、グループ化されたアクティビティを格納することだと思います。新しいアクションが発生したら、同じタイプの既存のものを確認し、レコードを編集して「グループ化」するか、新しいレコードを追加します。関連するレコードを含む可能性のあるすべてのテーブルに ManyToMany リレーションシップを追加するか、他のテーブル オブジェクトにクエリを実行することなく、フィード内のアクティビティをレンダリングするのに十分な情報を含む json フィールドにデータを格納するだけです。

リソースを集中的に使用する場合は、新しいアクティビティの追加/編集をキューに入れることができます。アクティビティ テーブルは、レンダリング時に処理を必要としない単純なフィードのままにしておく方がよいでしょう。これは実装が最も簡単な解決策ではありませんが、長期的には理にかなっていると思います。

于 2013-12-16T20:34:52.860 に答える