This is a direct continuation of the last part in the Writing Instagram in Python series. This is a highly dependant article that assumes work on the previous articles so even though one could read the other articles as standalone ones, it’s recommended to go through all the previous posts in this series to get an idea of what we’re working with here.
We’ve accomplished most of what we set out to do in the beginning of this series. And as I said before, Instagram is nothing but an image based CRUD app that runs on the scale of the globe. But so far, we haven’t implemented anything belonging to the R in CRUD — that stands for retrieve (or read). This is the trickiest since we need to keep a couple of things in mind before jumping in and creating a feed.
Instagram today relies on highly advanced machine learning models that are trained on the activities of millions of users every day and thus is very advanced in predicting what the end user wants to see based on their conversations with people, the kind of pictures they like, the kind of tags they follow, etc. It does have some sense of linearity in the way that it tries to place all the new posts at the top of one’s feed according to the relevance that these machine learning algorithms predict. But we’re not going to do that because that is extremely out of the scope of this series. We’re going to try to build a simple linear feed for users which is an aggregation of Post instances by the user that the active user follows sorted according to their timestamps.
But the fact of the matter is — this was all just an elaborate scheme. There’s nothing difficult about generating simple feeds given the following list and even sorting them according to the timestamps. It’s just one simple ListAPIView
away —
It might seem like a complex query but it’s exactly what I just described in such a complicated fashion. That might lead you to believe that we’re done with our Instagram app but there’s just one component missing — the profile view.
What happens when a user visits the profile of another user? I can image three possible permutations —
- The visitor is not authenticated, aka, an anonymous user: we simply redirect them to the login page
- The visitor is authenticated but does not follow the user he’s visiting: we simply don’t show any posts save the bio, username, and profile picture of said user.
- The visitor is authenticated as well as a follower of the user he’s visiting: we show all the posts of the user.
Once again, easier done than said, utilizing ListAPIView
and our homegrown follower relationship API to its full power. The one key decision to take here is the location of this view. Should it live in the user
app since it’s a direct retrieval of user related data or should it live in the feed app since it’s a job of generating a feed based off of relationships?
One can make arguments for both sides but I prefer to keep any direct user information fetching views inside the user app. Thus, in your user/views.py
file, add these two views to the bottom along with all the appropriate imports at the top —
And believe it or not, that’s all there is to our views for users! If you take a look at the code we’ve written, you’ll realize we’ve only used rest framework’s generics! That’s how powerful they are.
The UserUpdateAPIView needs some work but as a starter point, it’s good enough. There is a start lack of inline documentation is my opinion but the code is so expressive that it speaks for itself — there’s nothing out of the ordinary here, and we trust the reader of the code to understand it at first glance.
Once again — this is all there is to it for generating a user following based feed in a linear fashion. However, it’s not perfect. Some, including me, will argue it’s not even good. But it works. And that’s what matters. Once you do reach the scale where raw SQL queries with a large enough in
clause is causing you performance troubles, trust me, you’ll be large enough to invest into a performance engineer who can solve all those headaches for you. And in the mean time, always remember —
Don’t fix something that isn’t broken.