django + ajax post form - django

i tru use ajax with django.
There are 2 forms. the first with the name and mail. and a quick form with a confirmation code that comes in the mail.
views.py
def get_name(request):
if request.method == 'POST':
user_code = generate_code(8)
subject = 'code'
message = user_code
form = NameForm(request.POST)
if form.is_valid():
Registration.objects.create(fio=request.POST['fio'],mail=request.POST['mail'])
send_mail(subject, message,settings.EMAIL_HOST_USER,[mail],fail_silently=False)
return JsonResponse({ 'form1': render_to_string( 'registers/endreg.html', {'form': NameForm1()},request=request ) })
else:
form = NameForm()
return render(request, 'registers/detail.html', {'form': form})
template (detail.html)
<form action="" method="post" autocomplete="off" id="my_form">
{% csrf_token %}
<div class="contact-form" >
<h1>{%trans 'Registers' %}</h1>
<div class="txtb">{{form.fio.label}} {{form.fio}}{{form.fio.help_text}}</div>
<div class="txtb">{{form.phone.label}} {{form.phone}}{{form.phone.help_text}}</div>
<input type="submit" value="{%trans 'send' %}" class="btn" id="btn">
</div>
</form>
I am hanging an event to submit this form
$(document).ready(function()
{ $("#my_form").submit(function(event)
{ event.preventDefault();
$this = $(this);
$.ajax({
type: "POST",
data: $this.serialize(),
success: function(data)
{ console.log(data);
var parent=$("#my_form").parent();
parent.html(data.form1);
},
error: function(data)
{ console.log(data);
$this.html(data);
}
});
});
});
ajax request works and get my 2 form (endreg.html)
<form action="endreg/" method="post" autocomplete="off" id="my_form2">
{% csrf_token %}
<div class="verification" >
<div class="ver">
{{form}}
</div>
<input type="submit" value="{%trans 'send' %}" class="btn1" >
</div>
</form>
views.py
def endreg(request):
if request.method == 'POST':
form = NameForm1(request.POST)
if form.is_valid():
code_use = form.cleaned_data.get("key")
try:
user = Registration.objects.get(code=code_use)
user.verification = True
user.save()
JsonResponse({'message': 'thanks.'})
except:
JsonResponse({'error': 'erorr.'})
else:
form = NameForm1()
return render(request, 'registers/endreg.html', {'form': form})
and 2nd ajax.
$(document).ready(function()
{ $("#my_form2").submit(function(event)
{ event.preventDefault();
$this = $(this);
$.ajax({
type: "POST",
data: $this.serialize(),
success: function(data)
{ console.log(data);
},
error: function(data)
{ console.log(data);
}
});
});
});
Now the question. why when I enter the code in the second form, the code is applied and a redirect to localhost:8000/endreg occurs with json .

Looks like your form is not valid, thats why it is loading the same page with the entered data. You should handle the failure condition for form.is_valid(). And also don't add the blank exception block for handling exceptions.
def endreg(request):
if request.method == 'POST':
form = NameForm1(request.POST)
if form.is_valid():
code_use = form.cleaned_data.get("key")
try:
user = Registration.objects.get(code=code_use)
user.verification = True
user.save()
messages.warning(request, u'thanks.')
except Registration.DoesNotExist as e: # Handling Exception for get()
print("NOT FOUND", e)
messages.warning(request, u'error.')
else: # if form is not valid
messages.warning(request, u'not valid.')
form = NameForm1() # reset the form
else:
form = NameForm1()
return render(request, 'registers/endreg.html', {'form': form})
In your HTML, you can render {{ form.errors }} as well.

Related

How can show variable in UI in django from view function?

