django try block best use - python

I have a view that takes 2 arguments :course_slug and chapter_slug and i want to check if the given course and chapter exist in the database so what's the best way to do that :
def Chapter_Detail(request,course_slug,chapter_slug):
try:
course = Course.objects.get(slug=course_slug)
except Course.DoesNotExist:
raise Http404("course does not exist")
try:
chapter = Chapter.objects.get(slug=chapter_slug)
except Chapter.DoesNotExist:
raise Http404("chapter does not exist")
'''
continue view logic
'''
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
or:
def Chapter_Detail(request,course_slug,chapter_slug):
try:
course = Course.objects.get(slug=course_slug)
chapter = Chapter.objects.get(slug=chapter_slug)
'''
continue view logic
'''
except Course.DoesNotExist:
raise Http404("course does not exist")
except Chapter.DoesNotExist:
raise Http404("chapter does not exist")
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
or:
def Chapter_Detail(request,course_slug,chapter_slug):
try:
course = Course.objects.get(slug=course_slug)
chapter = Chapter.objects.get(slug=chapter_slug)
except Course.DoesNotExist:
raise Http404("course does not exist")
except Chapter.DoesNotExist:
raise Http404("chapter does not exist")
else :
'''
continue view logic
'''
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
or there is a better way
continue view logic means that we are going to work with the course and chapter objects

As mentioned by Aiden, you can use the shortcut specifically made for this.
from django.shortcuts import get_object_or_404
def Chapter_Detail(request,course_slug,chapter_slug):
course = get_object_or_404(Course, slug=course_slug)
chapter = get_object_or_404(Chapter, slug=chapter_slug)
'''
continue view logic
'''
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
Your three variants will also work of course. The else-block in the third example is strictly not necessary, since either error will get raised or code will proceed.

Related

ValueError: The view create.views.CheckoutView didn't return an HttpResponse object. It returned None instead

I am getting a ValueError that the class below didn't return any httpresponse when i try to redirect to a template. the redirect is supposed to go to the stripe payment view.
here is an entire class that has the redirect call
class CheckoutView(View):
def get(self, *args, **kwargs):
form = forms.CheckoutForm()
context = {
'form': form
}
return render(self.request, "checkout.html", context)
def post(self, *args, **kwargs):
form = forms.CheckoutForm(self.request.POST or None)
try:
equipment_order = models.EquipmentOrder.objects.get(user=self.request.user, ordered=False)
if form.is_valid():
street_address = form.cleaned_data.get('street_address')
apartment_address = form.cleaned_data.get('apartment_address')
country = form.cleaned_data.get('country')
zip = form.cleaned_data.get('zip')
'''
TODO: add functionality to these fields
same_shipping_address = form.cleaned_data.get('same_shipping_address')
save_info = form.cleaned_data.get('save_info')
'''
payment_option = form.cleaned_data.get('payment_option')
billing_address = models.BillingAddress(
user=self.request.user,
street_address=street_address,
apartment_address=apartment_address,
country=country,
zip=zip
)
billing_address.save()
equipment_order.billing_address = billing_address
equipment_order.save()
if payment_option == 'S':
return redirect('create:payment', payment_option='stripe')
elif payment_option == 'P':
return redirect('create:payment', payment_option='paypal')
else:
messages.warning(self.request, "Invalid payment option")
return redirect('create:checkout')
except ObjectDoesNotExist:
messages.error(self.request, "You do not have an active order")
return redirect("create:order_summary")
1) Remove the try/except i think its better
2) I think you have a problem on 'payement_option' , maybe it doesnt give any value of expected , try to print it first to see what does it give
3) remove the ' or None ' from CheckoutForm
4) you can avoid using 'self' by importing form in that way :
from .forms import CheckoutForm
...
form = CheckoutForm(request.POST)
The above answer may work fine but as I tried your code it throws the same error as you described whenever you leave the form field empty or no payment method is selected.
After trying your code the best possible solution I figure out is this. I know this is not a perfect solution but it worked 😅
Suggestion: Try to move your else statement under if instead of nesting it after elif statement. And change your else to given below.
Old:
else:
messages.warning(self.request, "Invalid payment option select")
return redirect('core:checkout')
New:
else :
messages = 'Invalid payment option select'
return HttpResponse(messages)
Proof: Invalid payment option select

Return value on try except

I'm writing a challenge in Python and I would like to know what is the right approach to return None case my function throws an Exception.
def get(email):
try:
customer = get_customer(email)
return customer
except TypeError as e:
logging.error(f'Customer {email} not found', e)
Should I do something like customer = None and return customer after except block?

Most pythonic way of checking if a form submiited has data

