I'm following a Django tutorial and have reached the point of using return renderand currently my views.py looks like this:
from django.http import HttpResponse
from django.shortcuts import render
# Create your views here.
def construction_view(*args, **kwargs):
return HttpResponse("<h1> This site is currently being constructed. Please check back later </h1>")
def home_view(*args, **kwargs):
return render(request, "home.html", {})
I am getting an error whien trying to go to my home page:
views.py", line 9, in home_view
return render(request, "home.html", {})
NameError: name 'request' is not defined
Not sure what is causing this as according to Django docs request is part of render which is imported above.
request is always the first parameter of any view. In your view, your function only has *args and **kwargs, so request will be the first item in the args. It is better to make the request parameter explicit and work with:
# request ↓
def home_view(request, *args, **kwargs):
return render(request, "home.html", {})
Since you likely only use this view for URL patterns without URL patterns, you can probably omit the *args and **kwargs:
# ↓ omit *args and **kwargs
def home_view(request):
return render(request, "home.html", {})
Related
I have a Class Based View called ChannelAuth that for testing purposes we have decorated with #csrf_exempt. This isn't final, but nonetheless I'd like an answer for the sake of learning.
#csrf_exempt
class ChannelAuth(views.APIView):
def post(self, request, *args, **kwargs):
if not request.data:
return JsonResponse({'Error': 'Data is malformed.'}, status=400)
....
When using a decorator, though, we are "wrapping" the class so to speak in a function.
This means when we use ChannelAuth.as_view() we aren't actually accessing the as_view() attribute as expected, because it doesn't exist on the "wrapper function" thus throwing an AttributeError.
urlpatterns = [
path('admin/', admin.site.urls),
path('api/auth/channels/', ChannelAuth.as_view(), name="channel_auth")
]
So my question is how would I still utilize a decorator like #csrf_exempt on a Class Based View properly?
The initial solution is to use Django's method_decorator() on the targeted method.
from django.utils.decorators import method_decorator
class ChannelAuth(views.APIView):
#method_decorator(csrf_exempt, name='post')
def post(self, request, *args, **kwargs):
if not request.data:
return JsonResponse({'Error': 'Data is malformed.'}, status=400)
....
I have sub-classed Generic DetialView class in views.py and trying to figure out a way to return data in JSON format based on an argument received in the url. Here's what I have tried doing...
# views.py
from django.views.generic import DetailView
from django.http import JsonResponse
class ExtendedView(DetailView):
context_object_name = 'post'
model = StorageModel
template_name='posts.html'
def get_context_data(self, **kwargs):
data = super(HacksViewPost, self).get_context_data(**kwargs)
if bool(self.request.GET):
data__ = JsonForm(request.GET)
if data__.is_valid():
json = data__.cleaned_data['json']
if json == 'true':
return JsonResponse({'data': 'data'})
return data
But this gave me TypeError as it should be:
TypeError at /category/extended-slug/
context must be a dict rather than JsonResponse.
The url that activates the ExtendedView class is:
/category/extended-slug?json=true
So, the question is how could i send data in JSON Format from a Generic View Class and are there any better ways of acheiving this?
I think you patch it at the wrong level. The get_context_data is used by the get function to render it. As a result, the get_context_data object has no control about what is done with the result, in order to construct a server response,
You can however patch the get(..) function like:
class ExtendedView(DetailView):
"""A base view for displaying a single object."""
def get(self, request, *args, **kwargs):
self.object = self.get_object()
data = self.get_context_data(object=self.object)
if self.request.GET:
data__ = JsonForm(request.GET)
if data__.is_valid():
json = data__.cleaned_data['json']
if json == 'true':
return JsonResponse({'data': data})
return self.render_to_response(data)
The same holds for post, put, and other requests.
If we take a look at the DetailView source code we see:
class BaseDetailView(SingleObjectMixin, View):
"""A base view for displaying a single object."""
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
Hence the get(..) calls the get_context_data(..) function. But it does not immediately returns the result, it wraps it into a rendered response.
You can't return a JsonResponse inside the get_context_data method. The get_context_data method allows you to send extra information (context) to the template and is expected to return a dict, not a JsonResponse.
If you want to return a JsonResponse, do that in the get or post method of your class.
This question already has answers here:
How to pass extra_context when redirecting in Django
(2 answers)
Closed 4 years ago.
I have a Django form which upon validation I want to redirect to a success page. I start at "localhost/upload", submit my form, if it is validated I want to go to localhost/upload/success. The following code works, I just want to be able to pass a context dictionary with some variables in there to render to the page. I can only do this using (hashed out in the views.py code below)
return render(request, 'results/success.html', context)
but this returns to localhost/upload, but with my success.html template - i want to go to upload/success.
Here is my code:
views.py:
#login_required(login_url='/')
def upload(request):
""" Upload panel or results.
"""
if request.method == 'POST':
paneluploadform = PanelUploadForm(request.POST, request.FILES)
if paneluploadform.is_valid():
paneluploadform.upload()
context = {'hi': 'helloasdgja'}
# return render(request, 'results/success.html', context)
return HttpResponseRedirect('success')
else:
# print(paneluploadform.errors.as_text)
pass
else:
paneluploadform = PanelUploadForm()
context = {'paneluploadform': paneluploadform}
return render(request, 'results/upload.html', context)
#login_required(login_url='/')
def success(request):
""" Success view
"""
return render(request, 'results/success.html')
urls.py:
from django.conf.urls import url
from .views import *
urlpatterns = [
url(r'^upload/$', upload),
url(r'^upload/success/', success)
]
I can use the hashed out return render() line to give my test context, but this returns to "localhost:8000/upload"
I want to go to localhost:800/upload/success, but get information from upload view and redirect to upload/success. Can I pass a context arg to HttpResponseRedirect or is there a way around this?
Session variables are useful for passing information between pages/views.
https://docs.djangoproject.com/en/dev/topics/http/sessions/
Ian Clelland does a good job of highlighting your options here:
https://stackoverflow.com/a/8931063/4928578
Trying to make a form with Django and using a HttpResponseRedirect, I expected this should be fairly easy, however I seem to be doing something wrong.
I keep getting an error:
The view hotel.views.hotel_registration didn't return an HttpResponse object. It returned None instead.
In this case my guess would be that HttpResponseRedirect is not working properly, since, when I remove the if statement with the contents everything is working fine, except I can't submit a form.
I have 2 views:
def hotel_registration(request):
if request.method == 'POST':
form = HotelRegistrationForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('hotel:hotel_registered')
else:
form = HotelRegistrationForm()
return render(request, 'hotel/hotel-registration-form.html', {'form': form})
def hotel_registered(request):
pass
And in urls.py
url(r'hotel-registratie/', hotel.views.hotel_registration, name='registration'),
url(r'hotel-geregistreerd/', hotel.views.hotel_registered, name='registered'),
These are all the parameters I have used in HttpResponseRedirect:
HttpResponseRedirect('hotel:hotel_registered')
HttpResponseRedirect('hotel_registered')
HttpResponseRedirect('/hotel_registered/')
HttpResponseRedirect(hotel_registered)
And then I rust wanted to redirect back to root:
HttpResponseRedirect('/')
And using reverse:
HttpResponseRedirect(reverse(hotel_registration))
HttpResponseRedirect(reverse('hotel_registration'))
What would be the right way to do this?
According to the following urls.py that you posted :
url(r'hotel-registratie/', hotel.views.hotel_registration, name='registration'),
url(r'hotel-geregistreerd/', hotel.views.hotel_registered, name='registered'),
You should make the redirection using one of the following methods :
return HttpResponseRedirect('hotel-geregistreerd/')
or
return HttpResponseRedirect(reverse('registered'))
or simply
return redirect('registered')
When you use HttpResponseRedirect provide the path of the url, if you use reverse or redirect you can use the name that you defined in your urls.py.
I have a template that I want to be able to both serve directly and embed in arbitrary other templates in my Django application. I tried to create a view class for it that looks like this:
class TemplateView(View):
def get(self, request):
context = self._create_context(request)
return render_to_response('template.html', context)
def get_string(self, request):
context = self._create_context(request)
return render_to_string('template.html', context)
def _create_context(self, request):
context = {}
# Complex context initialization logic...
return context
I've wired get to my Django URLs. However, I haven't been able to figure out how to instantiate TemplateView so that I can call get_string from other views.
There must be a better way to go about doing this. Ideas?
Update: I've seen some folks talking about making a request internally and using response.content, which would save me from having to write the get_string method. So, perhaps a better question is: How do I make a request to TemplateView from another view?
I'd follow in django's CBV pattern: it determines via dispatch what method to return. By default based on request.method. Why not based on any other argument passed to dispatch()?
So subclass dispatch and give it a way to determine whether or not to return get_string.
def dispatch(self, request, *args, **kwargs):
if 'as_string' in kwargs:
return self.get_string(request)
return super(TemplateView, self).dispatch(request, *args, **kwargs)
response = TemplateView.as_view()(request, as_string=True)