How to send javascript variable to django - javascript

I am building a web app, where a user can set a value to a specific number. It looks like that
<button type="button" class="btn btn-outline-primary" onclick="decrease()"> +1 </button>
<button type="button" class="btn btn-outline-primary" onclick="increase()"> -1 </button>
<script>
var a = 0;
function increase()
{
a--;
document.getElementById("val").innerHTML = a;
}
function decrease()
{
a++;
document.getElementById("val").innerHTML = a;
}
</script>
Now I would like add an other button like:
<button type="button" class="btn btn-outline-primary" onclick="send()"> send it </button>
But I don't really now how to send it (maybe I should use axaj and POST). I would like to access the value from my django view.py file and process it further and send it back (here it's GET).
How can I do it?
Appreciate any help here

So I have found out how to do it.
html:
<button id="post-btn" class="btn btn-outline-primary"> test </button>
js:
var data = new FormData()
var a = 50;
var b = 100;
const button = document.getElementById('post-btn');
button.addEventListener('click', async _ => {
try {
data.append( "json", JSON.stringify(
{
'data1': a, /* var a = whatever */
'data2': b /* var b = whatever */
}
));
const response = await fetch('{% url "pulsox" %}', {
method: 'post',
headers: {
"X-Requested-With": "XMLHttpRequest"
},
body:data
});
}
catch(err)
{ window.alert('sth was wrong!'); }
});
view.py
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
#method_decorator(csrf_exempt, name='dispatch')
def pulsox_view(request, *args, **kwargs):
if request.method == 'POST':
print(request.POST.get('json'))
a = request.POST.get('json')
print(a)
if request.POST.get( youritem):
# do you stuff
return render(request, your_page ,obj)
else:
return render(request,your_page,obj)
return render(request,your_page,obj)

Related

Cannot Edit Form in Javascript With Django

I'm trying to edit a form on this site with Django, and save the edits using Javascript (but not mandating a page refresh).
When the user clicks 'edit' on the page, nothing happens. No console errors. I think the issue is in the Javascript function edit_post. I'm new to using Javascript with Django. Any help is appreciated.
Relevant urls.py
path('edit_post/<str:id>', views.edit_post, name="edit_post"), #before was pk not id
path('edit_post/', views.edit_post),
path("profile/<str:username>", views.profile, name="profile"),
Javascript
function edit_handeler(element) {
id = element.getAttribute("data-id");
document.querySelector(`#post-edit-${id}`).style.display = "block";
document.querySelector(`#post-content-${id}`).style.display = "none";
// everything above this works and opens up the form for editing
edit_btn = document.querySelector(`#edit-btn-${id}`);
edit_btn.textContent = "Save";
edit_btn.setAttribute("class", "text-success edit");
if (edit_btn.textContent == "Save") {
edit_post(id, document.querySelector(`#post-edit-${id}`).value); //here
edit_btn.textContent = "Edit";
edit_btn.setAttribute("class", "text-primary edit");
}}
function edit_post(id, post) {
const body = document.querySelector(`#post-content-${id}`).value;
fetch(`/edit_post/${id}`, {
method: "POST",
body: JSON.stringify({
body:body
})
}).then((res) => {
document.querySelector(`#post-content-${id}`).textContent = post;
document.querySelector(`#post-content-${id}`).style.display = "block";
document.querySelector(`#post-edit-${id}`).style.display = "none";
document.querySelector(`#post-edit-${id}`).value = post.trim();
});
}
Relevant html
<span id="post-content-{{i.id}}" class="post">{{i.text}}</span> <br>
<textarea data-id="{{i.id}}" id="post-edit-{{i.id}}"
style="display:none;" class="form-control textarea" row="3">{{i.text}}</textarea>
<button class="btn-btn primary" data-id="{{i.id}}" id="edit-btn-{{i.id}}"
onclick="edit_handeler(this)" >Edit</button> <br><br>
views.py
def edit_post(request, id):
post = Post.objects.get(id=id)
form = PostForm(instance=post)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
form.save()
return JsonResponse({}, status=201)
else:
if request.method == "GET":
form = PostForm(instance=post)
form_for_post = {'form': PostForm()}
return render(request, "network/make_post.html", {
"post": post,
"form_for_post": form,
})

