Sending data from Python to HTML in Django - python

I have a Django project with a form in an HTML file, and I'd like to update the text on the submit button of that form WITHOUT a page reload. Essentially:
I click submit on the form
Python handles the submit with the form data
The button text is updated to say "show result"
If I understand correctly, I have to use AJAX for this. The problem is that the form submit relies on an API call in Python, so the HTML essentially has to always be "listening" for new data broadcasted by the views.py file.
Here's the code I have (which doesn't work, since when I hit submit I'm greeted by a page with the JSON response data and nothing else):
views.py:
def home(request):
if request.method == "POST":
print("Got form type", request.content_type)
return JsonResponse({"text": "show result"})
return render(request, 'home.html')
home.html:
<div class="content" onload="document.genform.reset()">
<form name="genform" autocomplete="off" class="form" method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
<div class="title-sect">
<h1>AJAX Test Form</h1>
</div>
<div class="submit">
<button id="submit" type="submit">Submit</button>
</div>
</form>
</div>
<script type="text/javascript">
function queryData() {
$.ajax({
url: "/",
type: "POST",
data: {
name: "text",
'csrfmiddlewaretoken': '{{ csrf_token }}',
},
success: function(data) {
var text = data['text'];
var button = document.getElementById('submit');
button.innerHTML = text;
setTimeout(function(){queryData();}, 1000);
}
});
}
$document.ready(function() {
queryData();
});
</script>
I've imported jQuery with the script <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.min.js"></script>. Any idea why this doesn't work in its current state? Thanks!

Related

Autosave user input in textarea in Django

I'd like to save user input in a text area automatically without any submit button. The UI I'm looking for is google docs kind of thing. Ideally there should be a time interval of 2-3 seconds after the input to prevent submitting requests every-time something is typed.
Here's my current implementation.
model:
class ActionField(models.Model):
content = models.TextField()
def __str__(self):
return self.content
view:
def action_view(request):
all_todo_items = ActionField.objects.all()
return render(request, 'action.html',
{'all_items': all_todo_items})
and html displaying the form and the submit button I'd like to remove:
<form action="/add/" method='post'>{% csrf_token %}
<textarea name="content" rows="30" cols="100"></textarea>
<br><br>
<input type="submit" value="enter">
</form>
After some quick research, it seems this would be normally done with AJAX or Jquery but is there any simple approach using purely Django? I'm new to the framework as well as html / FE.
I've never heard about that possibility. Django (just like any other backend framework) can only send or receive data to or from your browser. It can't somehow make your browser send something without any script at the browser's side.
However, there is a script that you can use:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<form action="/add/" method='post'>{% csrf_token %}
<textarea name="content" rows="30" cols="100"></textarea>
<br><br>
<input type="submit" value="enter">
</form>
<script>
$("textarea[name='content']").on("change", function() {
$.ajax({
url: '/add/', // or better {% url 'view-name-in-urls.py' %}
method: 'POST',
data: {
content: $(this).val(),
csrfmiddlewaretoken: '{{ csrf_token }}'
}
}).done(function(msg) {
alert("Data saved");
})
});
</script>
</body>
I know that the ability to do everything on the server-side is very convenient and looks nice but it's just impossible.
You need to learn how to deal with the server on the client-side too.
You can read more about forms here https://docs.djangoproject.com/en/3.1/topics/forms/
and ajax https://api.jquery.com/jquery.ajax/

redirect() / render_template() enters the route once again when called from the same route in Flask

