Call a view within a view with different methods - django

I have two views, one to create an item and another to generate the global view of an instance of another object.In this view, I have a form and what I want is to redirect to the previous page after the processing of the view.
Basically :
def view1(request):
if request.method == 'GET':
#heavy processing for the context
return HttpResponse(template.render(context))
def view2(request):
if request.method == 'POST':
# Simply add an element
return view1(request)
Here's what I want to do. The thing is that, as you can see, the method is different from view1 to view2. I can't use redirect because the heavy processing of data of view 1 wouldn't be done (I guess).
Does someone know how can I transform my POST request into a GET and add a parameter ?
Thanks !

You can use this too:
def view(request):
if request.method == "POST"
#add the element
#heavy processing for the context
here if the method is post, it will goto the post method if post is available and u can use the post perimeters in the processing u want
hope its useful, please vote up
or u can use:
from django.views.generic.base import View
class view(View):
def get(self, request, *args, **kwargs ):
#heavy processing for the context
def post(self, request, *args, **kwargs):
#add the element
when you'll call the above url with post method, it will goto post, and for other cases it will load get

What makes you think the processing of data in view1 wouldn't be done on a redirect? A HttpRedirectResponse and its shortcut redirect() will simply give the user's browser a 302 HTTP response code, indicating that the browser should do a new request to the specified url and display that page instead of the current page.
It is actually good practice to always do a redirect after a successful POST request. Otherwise, the data in the POST request would be sent and processed twice if the user refreshes the original page. Using a redirect will reset all POST data and prevent duplicate entries or error messages to the user after a successful request.
To pass a parameter, simply add it to the redirect url as you would with any GET parameter:
from django.http import QueryDict
parameters = QueryDict(foo='bar', myOtherVar='something_else')
url = '%s?%s' % (reverse('my_view_name'), parameters.urlencode())
return redirect(url)

You can use request.REQUEST in that case: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.REQUEST
But it seems bad idea, cause it will be deprecated in django 1.7. You shouldn't pass GET parameter to another view as POST, it would be better to use POST in booth views.

Related

What is the cycle for Django's single Function Based Views(FBV) handling both GET and POST requests for this code?

I have been trying to get my head around the views and web requests but, couldn't understand how the below code works internally and couldn't figure out how the cycle of request-response works for this code.
def todos_add(request):
form = TodoForm(request.POST or None) #This is Django's in-built Form instance
if form.is_valid():
form.save()
return redirect('/') #redirects to the homepage
context = {"form" : form}
return render(request, "main/todos_create.html", context)
todos_create.html contains the code for displaying the forms and submitting the data. If the form is valid then it stores it in the database and redirects to the homepage.
Any help or link to the references is appreciated. Thanks.
form = TodoForm(request.POST or None) Whole logic happens here.
Whenever the view is called, it checks if there is any POST data, if it is the request is considered as POST request if there is no data submitted on the request it is considered a GET view.

Check in DeleteView if its post or get? django

Im trying to check either a user tried to enter a url by himself or he follows the urls and put the values needed in the form i build for him..
In some Ungeneric class, I can check that thing -
if request.method == 'GET':
But in DeleteView i can't do that thing so i don't know how to prevent from the user from doing bad things by input url by himself.
How can i use a function that does the same in generic View and checks if the user enter a url by himself or fill in the form?
It should be a POST, there isn't any need to check it yourself.
From the docs
The given object will only be deleted if the request method is POST. If this view is fetched via GET, it will display a confirmation page that should contain a form that POSTs to the same URL.
By default DeleteView does deletion only on POST request. So your user will not be able to delete items just making GET request.
But for your information all class based views(CBV) call dispatch method which then calls ether post or get depending on request.method.
You can add some logic directly in dispatch method or modify get and do your checks there
Example
class MyDeleteView(DeleteView):
def post(self, request, *args, **kwargs):
...
def get(self, request, *args, **kwargs):
# here you can make redirect to any url
...

How to write separate views for GET and POST