I want to show value of pro in UI but not getting , here is my test view function code .value of pro is getting from previous function using django session variable.
#api_view(['GET', 'POST'])
def test(request):
pro = request.session.get('j')
print("Request ID from Index View : ", pro)
if request.method == "POST":
form = TestForm(request.POST)
if form.is_valid():
print("Form is Valid")
selected = form.cleaned_data.get('myfield')
print(selected)
else:
# rq = request_id["request_id"]
s = sql()
query = f"""update request_form_db.request_form_mymodel
set is_approved=1
where request_id = '{pro}' """
print(query)
s.update_query(query)
print("Updated Successfully")
form = TestForm()
else:
form = TestForm()
context = {'form': form, 'pro': pro}
return render(request, 'test.html', context)
Here is my html code test.html
<form action ="{% url 'test' %}" method="POST">
<div class="form_data">
{% csrf_token %}
<br><br>
{{form.myfield}}
<label><b>Git Id</b></label> <br><br>
<br><br>
{{form.pro}}
<input type="submit" value="Submit" class="btn btn-success" />
form.myfield returns what i want but value of pro variable not getting.please help
Just pass same key as you created in context. you dont have to use {{ form.pro }}
context = {'form': form, 'pro': pro}
In html you can render with:
{{ pro }}

Django view not sending context data to ReactJS/Axios application

It appears I have come across very strange behavior. I am building a ReactJS+Django 3.0 application. Here is the problem...
I have a <form onSubmit={handleSubmit}> that wraps the form on the frontend.
const handleSubmit = (e) => {
e.preventDefault();
axios.post(paths.login, qs.stringify({
email: emailVal,
password: passwordVal
}));
}
This works perfectly fine in sending data to the Django view! But when I try to then pass context variable through the Django view, it just fails completely. Meaning,
def login(request):
data = {}
'''
Handle Logging in
'''
if request.method == 'POST':
login_form = forms.LoginForm(request.POST)
if login_form.is_valid():
user = login_form.authenticate_user()
#login(request, user)
return redirect('home')
else:
data['errorMessage'] = ''
for field, errors in login_form.errors.items():
for error in errors:
data['errorMessage'] += error
print(data)
return render(request, 'index.html', context=data)
Given this, the data dictionary will be empty at first, but even when the print(data) shows that the data dictionary is populated, the context data that is sent to the index.html file is still empty.
WHY MIGHT THIS BE? I've been stuck on this forever.
I can work around this if I just use form submission instead of axios like this: <form method='POST'> However, I need to use axios. SOS
You can also use the Django messages framework for this, which might be a better option (assuming you are re-rendering the page after POST):
from django.contrib import messages
def login(request):
data = {}
'''
Handle Logging in
'''
if request.method == 'POST':
login_form = forms.LoginForm(request.POST)
if login_form.is_valid():
user = login_form.authenticate_user()
#login(request, user)
return redirect('home')
else:
error_message = ''
for field, errors in login_form.errors.items():
for error in errors:
error_message += error
messages.add_message(request, messages.ERROR, error_message)
return render(request, 'index.html')
Then in your template (this is an example using Bootstrap, but you can modify it to fit your needs):
{% if messages %}
{% for message in messages %}
{% if message.tags == 'error' %}
<div class="alert alert-danger alert-with-icon alert-dismissible fade show" role="alert">
{% else %}
<div class="alert alert-{{ message.tags }} alert-with-icon alert-dismissible fade show" role="alert">
{% endif %}
{{ message|safe }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endfor %}
{% endif %}
If you are sending data back as an AJAX JSON response instead:
from django.http import JsonResponse
def login(request):
data = {}
'''
Handle Logging in
'''
if request.method == 'POST':
login_form = forms.LoginForm(request.POST)
if login_form.is_valid():
user = login_form.authenticate_user()
#login(request, user)
return redirect('home')
else:
error_message = ''
for field, errors in login_form.errors.items():
for error in errors:
error_message += error
data['error_message'] = error_message
return JsonResponse(data)
else:
return render(request, 'index.html')
In your Axios code:
const handleSubmit = (e) => {
e.preventDefault();
axios.post(paths.login, qs.stringify({
email: emailVal,
password: passwordVal
}).then((response) => {
//do something with JSON response
}, (error) => {
//do something with JSON response
});
});

Login Required decorator not redirecting to login url | Django

