How could I add a helper function in Django to match a topic with its user and show Http404 if not the case?

Question:

thank you beforehand. This is my first post, I´ll try to be brief. I´m going through exercise 19-3 Refactoring in Python Crash Course. However I’m a bit stuck in it. I should make a function to check the owner of a topic, and if not the case raise a Http404 error.

I tried to create a “utils” folder and house my function there, but had a Name Error, so I deleted it. Then tried to store the function in the same file, but I raised a Http404 error even when the user was the owner of the topic. I left it as before trying this exercise with the function in place commented out:

from django.shortcuts import render
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from .models import Topic, Entry
from .forms import TopicForm, EntryForm

@login_required
def topic(request, topic_id):
    topic = Topic.objects.get(id=topic_id)
    # check_topic_owner(request)
    if topic.owner != request.user:
        raise Http404

    entries = topic.entry_set.order_by('-date_added')
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

@login_required
def edit_entry(request, entry_id):
    """Edit an existing entry"""
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic
    # check_topic_owner(request)
    if topic.owner != request.user:
        raise Http404

    if request.method != 'POST':
        form = EntryForm(instance=entry)

#The function to check owner is here:
def check_topic_owner(request):
    owner = Topic.owner
    if owner != request.user:
        raise Http404

What is difficult for me to understand is how can I make a “helper” function if it needs some additional information like the ID of the topic and to define the owner. Hope you can help me, thank you very much.

Asked By: hco_3

||

Answers:

The problem is that in check_topic_owner() you use Topic.owner which will just likely return the field definition. You are not using an instance of Topic there.

If you do something like this

def edit_entry(request, entry_id):
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic
    check_topic_owner(topic.owner, request)
    ...

def check_topic_owner(owner, request):
    if owner != request.user:
        raise Http404

you should be fine.

Answered By: wfehr

You should do the check in the query itself. get_object_or_404 will raise a 404 if a matching item is not found. So:

@login_required
def edit_entry(request, entry_id):
    entry = get_object_or_404(Entry, id=entry_id, topic__owner=request.user)
Answered By: Daniel Roseman

The check_topic_owner() function the exercise 19-3 asks for needs two arguments to work, request and topic. So, it would go just like this on views.py:

 def check_topic_owner(request, topic):
       if topic.owner != request.user:
           raise Http404

To call this function, you should write check_topic_owner(request, topic) where the check is needed.