First of all I want both views use exact same URL because I don't want to make my URLConf more complicated. I want separate views for GET and POST to make my code cleaner. The code is something like this:
def view2 (request):
# handle POST request, possibly a ajax one
return HTTPRESPONSE(json_data, mimetype="Application/JSON")
def view1 (request):
if method == POST:
view2(request)
# What should I return here???
else:
# handle GET
return render(request, template, context)
My question is about the # What should I return here??? line. If I don't put a return there, error occurs:
not returning http response
But I already return an HTTP response in view2. How can I make this work?
Another, probably a bit cleaner way would be using class-based views
from django.views.generic import TemplateView
class View1(TemplateView):
def get(self, request, *args, **kwargs):
"""handle get request here"""
def post(self, request, *args, **kwargs):
"""handle post request here"""
def head(self, request, *args, **kwargs):
"""handle head request here. Yes, you can handle any kind of requests, not just get and post"""
Of course you can add common methods, __init__ (which is useless unless you are sure what you are doing), apply login_required (see this SO question) and pretty much everything you can do with django views (e.g. apply middleware, permissions, etc.) and python classes (e.g. inheritance, metaclasses/decorators, etc.)
Also, there's a whole bunch of generic class based view coming with Django to address common situations like list page, details page, edit page, etc.
You need to return the results of view2:
def view1 (request):
if request.method == 'POST':
return view2(request)
else:
# handle GET
return render(request, template, context)

django admin - overriding changelist_view for single entry models

I have a model for which i'll have one single instance, so i need to override the changelist_view to by-pass it (only if i have at least one record saved), and jump directly to change_view. i found snippet online and it works well for it, so i wrote my custom changelist_view:
def changelist_view(self, request, extra_context=None):
queryset = self.model.objects.all()
if queryset.count()>0:
try:
obj = queryset[0]
return self.change_view(request, str(obj.id), extra_context)
except IndexError:
pass
return super(MyModelAdmin, self).changelist_view(request, extra_context)
this works until I try to save. The difference from the normal change_view is in the url. the normal has the object id:
http://127.0.0.1:8000/admin/myapp/mymodel/2
instead with modified version i have:
http://127.0.0.1:8000/admin/myapp/mymodel/
if i try to save i got this error:
You called this URL via POST, but the URL doesn't end
in a slash and you have APPEND_SLASH set. Django can't redirect to
the slash URL while maintaining POST data. Change your form to
point to 127.0.0.1:8000/admin/myapp1/mymodel/None/ (note
the trailing slash), or set APPEND_SLASH=False in your
Django settings.
At the moment the only trick that works for me is a HttpResponseRedirect(url), with as url the change_view url hardcoded with object id.
is there a more elegant way?
thanks
Luke
You can change target URL the admin will redirect to after processing your edits by using the response_change method on your model admin. That receives the request and the changed object as parameters, and can return a redirect to a dynamically calculated URL.
def response_change(self, request, obj):
# call the parent version to collect messages for the user
original_response = super(MyModelAdmin, self).response_change(request, obj)
if "_popup" in request.POST:
return original_response
return HttpResponseRedirect(reverse("admin:myapp_mymodel_change", args=[obj.id]))
There's also a response_add, but I doubt you'll need that if you're using a singleton model. Likewise, there are ways to test for whether the user selected "save and add another", "save and continue editing" or just "save" but you probably don't care about that distinction for a singleton.
When using
def changelist_view(self, request, extra_context=None):
django will insert an action="None" in the Html output which causes the above mentioned error when submitting the post. Instead try
def changelist_view(self, request, extra_context=""):

Django class-based view - DeleteView - How to disable confirmation requirement

I am switching to the class-based views. I also use JavaScript to confirm any deletion on the client side. Django DeleteView requires a delete confirmation template which I don't care about.
Is there any simple way of disabling the confirmation on any kind of deletes in Django?
class EntryDeleteView(DeleteView):
model = Entry
success_url = reverse_lazy('entry_list') # go back to the list on successful del
template_name = 'profiles/entry_list.html' # go back to the list on successful del
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(EntryDeleteView, self).dispatch(*args, **kwargs)
You should make a POST query from clientside (with AJAX or POSTing a form). That's because if you'll allow to delete something by GET, your service will be vulnerable to CSRF. Someone will send your admin a in email or somehow else, and you'll be in trouble.
The DeleteView renders the confirmation page on GET and deletes the object if you use a POST or DELETE. If your JS does a POST to the url after confirmation it should work like you want.