I'm currently learning Django however I'm torn on how to structure the equivalent of add method using it. I'm creating a URL shortener and I'm between the following methods to implement in creating the shortened URL:
def shorten(request):
if request.method == 'POST':
http_url = request.POST.get("http_url","")
if http_url: # test if not blank
short_id = get_short_code()
new_url = Urls(http_url=http_url, short_id=short_id)
new_url.save()
return HttpResponseRedirect(reverse('url_shortener:index'))
else:
error_message = "You didn't provide a valid url"
return render(request, 'url_shortener/shorten.html', { 'error_message' : error_message })
return render(request, 'url_shortener/shorten.html')
vs.
def shorten(request):
http_url = request.POST["http_url"]
if http_url:
short_id = get_short_code()
new_url = Urls(http_url=http_url, short_id=short_id)
new_url.save()
return HttpResponseRedirect(reverse('url_shortener:index'))
else:
error_message = "You didn't provide a valid url"
return render(request, 'url_shortener/shorten.html', { 'error_message' : error_message })
return render(request, 'url_shortener/shorten.html')
Specifically, I want to know the best practice on the following:
Is it best practice to explicity test if method is post or http_url = request.POST["http_url"] is enough
Is http_url = request.POST.get("http_url","") recommended to be used or this is just suppressing the error?
If (2) is not recommended, how can I make the http_url required and throw an error? I also tried the following but the except block is not triggered when I submit a blank form
def shorten(request):
if request.method == 'POST':
try:
http_url = request.POST["http_url"]
short_id = get_short_code()
new_url = Urls(http_url=http_url, short_id=short_id)
new_url.save()
return HttpResponseRedirect(reverse('url_shortener:index'))
except KeyError:
error_message = "You didn't provide a valid url"
return render(request, 'url_shortener/shorten.html', { 'error_message' : error_message })
return render(request, 'url_shortener/shorten.html')
request.POST["key"]
will throw a KeyError when the key is not present in the dictionary. You can use a try...catch clause to handle the error.
Generally though, its idiomatic and perfectly normal to do:
request.POST.get("key")
More about get here.

Django - view didn't return an HttpResponse object

I'm facing this exception error and I'm puzzled by it, as this method worked in similar system, appreciate any help or pointers. Many Thanks!
Exception Value: The view Project.qna.views.add_vote didn't return an HttpResponse object.
def add_vote(request):
if request.method == "POST":
q_id = request.POST['vote_form_q_id']
a_id = request.POST['vote_form_a_id']
vote_value = request.POST['vote_form_value']
ok = False
vote_num = None
name = None
if q_id:
try:
question = Question.objects.get(id=q_id)
question.num_vote += int(vote_value)
question.save()
vote_num = question.num_vote
name = 'Question_'+str(q_id)
ok = True
except Question.DoesNotExist:
pass
elif a_id:
try:
answer = Answer.objects.get(id=a_id)
answer.num_vote += int(vote_value)
answer.save()
vote_num = answer.num_vote
name = 'Answer_'+str(a_id)
ok = True
except Answer.DoesNotExist:
pass
if ok and request.is_ajax:
result = simplejson.dumps({
"vote_num": vote_num,
}, cls=LazyEncoder)
response = HttpResponse(result, mimetype='application/javascript')
response.set_cookie(name, datetime.now)
return response
Fix your indention please, also you seem to have a lot of workarounds that could be simplified.
Every django view should return a HttpResponse object, you seem to have a lot of places where this would not be the case. To narrow down your problem change every pass to a print statement to see where your code actually fails. It would be quite helpful if you could present your POST data.
Well it's hard to tell without seeing what kind of request you are making to the view. But are you sending a POST request? Because you don't handle GET requests in any way. Also the indentation is wrong. But that might just be cutting and pasting gone awry.
This is untested, but it's a cleaner and more robust design, which I believe fits in with your logic and highlights the points where returning an HttpResponse is necessary:
def add_vote(request):
if not (request.method == 'POST' and request.is_ajax):
return # Some suitable response here
try:
vote_value = int(request.POST.get('vote_form_value',''))
except ValueError as e:
pass # Some suitable response here
def saveobj(model, key, val): # helper function to reduce code repetition
item = model.objects.get(id=key)
item.num_vote += val
item.save()
return item.num_vote, '%s_%s' % (model.__class__.__name__, key)
for model, key in [(Question, 'vote_form_q_id'), (Answer, 'vote_form_a_id')]):
try:
new_vote_value, name = saveobj(model, request.POST[key], vote_value)
break
except (KeyError, ObjectDoesNotExist) as e:
continue # or error out
else:
pass # neither question or answer found - so suitable response here
# return ajax response here....

Context processors, passing a session which doesn't exist

Hay All, I've got a simple context processor which looks within a session and if a 'user' key exists. If it does i want to return it to the template.
Here's my context Processor
def get_user_details(request):
user = request.session['user']
data = {
'user':user
}
return data
and here is a sample view
def render_home(request):
return render_to_response("home", context_instance=RequestContext(request))
If the session['user'] doesn't exists, i want it to silently fail, or return False or Null.
Because the key doesnt exist within the session, i get a KeyError.
Any idea's how to fix this?
You can get a default value like None this way: request.session.get('user', None). Just like in normal Python dicts.
user = request.session.get('user', None)
or,
user = None
if 'user' in request.session:
user = request.session['user']
def get_user_details(request):
try:
user = request.session['user']
except KeyError:
return
data = {
'user':user
}
return data
Or if you want to catch it further away, do this instead:
def render_home(request):
try:
return render_to_response("home", context_instance=RequestContext(request))
except KeyError:
return

Categories