I want to use Ajax in Django to handle the view of my checkout form after it has been submitted. After the form is submitted, I want it to go to :
return HttpResponseRedirect(reverse(str(next_page))+"?address_added=True") , i.e http://127.0.0.1:8000/checkout/?address_added=True
But for some reason, it is not going there. Rather it's being going to http://127.0.0.1:8000/checkout/?csrfmiddlewaretoken=W4iXFaxwpdtbZLyVI0ov8Uw7KWOM8Ix5GcOQ4k3Ve65KPkJwPUKyBVcE1IjL3GHa&address=123+Main+Street&address2=&state=MA&country=USA&zipcode=55525&phone=%28877%29+314-0742&billing=on
As a result, the form data is also not getting saved. I was thinking if it were because of the new version of Django.
What I want to do is that after they submit the place order button, the form is going to be None, i.e disappear and then I would add a credit card form there for payment. But it is not happening. What is wrong here? How can I do this or is there a better way to do this?
My forms.py:
class UserAddressForm(forms.ModelForm):
class Meta:
model = UserAddress
fields = ["address", "address", "address2", "state", "country", "zipcode", "phone", "billing"]
My accounts.views.py:
def add_user_address(request):
try:
next_page = request.GET.get("next")
except:
next_page = None
if request.method == "POST":
form = UserAddressForm(request.POST)
if form.is_valid():
new_address = form.save(commit=False)
new_address.user = request.user
new_address.save()
if next_page is not None:
return HttpResponseRedirect(reverse(str(next_page))+"?address_added=True")
else:
raise Http404
My orders.views.py:
#login_required()
def checkout(request):
try:
the_id = request.session['cart_id']
cart = Cart.objects.get(id=the_id)
except:
the_id = None
return redirect(reverse("myshop-home"))
try:
new_order = Order.objects.get(cart=cart)
except Order.DoesNotExist:
new_order = Order(cart=cart)
new_order.cart = cart
new_order.user = request.user
new_order.order_id = id_generator()
new_order.save()
except:
return redirect(reverse("cart"))
try:
address_added = request.GET.get("address_added")
except:
address_added = None
if address_added is None:
address_form = UserAddressForm()
else:
address_form = None
if new_order.status == "Finished":
#cart.delete()
del request.session['cart_id']
del request.session['items_total']
return redirect(reverse("cart"))
context = {"address_form": address_form, "cart": cart}
template = "orders/checkout.html"
return render(request, template, context)
My urls.py:
path('ajax/add_user_address', accounts_views.add_user_address, name='ajax_add_user_address'),
My checkout.html:
<form method="POST" action="{% url 'ajax_add_user_address' %}?redirect=checkout">
{% csrf_token %}
<fieldset class="form-group">
{{ address_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-dark" type="submit">Place Order</button>
</div>
</form>
I would personally split these up in two views, because they do different stuff.
But, if you want to keep it that way, you can do the following:
First of all, because you are making an AJAX Request, you should return a JsonResponse object.
In your view you can render the checkout.html and pass it as a context variable to your json response:
def add_user_address(request):
...
data = dict()
context = {
'address_form': form,
...
}
data['html_form'] = render_to_string("checkout.html",
context,
request=request)
return JsonResponse(data)
And in your $.ajax success function you can do the following
success: function(data) {
// console.log(data);
$("div-to-replace-html").html(data.html_form);
}
Related
How to realize checking 'name' for current user in forms.py in ValidationError('Same name already added, change name').
views.py
#login_required
def main_page(request):
form = URL_listForm(request.POST)
if request.method == "POST":
if form.is_valid():
name = form.cleaned_data['name']
if URL_list.objects.filter(user=request.user, name=name).exists():
return HttpResponse('Same name already added, change name')
new_post = form.save(commit=False)
new_post.user = request.user
new_post.save()
return HttpResponse("Data added")
return render(request, 'link/main.html', {'form': form})
If you want validate in database
#-------ADDED CODE
data_tmp = """SELECT count(*) from jobtest WHERE link = %s""", (line)
data_tmp = cur.fetchall()
#-------END ADDED CODE
if (data_tmp == 0 ) :
Not exist
add form with name
<input type="text" id="projectName" size="40" placeholder="Spot your project files">
<input type="button" id="spotButton" value="Spot">
when press post button and action to api you can get value in input field using request.form['Name']
if you want send data from server code to html
return render_template('index.html', data=userinfo)
and render as
{% userinfo %}
I'm entering a duplicate value (already saved in another instance of the same model) in my form to test the unique=True attribute. form.is_valid() returns 'False', as expected, but I don't receive any prompt in the template. Shouldn't I get prompted something like "obj with this value already exists"? The page simply reloads... What am I missing?
forms.py
def update_route(request, pk):
instance = Route.objects.get(id=pk)
if request.method == "POST":
form = RouteForm(request.POST)
if form.is_valid():
data = form.cleaned_data
instance.name = data['name']
instance.priority = data['priority']
instance.url = data['url']
return redirect('campaigns:routes_list')
form = RouteForm(instance=instance)
context= {
'form': form,
}
return render(request, "campaigns/route_form.html", context)
models.py
class Route(models.Model):
name = models.CharField(max_length=48)
priority = models.SmallIntegerField(choices=PRIORITY_LEVEL, default=0, unique=True)
url = models.URLField()
Template
<form method="post" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Submit">
</form>
Your update_route() view handles the condition in which the submitted form is valid (form.is_valid()), but not the condition in which the form is invalid.
The errors you are looking for are stored in the form object that you created with RouteForm(request.POST). The errors are generated when the is_valid() method is called.
This form object needs to be added to the context dict and rerendered to the user for the errors to surface. But your code currently overwrites that object with form = RouteForm(instance=instance), so the POST data and the related errors disappear.
One solution could be to handle it in the conditional statement:
if form.is_valid():
...
else:
context = {'form': form}
return render(request, "campaigns/route_form.html", context)
Another solution could be to create a conditional statement for GET requests, for example:
elif request.method == 'GET':
form = RouteForm(instance=instance)
My task to make pre-populated content of the page, like this:
content
content = "Sample text"
content = forms.CharField(widget=forms.Textarea, initial = content)
I need something like above, can you help me with realising that in code
class EditPageForm(forms.Form):
content = forms.CharField(widget=forms.Textarea)
def editPage(request, title):
content = util.get_entry(title)
if request.method == "POST":
form = EditPageForm(request.POST)
if form.is_valid():
new_content = form.cleaned_data["content"]
util.save_entry(title, new_content)
return HttpResponseRedirect(reverse("encyclopedia:entry", kwargs={'title': title}))
EditPageForm.initial = content
return render(request, "encyclopedia/editpage.html", {
"form": NewSearchForm,
"editPageForm": EditPageForm,
"title": title
})
Html code:
<form action="{% url 'encyclopedia:editpage' title=title%}" method="post">
<div>
<h3>Content:</h3>
{% csrf_token %}
{{ editPageForm }}
</div>
<input type="Submit">
</form>
You can use widget attributes to add placeholder text that you'd like in your form which can be dynamic and less lines to add.
class EditPageForm(forms.Form):
content = forms.CharField(widget=forms.Textarea(attrs={'placeholder': 'THIS IS MY PLACEHOLDER TEXT'}))
Thank everyone for help, the solution was found.
return render(request, "encyclopedia/editpage.html", {
"form": NewSearchForm,
"editPageForm": EditPageForm(initial={'content': content}),
"title": title
})
Now how that looks like,
You can pass an initial=… parameter [Django-doc] to the form with as value a dictionary with initial values:
from django.shortcuts import redirect
def editPage(request, title):
content = util.get_entry(title)
if request.method == 'POST':
editPageForm = EditPageForm(request.POST, initial={'content': content})
if form.is_valid():
new_content = form.cleaned_data['content']
util.save_entry(title, new_content)
return redirect('encyclopedia:entry', title=title)
else:
editPageForm = EditPageForm(, initial={'content': content})
return render(request, 'encyclopedia/editpage.html', {
'form': NewSearchForm,
'editPageForm': editPageForm,
'title': title
})
That being said, it might be better to work with models and a ModelForm [Django-doc] since this can remove a lot of boilerplate code.
I have a scheduling app where patients can register for appointments. When I submit the form for a new appointment, I get the value error.
views.py
def patient_portal(request):
appointments = Appointment.objects.filter(patient=request.user.patient.pid)
data_input = request.GET.get('date')
selected_date = Appointment.objects.filter(date = data_input).values_list('timeslot', flat=True)
available_appointments = [(value, time) for value, time in Appointment.TIMESLOT_LIST if value not in selected_date]
doctor = Patient.objects.get(doctor=request.user.patient.doctor).doctor
print(doctor)
if request.method == 'POST':
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
if form.is_valid():
form.save()
return redirect('../home/')
else:
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
return render(request, 'scheduling/patient.html', {"form" : form, "appointments" : appointments, "available_appointments" : available_appointments, "data_input": data_input, "doctor": doctor})
patient.html:
<form method="post" action="" id="timeslot" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
forms.py:
class AppointmentForm(forms.ModelForm):
class Meta:
model = Appointment
fields = ('doctor','patient','date','timeslot')
Your view must always return an HTTP response. At the moment, your code doesn't handle the case when request.method == 'POST', but the form is invalid.
You can fix your code by de-indenting the final return statement, to move it outside of the else block:
def patient_portal(request):
...
if request.method == 'POST':
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
if form.is_valid():
form.save()
return redirect('../home/')
else:
form = AppointmentForm(initial={'doctor': doctor,'patient': request.user.patient}, instance=request.user.patient)
return render(request, 'scheduling/patient.html', {"form" : form, "appointments" : appointments, "available_appointments" : available_appointments, "data_input": data_input, "doctor": doctor})
I'm using Django 2.0. This is my forms.py:
class PostcodeForm(forms.Form):
postcode = forms.CharField(required=True, widget=forms.TextInput(
attrs={
'placeholder': "enter a postcode",
}
))
def clean_postcode(self):
postcode = self.clean_data.get('postcode', '')
print('clean_postcode', postcode)
if postcode != 'something':
raise forms.ValidationError(_("Please enter a valid postcode"), code='invalid')
return data
And my views.py:
def index(request):
form = PostcodeForm()
context = {
'form': form
}
return render(request, 'index.html', context)
And my index.html:
<form class="form-inline" id="lookup_postcode" action="{% url 'lookup_postcode' %}" method="get">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.postcode.errors }}
{{ form.postcode }}
<button type="submit">Submit</button>
</form>
But when I type in any value other than 'something', the form still submits. I also don't see any print statements in the console, so it looks as though the validator just isn't being run.
What am I doing wrong?
At the moment you are always doing form = PostcodeForm(), for GET and POST requests. That means that the form is not bound to any data, so it will never be valid or have any errors.
In Django, a typical view to process a form looks something like this:
from django.shortcuts import redirect
def index(request):
if request.method == 'POST':
form = PostcodeForm(request.POST)
if form.is_valid():
# form is valid. Process form and redirect
...
return redirect('/success-url/')
else:
form = PostcodeForm()
context = {
'form': form
}
return render(request, 'index.html', context)
For this to work, you'll need to change your form method to 'post'.
<form class="form-inline" id="lookup_postcode" action="{% url 'lookup_postcode' %}" method="post">
If you keep the form method as 'get' then you'll need to bind the form to request.GET instead. You might want to add a check, otherwise you'll get errors for required fields when you first access the index view.
if 'postcode' in request.GET:
# bound form
form = PostcodeForm(request.GET)
else:
# unbound, empty form
form = PostcodeForm()
Use your form as below:
class PostcodeForm(forms.Form):
postcode = forms.CharField(required=True, widget=forms.TextInput(
attrs={
'placeholder': "enter a postcode",
}
))
def clean(self):
postcode = self.cleaned_data.get('postcode', '')
print('clean_postcode', postcode)
if postcode != 'something':
raise forms.ValidationError(_("Please enter a valid postcode"), code='invalid')
return super(PostcodeForm, self).clean()
Everytime you deal with the validity of the posted data, make sure to include form.is_valid() condition in your views.py.