Esempio n. 1
0
def push_tweet_to_cache(sender, instance, created, **kwargs):
    # 只有新建时才push, update时并不push
    if not created:
        return

    from tweets.services import TweetService
    TweetService.push_tweet_to_cache(instance)
Esempio n. 2
0
 def create(self, validated_data):
     user = self.context['request'].user
     content = validated_data['content']
     tweet = Tweet.objects.create(user=user, content=content)
     if validated_data.get('files'):
         TweetService.create_tweet_photos(tweet, validated_data['files'])
     return tweet
Esempio n. 3
0
 def list(self, request, *args, **kwargs):
     """
     重载 list 方法,不列出所有 tweets,必须要求指定 user_id 作为筛选条件
     """
     user_id = request.query_params['user_id']
     cached_tweets = TweetService.get_cached_tweet(user_id)
     page = self.paginator.paginate_cached_list(cached_tweets, request)
     if page is None:
         # 这句查询会被翻译为
         # select * from twitter_tweets
         # where user_id = xxx
         # order by created_at desc
         # 这句 SQL 查询会用到 user 和 created_at 的联合索引
         # 单纯的 user 索引是不够的
         queryset = Tweet.objects.filter(
             user_id=user_id).order_by('-created_at')
         page = self.paginate_queryset(queryset)
     serializer = TweetSerializer(
         page,
         context={'request': request},
         many=True,
     )
     # 一般来说 json 格式的 response 默认都要用 hash 的格式
     # 而不能用 list 的格式(约定俗成)
     return self.get_paginated_response(serializer.data)
Esempio n. 4
0
    def list(self, request, *args, **kwargs):
        """
        overloading list function, make user_id as a requirement to filter
        """

        user_id = request.query_params['user_id']
        tweets = Tweet.objects.filter(user_id=user_id).prefetch_related('user')

        cached_tweets = TweetService.get_cached_tweets(user_id)
        page = self.paginator.paginate_cached_list(cached_tweets, request)
        if page is None:
            """
                            if 'user_id' not in request.query_params:
                        return Response('missing user_id', status=400)
                    The above line will be interpreted as following SQL:'
                    select * from twitter_tweets where user_id=xxx order by created_at DESC
                    this SQL query will be using composite index of user_id and created_at
                    """
            queryset = Tweet.objects.filter(
                user_id=user_id).order_by('-created_at')
            page = self.paginate_queryset(queryset)
        serializer = TweetSerializer(
            page,
            context={'request': request},
            many=True,
        )
        # usually response in JSON format should be included in hash
        # instead of a list
        return self.get_paginated_response(serializer.data)
Esempio n. 5
0
 def list(self, request, *args, **kwargs):
     tweets = TweetService.get_cached_tweets(
         user_id=request.query_params['user_id'])
     paginated_tweets = self.paginate_queryset(tweets)
     serializer = TweetSerializersWithCommentsAndLikes(
         paginated_tweets,
         context={'request': request},
         many=True,
     )
     return self.get_paginated_response(serializer.data)
Esempio n. 6
0
    def test_create_new_tweet_before_get_cached_tweets(self):
        tweet1 = self.create_tweet(self.user1, 'test tweet')
        RedisClient.clear()
        conn = RedisClient.get_connection()
        key = USER_TWEET_PATTERN.format(user_id=self.user1.id)
        self.assertEqual(conn.exists(key), False)
        tweet2 = self.create_tweet(self.user1, 'another tweet')
        self.assertEqual(conn.exists(key), True)

        tweets = TweetService.get_cached_tweets(self.user1)
        self.assertEqual([tweet.id for tweet in tweets], [tweet2.id, tweet1.id])
