The problem is when refreshing the page with an invalid form (with errors displayed on the page) I get "Confirm Form Resubmission" alert and hitting 'ok' I end up with the same invalid form with errors. This behavior seems a bit strange to me, I suppose I should get an empty form.
In case the form is submitted (by pressing the submit button) I get a POST request and process that POST request in my view function. I do check my form's validity. In case it is valid I HttpResponseRedirect to the success page, in case not, I respond with that invalid form (in order to not loose the users data and have errors displayed on the page). This is the expected behavior of the view function (at least to me).
BUT the problem is that the refresh also "triggers" POST request. This is strange, if someone could explain why refresh triggers that alert and sends a POST request, I'd be many thankful. I'm new to web and eager to understand what is going under the hood.
So, as in my view function I get the same POST than I have to go the same way as well as with the "submit button" case, right? I can't "distinguish" whether it was a submit or a refresh? I've dumped the request dict for both cases, those are identical.
What I'm missing here? I've done lot of search for this but couldn't get any answers. In almost every case I end up with a case of valid form with suggestion to use HttpResponseRedirect, all right, but what if the form is invalid? User has entered some invalid data then he/she decides to start with a new empty form. The only way now is to click on the url and hit enter. Shall he/she be able to do this with refresh?
Lot of thanks for your answers.
Regards,
Karen
P.S. Here is the code:
class TireFormView(FormView):
template_name = 'tire_form.html'
form_class = TireForm
success_url = '/tires/tire/thanks'
initial = {'make': MAKE_CHOICES[0][1]}
def get(self, request, *args, **kwargs):
form = self.form_class(request=request, initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request = request)
if form.is_valid():
return HttpResponseRedirect(self.success_url)
return render(request, self.template_name, {'form': form})
HTML
...<form action="">...
Related
This is my view
class UserRegistrationView(FormView):
template_name = "register/register_form.html"
form_class = None
extra_fields_form_page_slug = ""
email_template = "register/account_activation_email.html"
def get_form(self, form_class=None):
form = super().get_form(form_class)
add_extra_fields(
form.fields, form.helper.layout.fields, self.extra_fields_form_page_slug
)
return form
def get_extra_form(self):
return FormPage.objects.filter(slug=self.extra_fields_form_page_slug).first()
def form_valid(self, form):
user = form.save(commit=False)
user.is_active = False
user.save()
email = form.cleaned_data.get("email")
email_template = "register/account_activation_email.html"
send_confirmation_email(
self, "Activate Your Account", user, email, email_template
)
return render(self.request, "register/after_submission.html")
This is working fine (registration wise) but it's not from many other sides, because I have the registration form as a pop up window in the header, so it's available throughout the whole website, my problems are:
if the user had a successful registration they will be redirected to the specified template "after_submission" what I want is to stay on the same page and display a pop up with some message
if the user had an unsuccessful registration they will be redirected to the main template "register_form.html" with the errors displayed their, what I want is to stay on the same page and to display the error messages on the pop up form if the user opened it again
is this achievable using only Django?? or I must throw some JS in there, and if JS is the answer, can you give me a quick insight into how to do it?
You can redirect to the same page in your CBV :
from django.http import HttpResponseRedirect
return HttpResponseRedirect(self.request.path_info)
As stated in the comment your solution require Ajax and JS, you can however redirect to the same page but that will make a new request and refresh the whole page which might no be ideal for you.
There is a tutorial to work with Django and Ajax Ajax / Django Tutorial
I have a Django custom form classed-based view. Under normal conditions I want it to be accessible to both authenticated and logged out or anonymous visitors. However, under certain conditions I'd like it to alert the user they need to login to submit the form (and redirect them). Example:
class CustomFormView(FormView):
...
def form_valid(self, form):
user = self.request.user
req_id = self.request.GET.get("req_id")
if req_id:
errors = False
if not user.is_authenticated():
messages.error(self.request, "You must be logged in to fill out this form. Please sign in, then visit this link again.")
errors = True
# redirect
try:
...
if errors:
ctx = self.get_context_data()
return self.render_to_response(ctx)
I'm aware of LoginRequiredMixin (docs) as well as a decorator #method_decorator(login_required) but I don't want to apply it at the view level or to the entire form_valid() function, only check login state when if req_id condition is met. Currently the view's not executing my if not user.is_authenticated(): so my attempt isn't correct. Is there a way to accomplish this within form_valid()? thanks
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.
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.
I'm using django-allauth, and trying to use one form to fill in initial data on the signup form. So, say there is a form on the home page where you fill in your email address, and that form posts to the signup form, and we just want the email address you filled in to be set as the initial data for the second form.
The way I've been trying to do it is by extending the SignupView class:
class MySignupView(SignupView):
def post(self, request, *args, **kwargs):
if not request.POST.get('submit'):
email_initial = request.POST.get("email_initial")
self.initial = {"email":email_initial}
form_class = self.get_form_class()
form = self.get_form(form_class)
return self.render_to_response(self.get_context_data(form=form))
else:
return super(MySignupView, self).post(self, request, *args, **kwargs)
I'm sure that the code after "if not request.POST.get('submit'):" is being run when I post to the signup form from the first form. I want email_initial to be set as the initial email on the signup form. The problem I'm having is that the second form is being validated as if it were submitted itself. This code:
form_class = self.get_form_class()
form = self.get_form(form_class)
return self.render_to_response(self.get_context_data(form=form))
Is exactly the same as the code that gets run on GET for the form. I'm able to set initial data when overriding the GET function, but not the POST function. Is there any way to just display the form with some initial data on POST, without validating the form?
I found a solution to this problem. Instead of posting the first form to the second one, I posted to an intermediary view, saved the email address in the session, then redirected to the allauth signup form. I extended the allauth signup form to check the session for this initial email address.
The first form action is:
{% url 'my_signup_email' %}
In urls.py:
url(r'^accounts/signupemail/', 'projectname.views.signup_email',name='my_signup_email'),
url(r'^accounts/signup/?', 'projectname.views.signup', name='my_signup'),
In views.py:
def signup_email(request):
request.session['email_initial'] = request.POST.get('email')
return redirect('my_signup')
class MySignupView(SignupView):
def get(self, request, *args, **kwargs):
self.initial = {"email":request.session.get('email_initial')}
return super(MySignupView, self).get(self, request, *args, **kwargs)
signup = MySignupView.as_view()
If anyone has any criticism of this solution, I would be interested to hear it.