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