I have three forms like this:
<form id = "myForm" style="list-style-type: none;display: none;" class="form_class">
{% csrf_token %}
item1:
<input type="text" name="item1" style="width:10%;height:5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br>
item2:
<input type="text" name="item2" style="width:10%;height: 5%">
<br><br>
<input id="close_form" type="reset" value="reset">
</form>
Below is the code I used to click the button so it will go the javascript method:
<form method="post">
{% csrf_token %}
<input class="bg-yellow text-white" value="RUN" name="runModel" type="submit"
onclick="sendValuesToBack()">
</form>
In the JavaScript method, I'm getting all three form's values. I want to send those to the Django Framework to perform several operations. How do I send this data from JavaScript to Django?
You can do this using JQuery Ajax in the template and by creating an "API view" in your views.py that is basically just a regular view that returns a JSONResponse after checking to verify the request is Ajax. As an example of the "API" option, using JQuery:
In your urls.py:
...
path('/api/post_form/', post_form_api, name="post_form_api"),
...
For the POST method in your views.py:
from django.http import JsonResponse
def post_form_api(request):
data = {}
if request.method == "POST":
form = MyDjangoForm(request.POST)
# do something with the form data
...
if successful:
data['result'] = True
data['message'] = "Form data saved"
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
In your template:
<script type="text/javascript">
$("#myFormSubmitButton").click(function(){
var form_data = $("#formID").serialize();
$.ajax({ url: '{% url 'post_form_api' %}',
type: "POST",
dataType: "json",
data: form_data,
cache: false
}).done(function(data) {
if (data.result === true){
alert(data.message);
}
});
});
});
</script>
Alternatively, you can get the fields from all your forms individually, then send them in the Ajax data like so:
<script type="text/javascript">
$("#myFormSubmitButton").click(function(){
var csrfToken = $("input[name='csrfmiddlewaretoken']");
var item_1 = $("#item1").val();
var item_2 = $("#item2").val();
...
$.ajax({ url: '{% url 'post_form_api' %}',
type: "POST",
dataType: "json",
data: {'item1': item_1, 'item2': item_2, 'csrfmiddlewaretoken':csrfToken.val()},
cache: false
}).done(function(data) {
if (data.result === true){
alert(data.message);
}
});
});
});
</script>
If you have multiple forms you want to use this API for and are only submitting them one at a time, you can put a hidden field in your forms and do something like this in your views.py:
def post_form_api(request):
data = {}
if request.method == "POST":
form_name = request.POST.get('form_name', None) #the name of the hidden field identifying the form
if form_name is not None:
if form_name == "MyDjangoForm":
form = MyDjangoForm(request.POST)
# do something with the form data
...
elif form_name == "MyOtherForm":
form = MyOtherForm(request.POST)
# do something with the form data
...
if successful:
data['result'] = True
data['message'] = "Form data saved"
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
If you are getting the data from all three forms in your template at once, you can do something like this in your views.py after sending all of the data using JQuery Ajax as above:
def post_form_api(request):
data = {}
if request.method == "POST":
item_1 = request.POST.get('item_1', None)
item_2 = request.POST.get('item_2', None)
item_3 = request.POST.get('item_3', None)
...
# do something with the collected form data here
...
if successful:
data['result'] = True
data['message'] = "Form data saved"
if request.is_ajax():
return JsonResponse(data)
else:
return HttpResponseBadRequest()
When you are sending data via POST don't forget to pass along your CSRF token as in the example above (it should be in the serialized form data). This assumes you have a form on the page you can get it from, otherwise you can use something like this to get it:
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
If you don't want to deal with the CSRF token, you can mark the view with the #csrf_exempt decorator and remove the 'csrfmiddlewaretoken' data element from the Ajax call in the template, but it may not be ideal or the most secure. An example of that:
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
#csrf_exempt()
def post_form_api(request):
...
Now, without knowing more, this is basically just pseudocode (plus I just wrote this off the top of my head so it may have errors). This also depends on what type of views you are using, and whether you want to use the Django REST framework or not (the examples above are for regular, not class-based, views and do not require the Django REST framework to work).
If you post more details I can update my answer, but I think this should get you started.
Related
This my first time working with an api that returns a result. So I am using a post request to get information from the user in a form:
<form action="{{url_for('international.get_grade_data')}}" method="POST">
........
</form>
the endpoint looks like this:
#international.route("/grade_data", methods=["GET", "POST"])
#tfa_login_required
def get_grade_data():
if request.method == "POST":
grading_system_from= request.form.get('country_from')
grading_system_to = request.form.get('country_to')
users_grade= request.form.get('user_grade')
grade_request= {"free_grade": users_grade, "country_to": grading_system_to, "country_from": grading_system_from}
grade= grade_comparison_tool(grade_request)
return jsonify(
grade_request = grade
)
This data is sent to an api and then returns a result in JSON.
but when the user clicks on the submit button the user gets redirected to the json result.
I would like to get the result in the URL and then display the result on the webpage without redirect to the json result. How do I achieve this? I have gone online to know about POST and GET but not still clear.
Regarding the question I have been able to find a solution by changing the strategy,
firstly, I prevented the default action of the form:
<form action="#" onsubmit="return false" method="POST">
........
</form>
secondly, in the JS file I used an AJAX call to send the data from the form and received the result back in a click event:
function dataLoading(){
let datasetDict = {
"free_grade": free_grade.value,
"country_from": countryFrom.value,
"country_to": countryTo.value
}
$.ajax({
type: "POST",
url: '/international/grade_data',
data: JSON.stringify(datasetDict),
success: function(data_result, status){
console.log( JSON.stringify(data_result) + ': ' + status)
},
contentType: 'application/json;charset=UTF-8',
dataType: 'json'
});
}
document.getElementById('convert-button').addEventListener('click', dataLoading)
modified the flask python code:
#international.route("/grade_data", methods=["POST"])
#tfa_login_required
def get_grade_data():
if request.method == "POST":
user_grade_data =request.get_json()
grade = grade_analy(user_grade_data)
return jsonify(grade)
I have a sort of twitter like button function in my app such that, when the button is clicked, it triggers an AJAX call and performs the action specified in the views. However, when i click the button, it does not perform action in views. The code reaches the 'like view' but does not execute anything after 'if request.POST:'. Please help.
Menu.html
<form action="{% url 'like'%}" id="plt_{{menu.id}}" data-id="{{menu.id}}" method="post">
{%csrf_token%}
<input name="menu_id" type="hidden" value="{{ menu.id }}">
<div class="like-button" id="btn_{{menu.id}}"></div>
</form>
<script>
$('.like-button').on('click', function () {
var id = $(this).attr('id');
id = id.replace('btn_','');
$(this).toggleClass('animate').promise().done(function () {
var link = $("#plt_"+id).attr('action')
$.ajax({
type: 'POST',
url: link,
headers: {'X-CSRFToken': '{{ csrf_token }}'},
})
});
});
</script>
Views.py
def like(request):
print('reached') //this prints
if request.POST:
menu = Menu.objects.get(pk=request.POST.get('menu_id'))
//execute code to like
return HTTPResponse('')
Maybe you want to check
if request.is_ajax() and request.method== "POST":
request.POST is a dict .Empty here because body is empty in your request.
Empty dicts are treated like False by python like
if {}:
print("Hello World")
Above won't print anything
But below works
if {"hi" : "there"}:
print("Hello World")
And docs suggests this check is wrong if request.POST:
It’s possible that a request can come in via POST with an empty POST
dictionary – if, say, a form is requested via the POST HTTP method but
does not include form data. Therefore, you shouldn’t use if
request.POST to check for use of the POST method; instead, use if
request.method == "POST" (see HttpRequest.method).
It is fairly simple, use serialize() of jquery. Serialize function will take all the values from the form, even csrftokenmiddleware which is hidden input type. So, doing so you will be able to handle post request successfully. Use sthg like this:
<script>
$('.like-button').on('click', function () {
var id = $(this).attr('id');
id = id.replace('btn_','');
$(this).toggleClass('animate').promise().done(function () {
var link = $("#plt_"+id).attr('action');
var data = $("#plt_"+id).serialize(); // It will serialize all form data
$.ajax({
type: 'POST',
url: link,
data: data
});
});
});
</script>
In views.py do as you do for other request. serialize()
I am trying to display a User's name on top of a box where they enter their Employee # in a form, without having to refresh the page.
For example, they enter their # and then after they click/tab onto the next field, it renders their name on top, which comes from the database, so the user knows they've entered the correct info. This name is stored in a separate model, so I try to retrieve it using the "id/number".
I am not too familiar with AJAX but after reading a few similar questions it seems like an AJAX request would be the most appropriate way to achieve this. I tried to make a function get_employee_name that returns the name of the person based on the way I saw another ajax request worked, but I'm not sure how to implement this so it displays after the # is entered.
My page currently loads, but there is never a call to the function/url that searches for the name to display it on the page (because there isn't one). I'm not sure where I might be missing the part that connects these two areas of the code or how to connect these, as I am not too familiar with html and Django, most of this has been trial and error.
models.py
class EmployeeWorkAreaLog(TimeStampedModel, SoftDeleteModel, models.Model):
employee_number = models.ForeignKey(Salesman, on_delete=models.SET_NULL, help_text="Employee #", null=True, blank=False)
work_area = models.ForeignKey(WorkArea, on_delete=models.SET_NULL, null=True, blank=False)
station_number = models.ForeignKey(StationNumber, on_delete=models.SET_NULL, null=True, blank=True)
This is the model where the name is stored
alldata/models.py
class Salesman(models.Model):
slsmn_name = models.CharField(max_length=25)
id = models.IntegerField(db_column='number', primary_key=True)
I was reading I can add to the "attrs" in the widget an 'onchange' part, but I am not too familiar with how to approach this and tying it to the ajax request from forms and not the html.
forms.py
class WarehouseForm(AppsModelForm):
class Meta:
model = EmployeeWorkAreaLog
widgets = {
'employee_number': ForeignKeyRawIdWidget(EmployeeWorkAreaLog._meta.get_field('employee_number').remote_field, site, attrs={'id':'employee_number_field'}),
}
fields = ('employee_number', 'work_area', 'station_number')
views.py
def enter_exit_area(request):
form = WarehouseForm(request.POST or None)
if form.is_valid():
# Submission stuff/rules
return render(request, "operations/enter_exit_area.html", {
'form': form,
})
def get_employee_name(request):
employee_number = request.GET.get('employee_number')
try:
employee = Salesman.objects.get(id=employee_number)
except Salesman.DoesNotExist:
return JsonResponse({'error': 'Employee not found'}, status=404)
employee_name = employee.slsmn_name
return JsonResponse({'employee_name': employee_name})
urls.py
urlpatterns = [
url(r'enter-exit-area/$', EnterExitArea.as_view(), name='enter_exit_area'),
path('get-employee-name/', views.get_employee_name, name='get_employee_name'),
]
The ajax request I tried to create is at the end of this html. I modified a similar request I found, but it does not actually display anything on the screen, not sure if I'm missing an area where the request is actually never being called, as I am not too familiar with how these types of requests work.
enter_exit_area.html
{% extends "base.html" %}
{% block main %}
<form id="warehouseForm" action="" method="POST" novalidate >
{% csrf_token %}
<div>
<div>
<!-- Here is where I would want the name to render after the user enters their number and tabs out -->
{{ form.employee_number.help_text }}
{{ form.employee_number }}
</div>
<div>
{{ form.work_area.help_text }}
{{ form.work_area }}
</div>
</div>
<div>
<div>
<button type="submit" name="enter_area" value="Enter">Enter Area</button>
</div>
</div>
</form>
<script>
$("#id_employee_number").change(function () {
var employee_number = $(this).val();
var url = $("#warehouseForm").data("employee-name");
$.ajax({
url: url,
type:'GET',
data: {
'id': employee_number
},
success: function (data) {
var employee_name = data['employee_name'];
$('#employee_name').text(employee_name);
},
error : function (data) {
var error_message = data['error'];
$('#employee_name').text(error_message);
}
});
});
</script>
{% endblock main %}
How can I call the function from the HTML? Could I do it in such a way that when the user enters 6 numbers it checks? (All employee numbers are 6 digits)
The url has to be the endpoint url which you defined in your url.py file
<script>
$("#id_employee_number").change(function (e) {
e.preventDefault();
var employee_number = $(this).val();
var url = $("#warehouseForm").data("employee-name");
$.ajax({
url: "/get_employee_name", // Here
type:'GET',
data: {
'id': employee_number
},
success: function (data) {
var employee_name = data['employee_name'];
$('#employee_name').text(employee_name);
},
error : function (data) {
var error_message = data['error'];
$('#employee_name').text(error_message);
}
});
});
</script>
You can append to your GET request a url parameter like: /get-employee-name/<your employee number here>
I recommend taking a look at URL Dispatcher to create url parameters within your django url definitions
I also recommend using underscores NOT dashes in your url definitions.
So a pseudo working config would be
urls.py
urlpatterns = [
url(r'enter-exit-area/$', EnterExitArea.as_view(), name='enter_exit_area'),
path('get_employee_name/<int:employeeNum>', views.get_employee_name, name='get_employee_name'),
]
views.py
def get_employee_name(request, employeeNum): #You get the employeeNum variable from urls.py
try:
employee = Salesman.objects.get(id=employee_number)
except Salesman.DoesNotExist:
return JsonResponse({'error': 'Employee not found'}, status=404)
employee_name = employee.slsmn_name
return JsonResponse({'employee_name': employee_name})
script
<script>
$("#id_employee_number").change(function () {
var employee_number = $(this).val();
var employeeNum = $("#warehouseForm").data("employee-name");
$.ajax({
url: `/get_employee_name/${employeeNum}`,
type:'GET',
success: function (data) {
var employee_name = data['employee_name'];
$('#employee_name').text(employee_name);
},
error : function (data) {
var error_message = data['error'];
$('#employee_name').text(error_message);
}
});
});
</script>
I am attempting to get an Ajax POST to to send data to my view so I can manipulate my data there, when I click on a div with class up-arrow.
Problem is, when I click said div and print request.POST in my view file, I am getting a POST object that contains <QueryDict: {}>. Empty! I can't seem to figure out why my the POST request isn't sending my data through.
Here is my HTML...
{% for i in post.posts %}
<li>
<div>
<div class='up-arrow'>
</div>
{{i}}
</div>
</li>
{% endfor %}
Here is my AJAX/jQuery...
$(document).ready(function(){
$('.up-arrow').click(function(){
$(this).hide()
console.log('click')
$.ajax({
headers: {
'Content-Type':'application/json',
'X-CSRFToken': getCookie('csrftoken')
},
url: 'voteuppost',
type: 'POST',
data: {'dane': 123456789101112},
success: function(data) {
alert('success!')
},
error: function(){
alert('fail')
}
})
return false
});
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
})
Here is my view...
class VoteUpPost(View):
def post(self, request):
print(request.POST)
return JsonResponse({'status': True})
Here is my url route...
url(r'^voteuppost$', VoteUpPost.as_view()),
Things I have tried...
1) I used GET instead of POST and I am able to get the data value using request.GET.get('dane')
1) Tried using request.POST.data and request.POST.DATA and get the following... AttributeError: 'QueryDict' object has no attribute 'data'
and I also get a 'fail' alert.
How do I send my data over to my view via a POST request and then access the data within?
When posting JSON data with application/json you need to use request.body instead of request.POST.
Like so:
class VoteUpPost(View):
def post(self, request):
print(request.body)
data = json.loads(request.body)
return JsonResponse({'status': True})
Also as Jacques mentioned, make sure to update your js to pass a JSON string.
Change:
data: {'dane': 123456789101112},
To:
data: JSON.stringify({'dane': 123456789101112}),
Django request can only parse application/x-www-form-urlencoded and
multipart/form-data to request.POST. For other content types you have to use request.body property. for assertion of content type you can get the content type from request.META.get('CONTENT_TYPE')
def sample_view(request):
if request.META.get('CONTENT-TYPE') == 'application/json':
data = json.loads(request.body)
return JsonResponse({'any-message':'Hello'})
So I have this code below.
This is my jquery/ajax script
$(function() {
$(".reply").click(function(){
var id = $(this).attr("id");
var element = ".comment_replies#" + id;
$(element).show();
$(".submit_reply#" + id).click( function(event) {
event.preventDefault();
var reply_box = ".reply_box#" + id
var data = $(reply_box).val
$.ajax({
type : "POST",
url : "{{url_for('main.HomePage')}}",
data: JSON.stringify(data, null, '\t'),
contentType: 'application/json;charset=UTF-8',
success: function(result) {
console.log(result);
console.log(data)}
})
})
})
})
here is the form:
<form class = "reply_form" action="#" method="post">
<input class = "reply_box" type="text" placeholder ="write a reply" name="reply" id = "{{'id_' +com.id|string}}">
<input type="submit" class = "submit_reply" value = "reply" id = "{{'id_' +com.id|string}}">
<input type="hidden" value="{{com.id}}" name = "form_id">
</form>
and if I do:
if request.json["data"] in my HomePage view it somehow doesn't pass
because usually i'd just go if request.form when submitting the form the usual way. here is my homepage view
if request.json["data"] and request.method == "POST":
return request.json["data"]
it's only a test to see if it return what I want it too and it fails.
am I suppose to have extra imports for json? because I don't have any.
I also see this error on firebug:
POST http://127.0.0.1:5000/homepage
400 BAD REQUEST
11ms
I could submit the form the usual way but I wanna try submitting the form and appending the info without a page refresh.