Request in Flask return empty data [duplicate]

This question already exists:
Problem with the form return empty data in Flask [duplicate]
Closed 1 year ago.
I am building an application in Flask and JavaScript and I have a problem with the Ajax in Flask. How can I handle it in Flask i mean using if. I use if request.method=='POST' but I have the form too and when I try if 'form-submit' in request.form and print nazwa_event = request.form.get('nameOfEvent') this return me nothing I mean it is empty.
Code JavaScript:
$("#search-button_event").click(function () { // make ajax request on btn click
$.ajax({
type: "POST",
url: "/mapaa", // url to the function
data: {
nameevent: $("#name_of_event").val(), // value of the form
},
success: function (response) {
id = (response['id']);
nazwa = (response['name']);
droga = (response['route']);
droga_without = droga.replaceAll("{","")
droga_with2 = droga_without.replaceAll("}","")
var string = droga_with2.split(',');
let marker_event = L.marker(array[0]).bindPopup()
marker_event._popup.setContent(
'<form method="POST" action="/mapaa"'+
'<p>Nazwa: '+nazwa+'</p>'+
'<input name="nameOfEvent" type="hidden" value="" id="idname">'+
'<button type="submit" id="form-submit" name="form-submit" class="btn btn-warning btn-block">Dołącz do wydarzenia</button>'+
'</form>')
marker_event.addTo(mymap)
polyline_event = L.polyline(array,{color: 'red'})
marker_event.on('click',function(){
polyline_event.addTo(mymap)
})
marker_event.getPopup().on('remove', function() {
polyline_event.remove()
})
$('input[id=idname]').val(nazwa.value);
mymap.setView(array[0],14)
},
});
});
Code in Flask:
#app.route('/mapaa',methods=['GET','POST'])
def mapa():
user_id = current_user.get_id()
slownik = {}
if request.method == "POST":
if request.is_json:
req = request.get_json()
nazwa = req['name']
data_pocz = req['data_start']
data_kon = req['data_end']
typ = req['type']
dlugosc = req['len_route']
coord = req['coordinates']
event_database = Event(date_start=data_pocz, date_end=data_kon, type=typ, name=nazwa, len_route=dlugosc,admin=user_id, route=coord)
db.session.add(event_database)
db.session.commit()
print('Dodano wydarzenie')
if 'form-submit' in request.form:
nazwa_event = request.form.get('nameOfEvent')
print("Name:",nazwa_event)
else:
name_ev = request.form.get('nameevent')
all_data = Event.query.filter_by(name=name_ev).all()
for row in all_data:
date_st_string = str(row.date_start)
date_end_string = str(row.date_end)
slownik = {'id':row.id,'date_st':date_st_string,'date_end':date_end_string,'type':row.type,'name':row.name,'len_route':row.len_route,'route':row.route}
return jsonify(slownik)
return render_template('mapaa.html', title='Mapa')
It is problem with the form or name of something ?

Upload file with text using AJAX & ASP.NET