#login_required decorator not redirecting me to the login page
When I click the add to cart button it doesn't redirect me to the login page. It just doesn't do anything. I tried the login required decorator in another function. Like the home view action. And when I try to access the home page it directly redirects me to the login page. But in the combo_add_to_cart it doesn't seems to work. But I have found something in the terminal. I have seen that when I click the add to cart button it first sends a post request of "POST /carts/cart/combo/add-to-cart/ " then it sends a get request "GET /accounts/login/?next=/carts/cart/combo/add-to-cart/"
accounts views.py
class Login(FormView):
form_class = LoginForm
success_url = '/'
template_name = 'accounts/login.html'
def form_valid(self, form):
request = self.request
next_ = request.GET.get('next')
next_post = request.POST.get('next')
redirect_path = next_ or next_post or None
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
user = authenticate(request, email=email, password=password)
if user is not None:
login(request, user)
if is_safe_url(redirect_path, request.get_host()):
return redirect(redirect_path)
else:
return redirect("/")
return super(Login, self).form_invalid(form)
cart views.py
#login_required(login_url='/accounts/login/')
def combo_add_to_cart(request):
combo_id = request.POST.get('combo_id')
if combo_id is not None:
try:
combo_obj = Combo.objects.get(id=combo_id)
except Combo.DoesNotExist:
return("carts:cart")
combo = combo_obj
cart_item, created = ComboCartItem.objects.get_or_create(
combo=combo,
user=request.user,
ordered=False
)
cart_obj, new_obj = Cart.objects.new_or_get(request)
if cart_obj.combo_item.filter(combo__id=combo.id).exists():
cart_item.quantity += 1
cart_item.save()
print("Cart Item Updated")
added = False
updated = True
# return redirect("carts:cart")
else:
cart_obj.combo_item.add(cart_item)
print("Combo Added")
added = True
updated = False
# return redirect("carts:cart")
# print(combo_id)
cartCount = cart_obj.get_cartItems()
print(cartCount)
if request.is_ajax():
print("Ajax Request")
json_data = {
"added": added,
# "not_added": not added,
"updated": updated,
# "not_updated": not updated
"ItemCount": cartCount
}
return JsonResponse(json_data, status=200)
# return JsonResponse("message: Error", status_code=400)
return redirect("carts:cart")
class ComboList(ListView):
template_name = 'products/list.html'
def get_context_data(self, *args, **kwargs):
context = super(ComboList, self).get_context_data(*args, **kwargs)
cart_obj, new_obj = Cart.objects.new_or_get(self.request)
context['cart'] = cart_obj
return context
def get_queryset(self, *args, **kwargs):
request = self.request
combo = Combo.objects.all()
return combo
combo-update.html
<form method="POST" action="{% url 'carts:combo_add_to_cart' %}" data-endpoint="{% url 'carts:combo_add_to_cart' %}" class="form add-ajax">
{% csrf_token %}
<input type="hidden" name="combo_id" value="{{ combo.id }}">
<span class="submit-span">
<button type="submit" class="btn btn-success">Add to Cart</button>
</span>
</form>
list.html
{% extends 'base.html' %}
{% block content %}
<div class="container">
<h1>Combos</h1>
<hr>
{% for obj in object_list %}
<b style="font-size: 1.5em;">{{ obj.title }} | Regular Rs.{{ obj.combo_regular_price }} | Sale Rs.{{ obj.combo_sale_price }}</b>
{% include "products/snippets/combo-update.html" with combo=obj %}
<br>
{% endfor %}
</div>
{% endblock %}
base.js
var comboForm = $(".add-ajax")
comboForm.submit(function(event){
event.preventDefault();
var thisForm = $(this)
var actionEndpoint = thisForm.attr("data-endpoint");
var httpMethod = thisForm.attr("method");
var formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data){
var submitSpan = thisForm.find(".submit-span")
if(data.added){
submitSpan.html('<button type="submit" class="btn btn-success">Add More?</button>')
swal({
title: "",
text: "Added to cart!",
icon: "success",
button: "Okay",
})
}else{
if(data.updated){
submitSpan.html('<button type="submit" class="btn btn-success">Add More?</button>')
}else{
submitSpan.html('<button type="submit" class="btn btn-success">Add to Cart</button>')
}
}
var cartCount = $(".cart-count")
cartCount.text(data.ItemCount)
console.log(data.ItemCount)
if(window.location.href.indexOf('cart') != -1){
refreshCart()
}
},
error: function(errorData){
swal({
title: "Opps!",
text: "An error occured!",
icon: "error",
button: "Okay",
})
console.log("No API")
console.log("error", errorData)
}
})
})
Traceback
[01/Jun/2020 19:05:26] "POST /carts/cart/combo/add-to-cart/ HTTP/1.1" 302 0
[01/Jun/2020 19:05:26] "GET /accounts/login/?next=/carts/cart/combo/add-to-cart/ HTTP/1.1" 200 4146
It was because of the javascript that I wrote!
Firs in my cart views.py file I added
def combo_add_to_cart(request):
combo_id = request.POST.get('combo_id')
if not request.user.is_authenticated:
if request.is_ajax():
print("Ajax Request")
json_data = {
"noUser": True,
}
return JsonResponse(json_data, status=200)
else:
if combo_id is not None:
try:
combo_obj = Combo.objects.get(id=combo_id)
In the ajax call of base.js I added a condition
if(data.noUser){
swal({
title: "Opps! You are not logged in",
text: "Redirecting......",
button: false,
})
setTimeout(function(){
window.location.href='/accounts/login/'
}, 1000)
}else{
if(data.added){
submitSpan.html('<button type="submit" class="btn btn-success">Add More?</button>')
swal({
title: "",
text: "Added to cart!",
icon: "success",
button: "Okay",
})
}else{
if(data.updated){
submitSpan.html('<button type="submit" class="btn btn-success">Add More?</button>')
}else{
submitSpan.html('<button type="submit" class="btn btn-success">Add to Cart</button>')
}
}
}
So now it works even without the login_required decorator.
Don't even need the js part. The answer was simple
I just replaced #login_required(login_url='/accounts/login/') with #login_required(login_url="accounts:login").
I don't know actually why it didn't work as the url was mapped properly. Now I just changed it to use the namespace and url name, and it works.

