I'm trying to create an content editable HTML table that'll update the db.sqlite3 database on keypress. The table can't have an input field in it because I also require it to be able to be filter and search using data-tables. so far I manage to retrieve the input on enter keypress but i don't know how to POST it straight to database (Presumably using AJAX) instead of JSON. Can anyone provide me with complete syntax sample as well, I'm very new to Django
Here's my code :
Model.py
class MyModel(models.Model):
a = models.CharField(max_length=10)
b = models.CharField(max_length=10)
def __str__(self):
return self.a
form.py
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['a', 'b']
view.py
def display_table(request):
context = {
"table_list": MyModel.objects.all(),
"title": "Table_List"
}
return render(request, 'tables/display.html', context)
display.html
<form action="" method="post" id="test_post">{% csrf_token %}
<div id="debug" contenteditable data-name="custom-text">Some text you can edit.</div>
<table id="myTable" class="display">
<thead>
<tr>
<th>A</th>
<th>B</th>
</tr>
</thead>
<tbody>
{% for data in table_list %}
<tr >
<td contenteditable="true" data-name="a_name" id="{{data.id}}">{{data.a}}</td>{% csrf_token %}
<td contenteditable="true" data-name="b_name" >{{data.b}}</td>{% csrf_token %}
</tr>
{% endfor %}
</tbody>
</table>
</form>
<script>
document.addEventListener('keydown', function (event) {
var esc = event.which == 27,
nl = event.which == 13,
el = event.target,
data = {};
if (esc) {
// restore state
document.execCommand('undo');
el.blur();
} else if (nl) {
// save
data[el.getAttribute('data-name')] = el.innerHTML;
// we could send an ajax request to update the field
$.ajax({
data: data,
type: "POST"
});
log(JSON.stringify(data));
el.blur();
event.preventDefault();
}
}, true);
function log(s) {
document.getElementById('debug').innerHTML = 'value changed to: ' + s;
console.log(s);
}
</script>
<script>
$(document).ready(function(){
$('#myTable').DataTable();
});
</script>
Thank you very much for everyone's help.
Yes you're right about using AJAX. A few things you will need to modify:
1. Your HTML/JS
$.ajax({
data: data,
type: "POST",
// include URL
url: 'url/to/post/to',
// include response handler here
success: function(response) {
// do whatever you want with response
// you can just console.log(response.data) first
},
error: function(response) {
// error handler to failed AJAX requests
}
});
2. Views
You'll need to change your view to return a JsonResponse instead of using render which creates an HTML response. Note that the JsonResponse will be the exact response received in the AJAX handler above.
Hope this helps.
Related
I have comments on a product on the page. and there is a button to add a comment, which puts a new comment into the database. How can I automatically display a new comment on a page?
mytemplate.html
<div id="comments">
{% include 'comments.html' %}
</div>
comments.html
{% for comment in comments %}
<!-- some code for display comments -->
{% endfor %}
script.js
$("#addComment").on("click", function(e){
e.preventDefault()
if ($("#addCommentArea").val() != ""){
data = {
commentText: $("#addCommentArea").val(),
product_id: "{{ product.id }}"
}
$.ajax({
type: "GET",
url: "{% url 'newcomment' %}",
datatype: 'json',
data: data,
success: function(data){
$("#addCommentArea").val("")
}
})
}
})
views.py
class CommentView(View):
def get(self, request):
commentText = request.GET.get("commentText")
if (len(commentText) > 0):
newComment = Comment()
newComment.Author = request.user
product_id = request.GET.get("product_id")
product = Product.objects.get(id=product_id)
newComment.Product = product
newComment.Comment = commentText
newComment.save()
return JsonResponse({'ok': 'ok'})
Currently, you just render the template once and fetch the comments, further you are using Ajax to submit, which means your template doesn't get updated. To update the comments without a page refresh you can either make a javascript polling or use for example web sockets
Using flask, I want to select a user from a table and then redirect the page with the id of the selected user. My code looks something like this:
HTML:
<form action="" method="POST">
<table>
<tr>
<th>Id</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
{% for user in users %}
<tr type="submit" name="action" value="{{user.user_id}}">
<td>{{user.user_id}}</td>
<td>{{user.first_name}}</td>
<td>{{user.last_name}}</td>
</tr>
{% endfor %}
</table>
</form>
Python:
def userSelect():
if request.method == 'POST':
return redirect(url_for('user', user=request.form['action']))
return render_template('userSelect.html', users=user.query.all())
I have also tried using JQuery to make the post, but I am unsure how to then use the id in the page that I redirected to, and I can't redirect from flask after having made a post from JQuery:
$("table tr").on("click",function()
{
var selected = $("td:first", this).text();
$.post("/user", {user_id: selected}, function(){
window.location.href = "/user";
});
});
EDIT:
Let's just say I want to display that id on the page I redirect to (something like this):
#app.route("/user")
def user(user):
return user
With your Jquery's code, it will make an ajax to server
$.post("/user", {user_id: selected}, function(){
window.location.href = "/user";
});
so, Flask can not redirect, if you edit code look like:
$.post("/user", {user_id: selected}, function(data){
console.log(data);
});
you will see Flask had returned HTML of the redirected page.
Finally, I think this is help you:
Flask:
#app.route('/user/<user_id>')
def userHasSelected(user_id):
....
// I don't know why do you need this return redirect
return redirect(url_for('user', user=request.form['action']))
JS:
$("table tr").on("click",function()
{
var selected = $("td:first", this).text();
// {{url_for('user', user_id=selected)}} it will be rending from server
window.location.href = {{url_for('user', user_id=selected)}}
// or
window.location.href = `/user?user_id=${selected}`;
});
I'm trying to return data with an ajax request on a form submission. My goal was too use two views, one too handle the template loading and the other to handle the POST request from the form. In the current state, the form is redirecting to the JSON that is in the callback. That makes sense as it's for the form action url is pointing, however, i want to just pass the data to the current page and not reload the page or be redirected to another page.
Here is the code:
user.html
<form action="{% url 'ajax-user-post' %}" method="post">
{% csrf_token %}
{% for user in users %}
<input type="submit" name="name" value="{{ user }}">
{% endfor %}
views.py
def ajax_user(request):
# get some data..
if request.METHOD == 'POST':
user = request.POST['user']
user_data = User.objects.get(user=user)
data = {'user_data': user_data}
return JsonResponse(data)
def user(request):
return render(request, 'user.html', context)
urls.py
url(r'^user/', user, name="user"),
url(r'^ajax/user/', ajax_user, name="ajax-user-post")
.js
$('form').on('submit', function(){
var name = // the name of the user selected
$.ajax({
type: "POST",
dataType: "json",
url: 'ajax/user/',
data: { 'csrfmiddlewaretoken': csrftoken, 'name': name, 'form': $form.serialize() },
success:function(data) {
// hide the current data
console.log(data);
displayUserData(data)
}
})
});
Thanks for the help in advance!
i want to just pass the data to the current page and not reload the page or be redirected to another page.
That means you need to stop the form submission event with the event.preventDefault() call.
Hence, change this line from:
$('form').on('submit', function(){
to to following two:
$('form').on('submit', function(e){
e.preventDefault();
I am using Django DeleteView for deleting objects. First, I implemented delete add confirm dialog redirecting another html page. Now, I want to add bootbox pop up. But i don't understand where to add code. Please help
models.py
class Review(models.Model):
review_description = models.TextField(max_length=500)
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
views.py
class ReviewDelete(DeleteView):
model = Review
template_name = "confirm_delete.html"
def get_success_url(self, *args, **kwargs):
review = get_object_or_404(Review, pk=self.kwargs['pk'])
return reverse("books:detail", args = (review.book.id,))
confirm_delete.html
{% extends "base.html" %}
{% block content %}
<h1>Delete</h1>
<p>Are you sure you want to delete {{ review }}?</p>
<form action="{% url "delete" pk=review.id %}" method="POST">
{% csrf_token %}
<input type="submit" value="Yes, delete." />
No, cancel.
</form>
{% endblock %}
book_details.html
Delete
{# Delete#}
base.html
<script type="text/javascript">
$(document).ready(function () {
$("#review-delete-btn").click(function (event) {
event.preventDefault();
bootbox.confirm({
title: "Destroy planet?",
message: "Do you want to delete? This cannot be undone.",
buttons: {
cancel: {
label: '<i class="fa fa-times"></i> Cancel'
},
confirm: {
label: '<i class="fa fa-check"></i> Confirm'
}
},
callback: function (result) {
console.log('This was logged in the callback: ' + result);
}
});
});
});
</script>
urls.py
url(r'^reviews/(?P<pk>\d+)/delete/$', ReviewDelete.as_view(), name='delete'),
Assuming your server page doesn't perform redirects when completing the delete, you just need to add an AJAX call to the confirm callback. Something like this:
<script>
$(function () {
$("#review-delete-btn").on('click', function (event) {
event.preventDefault();
// for referencing this later in this function
var _button = $(this);
bootbox.confirm({
title: "Destroy planet?",
message: "Do you want to delete? This cannot be undone.",
buttons: {
cancel: {
label: '<i class="fa fa-times"></i> Cancel'
},
confirm: {
label: '<i class="fa fa-check"></i> Confirm'
}
},
callback: function (result) {
// result will be a Boolean value
if(result){
// this encodes the form data
var data = _button.closest('form').serialize();
$.post('your delete URL here', data).
done(function(response, status, jqxhr){
// status code 200 response
})
.fail(function(jqxhr, status, errorThrown){
// any other status code, including 30x (redirects)
});
}
}
});
});
});
</script>
You will probably want to review the documentation for $.post and serialize. I would also recommend working your way through the AJAX topics - $.post is a convenience method for $.ajax, so you should know how to use both.
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.