Goal for this part
Home becomes a following timeline for signed-in people, with a public “Everyone” tab for discovery. Paginate both. Add search for posts and neighbors.
Concepts
The following feed is one SQL query: posts whose author is in the set you follow, plus your own posts. That is not a ranking model. It is honest and indexable. Search uses PostgreSQL icontains first; you can add SearchVector later without changing the URL.
Walkthrough
from django.core.paginator import Paginator
def feed(request):
scope = request.GET.get("scope", "following")
qs = Post.objects.select_related("author", "author__profile")
if request.user.is_authenticated and scope != "everyone":
people = list(request.user.following.values_list("following_id", flat=True))
people.append(request.user.id)
qs = qs.filter(author_id__in=people)
page = Paginator(qs, 10).get_page(request.GET.get("page"))
return render(request, "posts/feed.html", {"page": page, "scope": scope})def search(request):
q = (request.GET.get("q") or "").strip()[:80]
posts = Post.objects.none()
people = User.objects.none()
if q:
posts = Post.objects.filter(body__icontains=q)[:20]
people = User.objects.filter(
models.Q(username__icontains=q) | models.Q(profile__display_name__icontains=q)
)[:20]
return render(request, "social/search.html", {"q": q, "posts": posts, "people": people})Always cap q. Unbounded search strings are a cheap way to hurt Postgres. Use GET so results are shareable and refresh-safe.
How to run it and what you should see
Sign in as Ada (she follows Grace in the seed). Home should show Grace’s posts and Ada’s, not every seeded stranger. Switch to Everyone and paginate to page 2. Search block and see matching posts; search grace and see her profile in the people list.
Common mistakes
Using Python to filter a huge list instead of author_id__in will not scale. Forgetting your own id in the following set hides your just-composed post. Putting search on POST breaks the back button.
Try this
Unfollow Grace as Ada and confirm her posts leave the Following tab but remain on Everyone. Then add an index in a migration on Post.created_at if it is not there already.