I am having trouble uploading a file and value from a textbox/textarea in a single AJAX post. The entire project was created with AJAX posts to send data and receive resulting html/data. This means every button is handled with javascript/jquery and not asp.net's default onClick. Searches online yield answers with file upload but none of them show or explain any way to pass other parameters/data along with it.
*EDIT - I am not receiving any specific errors or crash attempting this. I try to run the file upload code in the success of the note upload or vice versa. It doesn't seem to be able to run both even if I switch it to asynchronous. I am more trying to get ONE single AJAX post to send both the file and the note to be handled in one codebehind function.
*EDIT(due to duplicate flag) - This is ASP.NET, not php. Please fully read questions before jumping to duplicate/closed conclusions.
Below is code/example of what I have so far.
HTML :
<div id="Modal_New_Document" class="modal fade" role="dialog">
<div class="modal-dialog Modal-Wrapper">
<div class="modal-content">
<div class="modal-header Modal-Header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3 class="modal-title">Upload New Document</h3>
</div>
<div class="modal-body Modal-Body">
<table>
<tr>
<th>Document :</th>
<td>
<input type="file" id="FileUpload_Modal_Document" />
</td>
</tr>
<tr>
<th>Note :</th>
<td>
<textarea id="TextArea_Modal_Document_Note" style="width: 400px;"></textarea>
</td>
</tr>
</table>
</div>
<div class="modal-footer Modal-Footer">
<button type="button" class="btn btn-success" onclick="enterDocumentInfo()">Upload</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
This is the most important part. I prefer to upload using the $.Ajax such as the example below. I was able to get only the file upload to work with the submitDocument()
Javascript :
function submitDocument()
{
var fileUpload = $("#FileUpload_Modal_Document").get(0);
var files = fileUpload.files;
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append(files[i].name, files[i]);
}
var options = {};
options.url = "FileUploadHandler.ashx";
options.type = "POST";
options.data = data;
options.contentType = false;
options.processData = false;
options.success = function (result) { alert("Gud"); };
options.error = function (err) { alert(err.statusText); };
$.ajax(options);
}
$.ajax({
type: "POST",
url: "Lease_View.aspx/enterDocument",
data: JSON.stringify({
leaseID: leaseID,
userID: userID,
note: note
}),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function ()
{
// Gud
},
error: function ()
{
// Bad
}
});
Codebehind FileUpload
public class FileUploadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.Files.Count > 0)
{
HttpFileCollection files = context.Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
// Upload code here
}
}
context.Response.ContentType = "text/plain";
context.Response.Write("File(s) Uploaded Successfully!");
}
public bool IsReusable
{
get
{
return false;
}
}
}
WebMethod Codebehind
I prefer to be able to upload file through this instead of above.
[System.Web.Services.WebMethod]
public static void enterDocument(string leaseID, string userID, string note)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
SqlCommand cmd;
cmd = new SqlCommand("INSERT INTO Lease_Documents " +
"(File_Name) " +
"VALUES " +
"(#File_Name)", conn);
cmd.Parameters.AddWithValue("#File_Name", note);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
I figured it out. Basically how to pass additional parameters is using data.append(name, value) in the javascript. You can receive the value in the .ashx handler by using (HttpContext)context.Request.Form["name"]. Unfortunately it is using the handler instead of the webmethod, but at least it works.
In Javascript
var data = new FormData();
for (var i = 0; i < files.length; i++) {
data.append(files[i].name, files[i]);
}
data.append("Note", note);
In Codebehind
string note = context.Request.Form["Note"].ToString();

Fetch callback in React