I have created a wishlist page which lists the items wishlisted by a user. The user can remove any item from the wishlist by clicking on the Remove button. On clicking the remove button, the HTML <form> submits it to the back-end application. The back-end application then removes the item from the wishlist database and redirects back to the same page using return redirect(url_for('wishlist')).
The problem I am facing is that if the user goes back after removing the item from the wishlist he has to go back twice to reach the page from where the user came from. This is caused due to the redirect that I am performing after removing the item which is necessary to show the updated wishlist.
I have also tried render_template() instead of redirect() but it is also causing the same problem.
Code for back-end:
#app.route('/wishlist/',methods=['GET','POST'])
#login_required
def wishlist():
userid=current_user.get_id()
if request.method=='POST':
toRemove=request.form['remove']
deleteWish=session.query(Wishlist).filter_by(userId=userid,productId=toRemove).one()
session.delete(deleteWish)
session.commit()
return redirect(url_for('wishlist'))
subquery=session.query(Wishlist.productId).filter(Wishlist.userId==userid).subquery()
wishes=session.query(Products).filter(Products.id.in_(subquery))
return render_template("wishlist.html",wishes=wishes)
HTML:
<html>
<body>
{% for wish in wishes %}
<img src={{wish.image_path}} width="150" height="200">
</br>
{{wish.material}}
{{wish.productType}}
</br>
{{wish.price}}
</br>
<form action="{{url_for('wishlist')}}" method="POST" target="_self">
<button name="remove" type="submit" value="{{wish.id}}">Remove</button>
</form>
</br>
{% endfor %}
</body>
</html>
Please suggest me a way to prevent this.
You may want to create a different end point for deleting wishes. This endpoint then redirects to your wish list once deletion is done.
FLASK
#app.route('/wishlist/',methods=['GET','POST'])
#login_required
userid=current_user.get_id()
def wishlist():
subquery=session.query(Wishlist.productId).filter(Wishlist.userId==userid).subquery()
wishes=session.query(Products).filter(Products.id.in_(subquery))
return render_template("wishlist.html")
#app.route('/deletewish', methods = ['GET', 'POST']
def deletewish():
if request.method=='POST':
toRemove=request.form['wish_delete_id']
deleteWish=...
session.delete(deleteWish)
session.commit()
return redirect(url_for('wishlist'))
HTML
<html>
<body>
{% for wish in wishes %}
<img src={{wish.image_path}} width="150" height="200">
</br>
{{wish.material}}
{{wish.productType}}
</br>
{{wish.price}}
</br>
<form method="POST" target="_self">
<button class="remove_wish" type="submit" value={{wish.id}}>Remove</button>
</form>
</br>
{% endfor %}`
<script src='path_to_jquery.js'></script>
<script src='path_to_deletewish.js'></script>
</body>
</html>
JS //deletewish.js content
<script>
$(document).ready(function() {
$('.remove_wish').click(function (event) {
event.preventDefault();
$.ajax({
data : {
wish_delete_id : $(this).val();
},
type : 'POST',
url : '/deletewish',
success: function (data) {
location.reload();
},
error: function (e) {
alert('something went wrong')
}
});
});
})
</script>

Django : SQLite Database is Locked when I build like feature on my home page

I am implementing Like functionality in Web application. Idea is Simple to List number of Post(Blogs) on Home page and Add a Like Button to each post(Blog). It works fine when I build it with normal
<form action='{% url target %}' method='POST'>
But when I implemented this with AJAX call It only allows me to like or dislike a particular post(blog) a single time.i.e One I liked a Post for first time it works, also when I dislike the same Post It works fine, But when I again Like that Post it throws an django.db.utils.OperationalError: database is locked
Also, when I like same post multiple(4 to 5) times it respond in a weird way. I goes in Loop of liking and dislikig post.
like_section.html
<form id="like-form{{ post.id }}">
{% csrf_token %}
<button type="submit" id="{{ post.id }}btn" name="like" value="{{ post.id }}" class="btn upvote">Like</button>
<script type="text/javascript">
{% for like in post.likes.all %}
{% if like != user %}
dislikingPost("{{ post.id }}btn");
{% else %}
likingPost("{{ post.id }}btn");
{% endif %}
{% endfor %}
$(document).ready(function(event){
$(document).on('click', '#{{ post.id }}btn', function(event){
event.preventDefault();
pk = $(this).attr('value');
$.ajax({
type: 'POST',
url: '{% url "like_post" %}',
data: {
'id': pk,
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
success:function(response){
$('#like-form{{ post.id }}').html(response['form'])
// $('#{{ post.id }}btn').style.color = 'green';
}, error: function(er, e){
console.log(er.responseText);
}
});
});
});
</script>
</form>
views.py:
def like_post(request):
all_posts = Posts.objects.all()
print("Insisde Like Post")
print('ID coming from form is', request.POST.get('id'))
post = get_object_or_404(Posts, id=request.POST.get('id')) # for AJAX call
context = {
'all_posts': all_posts,
'post': post
}
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user) # Liking The Post
print("DisLiking the post")
else:
post.likes.add(request.user)
print("Liking the post")
if request.is_ajax():
print('Hey its an AJAX calls') # TEsting AJAX request
html = render_to_string('like_section.html', context, request=request)
return JsonResponse({'form': html})
Note:
1. I am beginner in AJAX.
2. I know SQLite can not handle redundant calls, But why it was working before without AJAX calls.
3. I am not providing models.py and complete template of home page and I don't think they are required.
The Problem was not with the Django code. It was ajax call which was triggering Database more then one time on a single Button Click.
Adding event.stopImmediatePropagation(); below event.preventDefault(); in ajax call works perfect

Django dynamic inputs

I'd like to create dynamic input system, for example when I enter the folder name - the list of files inside automatically show up another input ChoiceField below, so I can choose the file. The methods are already written, the problem is - How can I make it in Django view?
Here is my view:
def get_name(request):
if request.method == 'POST':
form = NameForm(request.POST)
if form.is_valid():
dir_date = format_date(request.POST['date'])
files = os.listdir(os.path.join(path+dir_date))
return render(request, 'inform/show_name.html', {'data': request.POST['your_name'],
'date': format_date(request.POST['date'])})
else:
form = NameForm()
return render(request, 'inform/base.html', {'form': form})
Here is the form class:
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
date = forms.DateField(widget=forms.DateInput(attrs={'class': 'datepicker'}))
flights = forms.ChoiceField(choices=?)
Finally, here is my template.
{% extends 'inform/header.html' %}
{% block content %}
<script>
$( function() {
$( ".datepicker" ).datepicker();
$( "#anim" ).on( "change", function() {
$( "#datepicker" ).datepicker( "option", "showAnim", $( this ).val() );
});
} );
</script>
<div class="container" style="color: red; size: auto;">
<form class="form-vertical" action="get_name" role="form" method="post">
{% csrf_token %}
<div class="form-group" style="display: inherit">
<center>
{{form}}
<input type="submit" value="OK">
</center>
</div>
</form>
</div>
{% endblock %}
Is there any way to dynamically read the data from the Date input and give it to the method inside the view without clicking the submit button or creating several others? If it can be solved only by ajax, jQuery or JS, could you please give me a simple sample of how it's done? I'm pretty much frustrated by the inability of creating a simple form.
Thank you in advance!
So basically you are doing it right. You already know that you need the on(change) function for the datepicker
Now as soon as the user changes a date, your on(change) function is triggered. So all you need to do now is to the get the new date value, which you already have when you do $( this ).val(). After that make an ajax call to the url corresponding to your method get_name in views.py
Something like this:
$( function() {
$( ".datepicker" ).datepicker();
$( "#anim" ).on( "change", function() {
$( "#datepicker" ).datepicker( "option", "showAnim", $( this ).val() );
send_changed_date_value(variable_with_new_date);
});
});
function send_changed_date_value(new_date) {
$.ajax({
type: // "POST" or "GET", whichever you are using
url: "/url in urls.py corresponding to get_name method in views.py/",
data: new_date,
success: function(response){
console.log("Success..!!")
}
});
}
This is how you can send the new date value to your views, everytime it is changed. If you want to submit the complete form data, i.e., your_name and flights data as well, then you may directly send serialzed data of the form in the data attribute of ajax.
Note -> You will have to return a HttpResponse from your get_name view as an ajax call requires a HttpResponse from the backend to complete the ajax call successfully. You may simply return a string in the response.

POST doesn't happen in ajax

I have a simple form to submit and test ajax,but it doesn't work and I see any problem in it,I searched alot and there was no more poin-at least I dedn't see ;)
in urls.py
(r'^doctors/shahsavand/visiting/$','DrHub.views.visiting'),
(r'^doctors/shahsavand/visiting/add/$','DrHub.views.ajxTest')
the first URL is to direct to main page and there's this form in main page:
<form method='POST' action=".">
{% csrf_token %}
<ul>
<li>
<label for="start">Start Time: </label><input name="id_startTime" id="id_startTime" type="text" />
</li>
<li>
<label for="end">End Time: </label><input name="id_endTime" id="id_endTime" type="text" />
</li>
</ul>
<input type="submit" id="save_button" name="save_button" value="add" />
</form>
and ajax code in this page:
<script type='text/javascript' src='/static/DrHub/doctors/shahsavand/js/jquery-1.4.1.js'></script>
<script type="text/javascript">
$.ajax({
type:"POST",
url:"{% url DrHub.views.ajxTest %}",
data: {
'start': $('#id_startTime').val(),
'end': $('#id_endTime').val(),
'csrfmiddlewaretoken':$( "#csrfmiddlewaretoken" ).val()
},
success: function(data){
alert(data);
}
});
</script>
in views.py :
def ajxTest(request):
if request.is_ajax():
if request.method == 'POST':
return HttpResponse(simplejson.dumps({'message' : 'awesome'}), mimetype='application/javascript')
else:
return render_to_response('DrHub/doctors/nutrition/test.html', context_instance=RequestContext(request))
I did this to test if ajxTest view is called:
def ajxTest(request):
if request.is_ajax():
raise Http404
else:
pass
and this :
def ajxTest(request):
if request.is_ajax():
raise pass
else:
Http404
but no result and that sounds like my ajax POST is not associated with ajxTest view !!!
edit
when I check firebug I get 403 forbidden error that is for CSRF and I've tryed many things to solve it again no result :(
Add the javascript described in the documentation for csrf and it should fix your problem.

Categories

Resources