Esempio n. 7
0
    def test_create_tweet_before_get_cached_tweets(self):
        tweet1 = self.create_tweet(user=self.user1)

        RedisClient.clear()
        conn = RedisClient.get_connection()
        name = USER_TWEET_PATTERN.format(user_id=self.user1.id)
        self.assertFalse(conn.exists(name))
        tweet2 = self.create_tweet(user=self.user1)
        self.assertTrue(conn.exists(name))

        tweets = TweetService.load_tweets_through_cache(user_id=self.user1.id)
        self.assertEqual([t.id for t in tweets], [tweet2.id, tweet1.id])
Esempio n. 8
0
    def test_get_user_tweets(self):
        tweet_ids = []
        for i in range(3):
            tweet = self.create_tweet(self.linghu, 'tweet {}'.format(i))
            tweet_ids.append(tweet.id)
        tweet_ids = tweet_ids[::-1]

        RedisClient.clear()
        conn = RedisClient.get_connection()

        # cache miss
        tweets = TweetService.get_cached_tweets(self.linghu.id)
        self.assertEqual([t.id for t in tweets], tweet_ids)

        # cache hit
        tweets = TweetService.get_cached_tweets(self.linghu.id)
        self.assertEqual([t.id for t in tweets], tweet_ids)

        # cache updated
        new_tweet = self.create_tweet(self.linghu, 'new tweet')
        tweets = TweetService.get_cached_tweets(self.linghu.id)
        tweet_ids.insert(0, new_tweet.id)
        self.assertEqual([t.id for t in tweets], tweet_ids)
Esempio n. 9
0
 def list(self, request, *args, **kwargs):
     user_id = request.query_params['user_id']
     cached_tweets = TweetService.get_cached_tweets(user_id)
     page = self.paginator.paginate_cached_list(cached_tweets, request)
     if page is None:
         queryset = Tweet.objects.filter(
             user_id=user_id).order_by('-created_at')
         page = self.paginate_queryset(queryset)
     serializer = TweetSerializer(
         page,
         context={'request': request},
         many=True,
     )
     return self.get_paginated_response(serializer.data)
Esempio n. 10
0
    def test_tweet_cache_limit_pagination(self):
        limit_size = settings.REDIS_LIST_LENGTH_LIMIT
        page_size = 20

        tweets = [
            self.create_tweet(user=self.user1)
            for i in range(limit_size + page_size)
        ]
        tweets = tweets[::-1]

        # cached tweets
        cached_tweets = TweetService.load_tweets_through_cache(
            user_id=self.user1.id)
        self.assertEqual(len(cached_tweets), limit_size)
        db_tweets = Tweet.objects.filter(user_id=self.user1.id)
        self.assertEqual(len(db_tweets), limit_size + page_size)

        # paginate all tweets
        paginated_tweets = self._paginate_to_get_tweets(
            client=self.user2_client,
            user_id=self.user1.id,
        )
        self.assertEqual(len(paginated_tweets), limit_size + page_size)
        self.assertEqual([t['id'] for t in paginated_tweets],
                         [t.id for t in tweets])

        # create new tweet
        new_tweet = self.create_tweet(user=self.user1)

        def _test_tweets_after_pushed_new_tweet():
            new_paginated_tweets = self._paginate_to_get_tweets(
                client=self.user2_client,
                user_id=self.user1.id,
            )
            self.assertEqual(len(new_paginated_tweets),
                             limit_size + page_size + 1)
            self.assertEqual(new_paginated_tweets[0]['id'], new_tweet.id)
            for i in range(limit_size + page_size):
                self.assertEqual(tweets[i].id,
                                 new_paginated_tweets[i + 1]['id'])

        _test_tweets_after_pushed_new_tweet()

        # cache expire
        self.clear_cache()
        _test_tweets_after_pushed_new_tweet()
