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/
Related
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!
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>
i have a html form and submit button (It adds or removes relations in manytomanyfield "users"):
{% if user in event.users.all %}
<form action="/event/{{ event.id }}/" method="GET">
<input type="hidden" value="{{ event.id }}" name="remove">
<input type="submit" value="Remove">
</form>
{% else %}
<form action="/event/{{ event.id }}/" method="GET">
<input type="hidden" value="{{ event.id }}" name="add">
<input type="submit" value="Add">
</form>
in views.py:
def show_event(request, event_id):
...
event = get_object_or_404(Event, id=event_id)
user = request.user
if request.GET.get('add'):
event.users.add(user)
event.save()
if request.GET.get('remove'):
event.users.remove(user)
event.save()
return render(request, 'events/event.html', {'event':event, 'user':user,})
This function works fine, but the page refreshes after submitting form. I need no refresh and i need to change button text just like "Follow" button in Twitter. I tried to use some jquery\ajax but i dont exactly understand how it should work. Can please anyone explain how to do it? Thanks.
Here's an extremely basic ajax example. In your form, you can fire your ajax method with:
<a onclick="AjaxFormSubmit()" href="#">Submit</a>
Then your ajax method would be as follows:
function AjaxFormSubmit() {
$.ajax({
url : '/event/{{ event.id }}/',
type : "POST",
data : { the_post : $('#id-of-your-field').val() }
}).done(function(returned_data){
// This is the ajax.done() method, where you can fire events after the ajax method is complete
// For instance, you could hide/display your add/remove button here
});
}
I recommend looking at the Ajax documentation to see all of the Ajax methods available to you.
Also, in your view, you'll need to return (in this example) json data via an HttpResponse. i.e.
return HttpResponse(json.dumps(your_data))
# I like to return success/fail Booleans, personally
*Note, this is untested code.
I am using a flask framework, and can't seem to delete rows from the database. The code below gives a 405 error: "The method is not allowed for the requested URL." Any ideas?
In the py:
#app.route('/delete/<postID>', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries WHERE id = ?', [postID])
flash('Entry was deleted')
return redirect(url_for('show_entries', post=post))
In the html:
<h3>delete</h3>
Clicking <a href...>delete</a> will issue a GET request, and your delete_entry method only responds to POST.
You need to either 1. replace the link with a form & submit button or 2. have the link submit a hidden form with JavaScript.
Here's how to do 1:
<form action="/delete/{{ entry.id }}" method="post">
<input type="submit" value="Delete />
</form>
Here's how to do 2 (with jQuery):
$(document).ready(function() {
$("a.delete").click(function() {
var form = $('<form action="/delete/' + this.dataset.id + '" method="post"></form>');
form.submit();
});
});
...
Delete
One thing you should not do is make your delete_entry method respond to GET. GETs are meant to be idempotent (are safe to run repeatedly and don't perform destructive actions). Here's a question with some more details.
Alternatively, change POST to DELETE to get you going.
#app.route('/delete/<postID>', methods=['DELETE'])
Ideally, you should use HTTP DELETE method.
I used flaskr as a base for my Flask project (as it looks like you did as well).
In the .py:
#app.route('/delete', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries where id = ?', [request.form['entry_id']])
g.db.commit()
flash('Entry deleted')
return redirect(url_for('show_entries'))
In the HTML:
<form action="{{ url_for('delete_entry') }}" method=post class=delete-entry>
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="submit" value="Delete" />
</form>
I wanted a button, but you could easily use a link with the solution here.
A simple <a href= link in HTML submits a GET request, but your route allows only PUT requests.
<a> does not support PUT requests.
You have to submit the request with a form and/or with JavaScript code.
(See Make a link use POST instead of GET.)
Hi I got a simple form for a POST request and it works when I'm only having one input, but not two inputs together. Can someone show me some light on this?
index.html
<form name="input" action="{% url 'sending' %}" method="post">
{% csrf_token %}
Recipient: <input type="text" name="recipient">
<br>
Message: <input type="text" name="content">
<br>
<input type="submit">
</form>
views.py
def sending(request):
recipient = request.POST.get('recipient','')
content = request.POST.get('content','') #not working when I am doing this...
someMethod(recipient, content)
return HttpResponseRedirect(reverse('results'))
Adding a "forms" portion to your setup will help you greatly... see the quickstart docs on forms here: https://docs.djangoproject.com/en/1.6/topics/forms/
In particular, check out "using a form in a view": https://docs.djangoproject.com/en/1.6/topics/forms/#using-a-form-in-a-view
Basically, you end up with a "forms.py" file which defines your form fields. Then, after it all processes, you get a simplier API into your form fields that looks like this:
form.cleaned_data['recipient']
form.cleaned_data['content']
etc.