django + ajax send form

and at page i'm not see csrdI try after receiving one form to get another
views.py
def get_name(request):
if request.method == 'POST':
user_code = generate_code(8)
subject = 'ver code'
message = user_code
phone = request.POST['phone']
form = NameForm(request.POST)
if form.is_valid():
Registration.objects.create(fio=request.POST['fio'],mail=request.POST['mail'])
send_mail(subject, message,settings.EMAIL_HOST_USER,[mail],fail_silently=False)
return JsonResponse({ 'form1': render_to_string( 'registers/endreg.html', {'form': NameForm1() } ) })
else:
form = NameForm()
return render(request, 'registers/detail.html', {'form': form})
def endreg(request):
if request.method == 'POST':
form = NameForm1(request.POST)
if form.is_valid():
code_use = form.cleaned_data.get("key")
try:
user = Registration.objects.get(code=code_use)
user.verification = True
user.save()
messages.warning(request, u'thanks.')
except:
messages.warning(request, u'error.')
else:
form = NameForm1()
return render(request, 'registers/endreg.html', {'form': form})
and ajax
$(document).ready(function()
{ $("#my_form").submit(function(event)
{ event.preventDefault();
$this = $(this);
$.ajax({
type: "POST",
data: $this.serialize(),
success: function(data)
{ console.log(data);
$this.html(data.form1);
},
error: function(data)
{ console.log(data);
}
});
});
});
I am facing a CSRF token missing or incorrect problem. Because it is not transferred to form 2. how can I transfer this token to a new form
detatil.html it's html first page
{% extends 'base.html' %}
{% load i18n %}
{% block content%}
<div class="main-form">
<form action="" method="post" autocomplete="off" id="my_form">
{% csrf_token %}
<div class="contact-form" >
<h1>{%trans 'Регистрация' %}</h1>
<div class="txtb">{{form.fio.label}} {{form.fio}}{{form.fio.help_text}}</div>
<div class="txtb"> {{form.purpose.label}}{{form.purpose}}</div>
<div class="container" id="none">{{form.tso.label}}{{form.tso}}</div>
<div class="txtb">{{form.phone.label}} {{form.phone}}{{form.phone.help_text}}{{form.phone.errors}}</div>
<div class="txtb"> {{form.number_car.label}}{{form.number_car}}</div>
<div class="txtb"> {{form.date_visit.label}}{{form.date_visit}}</div>
<div class="txtb"> {{form.captcha.label}}<br>{{form.captcha}}{{form.captcha.errors}}</div>
<input type="submit" value="{%trans 'send' %}" class="btn" id="btn">
</div>
</form>
</div>
{% endblock %}
it's html secon page endreg.html
{% load i18n %}
{% block content%}
<form action="" method="post" autocomplete="off" >
{% csrf_token %}
<div class="verification" >
<div class="ver">
{{form}}
</div>
<input type="submit" value="{%trans 'send' %}" class="btn1" >
</div>
</form>
{%endblock%}
csrf token is on two pages, but when I look at the code in the browser, it does not appear when I add 2 forms using ajax
since you are using render_to_string, you need to pass request object to render_to_string. You can acheive it by:
def get_name(request):
if request.method == 'POST':
user_code = generate_code(8)
subject = 'ver code'
message = user_code
phone = request.POST['phone']
form = NameForm(request.POST)
if form.is_valid():
Registration.objects.create(fio=request.POST['fio'],mail=request.POST['mail'])
send_mail(subject, message,settings.EMAIL_HOST_USER,[mail],fail_silently=False)
return JsonResponse({ 'form1': render_to_string('registers/endreg.html', {'form': NameForm1()}, request=request) })
else:
form = NameForm()
return render(request, 'registers/detail.html', {'form': form})

