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.
Related
I have a class-based view in Django.
I have implemented a method get_context_data. A user can log in or update his/her data and is redirected to a class-based view template.
I want the information of the logged-in user inside the class-based view. I'm not rendering the view, just re-directing. Is there any approach like saving the data in memory during computation or global variables so that it can be accessed anywhere in the views.py.
if the user is logging in using the authenticate/login method, and you have the SessionMiddleware loaded as you should, then the user information should be in your request.user object.
In a class-based View object you can read the request like so:
class SomeView(View):
def get(self, *args, **kwargs):
user = self.request.user
#recommended: check if the user is authenticated, ie, not anonymous.
if user.is_authenticated:
check_something(user) #do whatever you need.
in the case of TemplateView subclasses (I assume, since you mention get_context_data) is the same:
class SomeTemplateView(TemplateView):
def get_context_data(self, *args, **kwargs):
if self.request.user and self.request.user.is_authenticated:
#do something
Globals and other things won't work in a Django service, it might work on development, but in production, your user's request could be handler by different python processes altogether and memory won't be shared between them.
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
...
I'm building a job application form. A logged-in user is permitted to apply to the job only once (there's only one job). At the moment, a user is able to directly access the job application (FormView), by typing in its specific URL, and an error message is thrown AFTER the user submits the form. To achieve this, I'm doing a couple of things:
(1) Wrapping the job application view in login_required()
(2) Using the form_valid() method to check whether or not a user has already submitted an application to this specific job via:
def form_valid(self, form):
form = form.save(commit=False)
form.user = self.request.user
if Application.objects.filter(user=user_id):
messages.error(self.request, 'Sorry, our records show that you have already applied to this job.')
return redirect('/')
But I'd rather not permit them to reach the page at all. Instead, I want to check whether or not a user has already applied (during the request), and redirect them away from the form, if they have already applied. I have limited access to logged-in users that pass a test in the past, using something like:
def job_application_view(request):
active_user = request.user
if Application.objects.filter(user=active_user):
return HttpResponse("Some response.")
However, I can't seem to figure out how to access request via the FormView Class-Based View. I'm sure I'm missing something simple. Perhaps another method of FormView I'm missing?
You can still use decorators on class-based views, but they are slightly more difficult to apply than function-based views.
class ApplicationView(FormView):
# ...
#method_decorator(user_passes_test(job_application_view))
def dispatch(self, *args, **kwargs):
return super(ApplicationView, self).dispatch(*args, **kwargs)
Answering specific parts of your post...
I have limited access to logged-in users that pass a test in the past
With class-based views, you need to decorate the url or decorate the dispatch method with any decorators you are interested in applying.
However, I can't seem to figure out how to access request via the FormView Class-Based View. I'm sure I'm missing something simple. Perhaps another method of FormView I'm missing?
You can access the request with self.request
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.
To delete an object I inherit from DeleteView which has 3 steps (user clicks on delete, goes to confirm page, click yes again, redirected to success page) How can I make it more inline (user clicks delete, alert window pops up asking user to confirm, user confirms, the object is gone, user is still on the same page)
url(r'^(?P<username>\w+)/recipientbank/delete/(?P<pk>\d+)/$', RecipientBankAccountDeleteView.as_view(model=RecipientBankAccount)),
url(r'^(?P<username>\w+)/recipientbank/delete/(\d+)/success/$',recipientbank_deleted,name='recipientbank_deleted'),
class RecipientBankAccountDeleteView(DeleteView):
form_class = RecipientBankAccountForm
success_url='success'
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.delete()
return HttpResponseRedirect(self.get_success_url())
def recipientbank_deleted(request, username, public_profile_field=None,template_name='main/recipientbankaccount_deleted.html',extra_context=None):
return render(request, template_name)
You should use django-piston to create RESTful APIs and make an AJAX call from your page to delete your django objects.
You can read about RESTful here: http://en.wikipedia.org/wiki/Representational_State_Transfer
and django-piston here: https://bitbucket.org/jespern/django-piston/wiki/Home
I've heard that you could achieve this with Generic Views starting django version 1.3, but I haven't used it.