Esempio n. 11
0
    def list(self, request, *args, **kwargs):
        user_id = request.query_params['user_id']
        tweets = Tweet.objects.filter(user_id=user_id).prefetch_related('user')

        cached_tweets = TweetService.get_cached_tweets(user_id)
        page = self.paginator.paginate_cached_list(cached_tweets, request)
        if page is None:
            # select * from twitter_tweets where user_id = xxx
            # order by created_at desc
            queryset = Tweet.objects.filter(user_id=user_id).order_by('-created_at')
            page = self.paginate_queryset(queryset)
        serializer = TweetSerializer(
            page,
            context={'request': request},
            many=True,
        )
        return self.get_paginated_response(serializer.data)
Esempio n. 12
0
 def list(self, request, *args, **kwargs):
     user_id = request.query_params['user_id']
     cached_tweets = TweetService.get_cached_tweets(user_id)
     page = self.paginator.paginate_cached_list(cached_tweets, request)
     if page is None:
         # 这句查询会被翻译为
         # select * from twitter_tweets
         # where user_id = xxx
         # order by created_at desc
         # 这句 SQL 查询会用到 user 和 created_at 的联合索引
         # 单纯的 user 索引是不够的
         queryset = Tweet.objects.filter(
             user_id=user_id).order_by('-created_at')
         page = self.paginate_queryset(queryset)
     # many = true means it will return a list of dict
     serializer = TweetSerializer(page,
                                  context={'request': request},
                                  many=True)
     return self.get_paginated_response(serializer.data)
Esempio n. 13
0
 def list(self, request):
     # select out all tweets of a specific user
     cached_tweets = TweetService.load_tweets_through_cache(
         user_id=request.query_params['user_id']
     )
     page = self.paginator.paginate_cached_list(cached_tweets, request)
     # cache not enough
     if not page:
         tweets = Tweet.objects.filter(
             user_id=request.query_params['user_id']
         )
         page = self.paginate_queryset(tweets)
     serializer = TweetSerializer(
         page,
         context={'request': request},
         many=True,
     )
     # wrap the list of tweet contents in endless pagination
     return self.get_paginated_response(serializer.data)
Esempio n. 14
0
 def list(self, request):
     """
     重载 list 方法,不列出所有 tweets,必须要求指定 user_id 作为筛选条件
     """
     user_id = request.query_params['user_id']
     # get tweets from redis cache instead of DB
     cached_tweets = TweetService.get_cached_tweets(user_id=user_id)
     page = self.paginator.paginate_cached_list(cached_tweets, request)
     if page is None:
         queryset = Tweet.objects.filter(user_id=user_id).order_by('-created_at')
         page = self.paginate_queryset(queryset)
     serializer = TweetSerializer(
         page,
         context={'request': request},
         many=True,
     )
     # 一般来说 json 格式的 response 默认都要用 hash 的格式
     # 而不能用 list 的格式(约定俗成)
     # return Response({'tweets': serializer.data})
     return self.get_paginated_response(serializer.data)
Esempio n. 15
0
 def list(self, request, *args, **kwargs):
     user_id = request.query_params['user_id']
     cached_tweets = TweetService.get_cached_tweets(user_id)
     page = self.paginator.paginate_cached_list(cached_tweets, request)
     if page is None:
         # 这句查询会被翻译为
         # select * from twitter_tweets
         # where user_id = xxx
         # order by created_at desc
         # 这句sql查询语句会用到user和created_at的联合索引
         # 单纯的user索引是不够的
         queryset = Tweet.objects.filter(
             user_id=user_id).order_by('-created_at')
         page = self.paginate_queryset(queryset)
     serializer = TweetSerializer(
         page,
         context={'request': request},
         many=True,
     )  # 传进去是是QuerySet,返回的是一个list of dict
     # 一般来说,json格式的response默认都要用的hash格式
     # 而不能用list的格式(约定俗成)
     # 所以在最外面需要套上一个dict
     return self.get_paginated_response(serializer.data)
Esempio n. 16
0
def push_tweet_to_cache(sender, instance, created, **kwargs):
    if not created:
        return

    from tweets.services import TweetService
    TweetService.push_tweets_to_cache(instance)