Django form submission - avoid page redirect

I am using a django form to update some details. once the save changes is clicked the ajax call is made, view executed, ajax response sent, success code executed n the page reloads again. n on reload as form is no longer valid, the else part of from.is_valid() is executed.
if form.is_valid:
#do something
return HttpResponse(simplejson.dumps(response), mimetype='application/json')
else:
#do something
return render_to_response('ts.html', {'form': form}, context_instance = RequestContext(request))
I want to avoid the page reload on the successful form submission and jus return ajax response. How can achieve that?
I have changed my code and here is the view, template and jquery.
if request.POST:
if form.valid():
if credentials.correct():
resp = {'success': True}
return HttpResponse(simplejson.dumps(resp), mimetype='application/json')
else:
resp = {'success': False}
return HttpResponse(simplejson.dumps(resp), mimetype='application/json')
else:
print "error in form"
return render(request, 'manage_accounts.html', {'creds': creds, 'form': form})
else:
form = SomeForm()
return render(request, 'manage_accounts.html', {'creds': creds, 'form': form})
Template
<form action="/accounts/" method="POST" id="bitlychangeform">
<div id="ajaxwrapper">
{% csrf_token %}
{{ form.non_field_errors }}
<!--{% include "Change_bitly_form.html" %}-->
{{ form.as_p }}
<div class="clearfix">
<label></label>
<div class="input" style="float:right">
<input type="submit" id="save" value="Save Changes" class="btn btn-primary "/>
</div>
</div>
</div>
</form>
Jquery:
$(function(){
var form = $('#bitlychangeform');
form.submit(function(e) {
jQuery("#save").attr('disabled', true)
jQuery("#ajaxwrapper").load(
form.attr('action') + ' #ajaxwrapper',
form.serializeArray(),
function(data) {
jQuery("#save").attr('disabled', false)
alert(data);
});
return false;
e.preventDefault();
});
});
The page reload doesn't occur when i use Django form as {{ form.as_p }} but when i use a "custom template for form with fields as password char fields with ** and editable only after one clicks edit button", the form.valid() returns false.
I require that the django form functions as my custom template for form as i desire. Can anyone guide me.
You can handle this in your JavaScript by returning false on submission of form.
form.submit(){
#do something
#make AJAX call
#do something
return false;
}
I would guess you didn't override the default form submission behavior on the front end, and you are submitting your form normally.
Make sure that you supress the default behavior of form submission.
This page
provides a great example under templates/contact/form.html