I am trying to have a simple print run statement to ensure the callback is working correctly.
var CsvUpload = React.createClass({
uploadfile: function() {
console.log('trying')
var file = this.refs.file.files[0];
var formData = new FormData()
formData.append('files', file)
fetch('http://127.0.0.1:5000/add_csv_to_db', {
method :'POST',
body : formData
})
.then(() => {console.log('this worked')})
.catch((err) => {console.log(err)})
},
render: function() {
return (
<div>
<h4 className='sub-header'>CSV Upload</h4>
<form onSubmit = {this.uploadfile} encType="multipart/form-data">
<input type="file" name="file" ref="file"/>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
)
}
})
On the server:
#app.route('/add_csv_to_db', methods=['GET','POST'])
def add_rows():
file = request.files['files']
x = io.StringIO(file.read().decode('UTF8'), newline=None)
csv_input = csv.reader(x)
for row in csv_input:
if row[0] == 'Email':
pass
else:
print(row)
tasks.add_User(row)
print('completed')
return json.dumps('success!')
I see "completed" print out in the server.
In the console I see "trying" but it doesn't print "This worked"
What am I doing wrong?
Have you tried adding submission event as your uploadFile function's parameter and then calling preventDefault() on it? Your app might be refreshing on submission, and that is why you never see "this worked" printed out.
This is what I mean:
var CsvUpload = React.createClass({
uploadfile: function(e) {
e.preventDefault();
console.log('trying')
...

How do i include the csrf_token to dropzone Post request (Django)

Allright this is resolved. Just editing in case anyone runs into the same problem.
Add the Code posted in Comment marked as answer in the same javascript file.
When defining
var myDropzone = new Dropzone(...
...//More stuff here
headers:{
'X-CSRFToken' : csrftoken
}
And thats it.
So im getting a 403 Forbidden when submitting the POST request through dropzone.js to django.Django displayed the message saying that I didnt include the CSRF token, but I don't know how to actually include it if im not using a form in the HTML.
document_form.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}Add files{% endblock %}
{% block files %}
<div class="container-fluid" id="container-dropzone">
<div id="actions" class="row">
<div class="col-lg-7">
<span class="btn btn-success file-input-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Add files...</span>
</span>
<button type="submit" class="btn btn-primary start">
<i class="glyphicon glyphicon-upload"></i>
<span>Start upload</span>
</button>
<button type="reset" class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel upload</span>
</button>
</div>
<div class="col-lg-5">
<!-- file processing state -->
<span class="fileupload-process">
<div id="total-progress" class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<div class="progress-bar progress-bar-success" style="width:0%;" data-dz-uploadprogress></div>
</div>
</span>
</div>
</div>
<div class="table table-striped files" id="previews">
<div id="template" class="file-row">
<div>
<span class="preview"><img data-dz-thumbnail></span>
</div>
<div>
<p class="name" data-dz-name></p>
<strong class="error text-danger" data-dz-errormessage></strong>
</div>
<div>
<p class="size" data-dz-size></p>
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0"
aria-valuemax="100" aria-valuenow="0">
<div class="progress-bar progress-bar-success" style="width:0%"
data-dz-uploadprogress>
</div>
</div>
</div>
<div>
<button class="btn btn-primary start">
<i class="glyphicon glyphicon-upload"></i>
<span>Start</span>
</button>
<button data-dz-remove class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel</span>
</button>
<button data-dz-remove class="btn btn-danger delete">
<i class="glyphicon glyphicon-trash"></i>
<span>Delete</span>
</button>
</div>
</div> <!-- /table-striped -->
</div> <!-- /container-fluid -->
</div>
{% endblock %}
{% block dz-add %}
<script src="{% static 'js/dropzone-bootstrap.js' %}"></script>
{% endblock %}
dropzone-bootstrap.js
$(function() {
var previewNode = document.querySelector("#template");
previewNode.id = "";
var previewTemplate = previewNode.parentNode.innerHTML;
previewNode.parentNode.removeChild(previewNode);
var myDropzone = new Dropzone(document.querySelector("#container-dropzone") , {
url: "/dashby/files/add/", //url to make the request to.
thumbnailWidth: 80,
thumbnailHeight: 80,
parallelUploads: 20,
previewTemplate: previewTemplate,
autoQueue: false,
previewsContainer: "#previews",
clickable: ".file-input-button",
headers: { // Tried to apply the token this way but no success.
'X-CSRFToken': $('meta[name="token"]').attr('content')
}
});
myDropzone.on("addedfile", function(file){
file.previewElement.querySelector(".start").onclick = function(){
myDropzone.enqueueFile(file);
};
});
myDropzone.on("totaluploadprogress", function(progress){
document.querySelector("#total-progress .progress-bar").style.width = progress + "%";
});
myDropzone.on("sending", function(file){
// Show total progress on start and disable START button.
document.querySelector("#total-progress").style.opacity = "1";
file.previewElement.querySelector(".start").setAttribute("disabled", "disabled");
});
// Hide progress bar when complete.
myDropzone.on("queuecomplete", function(progress){
document.querySelector("#total-progress").style.opacity = "0";
});
// Setup buttons for every file.
document.querySelector("#actions .start").onclick = function(){
myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
};
document.querySelector("#actions .cancel").onclick = function(){
myDropzone.removeAllFiles(true);
};
});
In my base.html im adding all the required files (dropzone, jquery, bootstrap and my custom javascript file)
For the django form handling:
views.py
class DocumentCreate(CreateView):
model = Document
fields = ['file']
def form_valid(self, form):
self.object = form.save()
data = {'status': 'success'}
response = JSONResponse(data, mimetype =
response_mimetype(self.request))
return response
My "Document" model
class Document(models.Model):
file = models.FileField(upload_to = 'files/',
validators=[validate_file_type])
uploaded_at = models.DateTimeField(auto_now_add = True)
extension = models.CharField(max_length = 30, blank = True)
thumbnail = models.ImageField(blank = True, null = True)
def clean(self):
self.file.seek(0)
self.extension = self.file.name.split('/')[-1].split('.')[-1]
if self.extension == 'xlsx' or self.extension == 'xls':
self.thumbnail = 'xlsx.png'
elif self.extension == 'pptx' or self.extension == 'ppt':
self.thumbnail = 'pptx.png'
elif self.extension == 'docx' or self.extension == 'doc':
self.thumbnail = 'docx.png'
def delete(self, *args, **kwargs):
#delete file from /media/files
self.file.delete(save = False)
#call parent delete method.
super().delete(*args, **kwargs)
#Redirect to file list page.
def get_absolute_url(self):
return reverse('dashby-files:files')
def __str__(self):
#cut the 'files/'
return self.file.name.split('/')[-1]
class Meta():
#order by upload_date descending
#for bootstrap grid system. (start left side)
ordering = ['-uploaded_at']
I created a Json response to handle the dropzone.
response.py
from django.http import HttpResponse
import json
MIMEANY = '*/*'
MIMEJSON = 'application/json'
MIMETEXT = 'text/plain'
# Integrating Dropzone.js with Django.
def response_mimetype(request):
can_json = MIMEJSON in request.META['HTTP_ACCEPT']
can_json |= MIMEANY in request.META['HTTP_ACCEPT']
return MIMEJSON if can_json else MIMETEXT
# Custom HttpResponse
class JSONResponse(HttpResponse):
def __init__(self, obj='', json_opts=None, mimetype=MIMEJSON,
*args, **kwargs):
json_opts = json_opts if isinstance(json_opts, dict) else {}
content = json.dumps(obj, **json_opts)
super(JSONResponse, self).__init__(content, mimetype,
*args, **kwargs)
I've been stuck with this problem for a day now, so decided to ask for help here as I havn't been able to find one.
Thanks to anyone that takes the time to read and for any help/tips that I can get.
I have just figured this out, all you need to do is add this to your dropzone config:
headers: {'X-CSRFToken': '{{ csrf_token }}'},
good luck!
just place {% csrf_token %} anywhere in your Html file . it's automatically add
<input type="hidden" name="csrfmiddlewaretoken" value="**************" />
Before sending data to the server just add extra field csrf_token which value is $("input[name='csrfmiddlewaretoken']").val();
Django’s docs have a reference for this:
While [a special parameter] can be used for AJAX POST requests, it has some inconveniences: you have to remember to pass the CSRF token in as POST data with every POST request. For this reason, there is an alternative method: on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.
[…]
Acquiring the token is straightforward:
// using jQuery
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]);
// 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');
[…]
Finally, you’ll have to actually set the header on your AJAX request, while protecting the CSRF token from being sent to other domains using settings.crossDomain in jQuery 1.5.1 and newer:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
If you run these two code blocks before you start to make requests, it should Just Work™.
In summary, just use this code block:
// from https://docs.djangoproject.com/en/1.10/ref/csrf/ via http://stackoverflow.com/a/39776325/5244995.
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]);
// 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');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
The docs recommend getting the CSRF token from the cookie, not the DOM. Try that.
While this is an old thread, I thought I'd share the solution that worked for me.
var myDropzone = $("#file-upload").dropzone({
url: "/dashboard/api/v1/upload/",
// addRemoveLinks : true,
maxFilesize: 5,
dictResponseError: 'Error uploading file!',
headers: {'X-CSRFToken': window.CSRF_TOKEN},
success: (file, response) => {
console.log(JSON.parse(file.xhr.response));
}
});

Categories