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.
Related
I am working on a project where user have his own profile, I want to create a BooleanField on model so that user can set profile privacy, private or public. I have added a BooleanField to modal (is_private). Also i have a toggle switch on template but i do not know how to go with it with Django. I want when a user click on switch boolean field is true (private), when user click again on switch boolean field is false (public). Jquery maybe needed as well.
Model:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,blank=True,null=True)
is_private = models.BooleanField(default=False)
Views:
def profile_edit_view(request):
p = Profile.objects.filter(user=request.user).order_by('-id')
context = {'p':p}
return render(request, 'profile_edit.html', context)
urls:
path('account/edit/', profile_edit_view, name ='profile-edit'),
Profile Edit Template:
<form method="POST" name="is_private">
{% csrf_token %}
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="customSwitches" name="is_private">
<label class="custom-control-label" for="customSwitches">Private Account</label>
</div>
</form>
<p class="text-muted font-weight-normal font-small">
When your account is private, only people you approve can see your photos and videows on Pixmate. Your existing followers won't be affected.
</p>
In template file change the input tag as shown
<!-- Mark the checkbox as checked or not by is_private -->
<input type="checkbox" class="custom-control-input" id="customSwitches" {% if p.is_private %}checked{% endif %}>
In that same template file add this script
<script type="text/javascript">
$(document).ready(function() {
// send request to change the is_private state on customSwitches toggle
$("#customSwitches").on("change", function() {
$.ajax({
url: "{% url 'change_privacy' %}",
data: {
csrfmiddlewaretoken: "{{ csrf_token }}",
is_private: this.checked // true if checked else false
},
type: "POST",
dataType : "json",
})
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
.done(function(data) {
console.log(data);
// show some message according to the response.
// For eg. A message box showing that the status has been changed
})
.always(function() {
console.log('[Done]');
})
})
});
</script>
Add a new path in your urls file of the app which binds to a view. Say: a function named change_privacy() in your views
path('changeprivacy', change_privacy, name="change_privacy"),
In views file add a new function. You need to import JsonResponse
from django.http import JsonResponse
def change_privacy(request):
if request.is_ajax() and request.method=='POST':
profile = Profile.objects.get(user=request.user)
profile.is_private = True if request.POST.get('is_private') == 'true' else False
profile.save()
data = {'status':'success', 'is_private':profile.is_private}
return JsonResponse(data, status=200)
else:
data = {'status':'error'}
return JsonResponse(data, status=400)
Here is how to do it with Ajax.
First include jQuery:
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
Ajax setup, you need to include a CSRF token (or make decorate your view with #csrf_exempt). Relevant section in the django documentation. If you don't include the CSRF token in your request you will get 403 Forbidden.
<script type="text/javascript">
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const 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;
}
const csrftoken = getCookie('csrftoken');
</script>
Then make the Ajax request:
<script type="text/javascript">
$("document").ready(function () {
$("#customSwitches").change(function () {
$.ajax({
type: "POST",
headers: {
"X-CSRFToken": csrftoken
},
url: {% url 'privacy' %},
data: {
"enabled": this.checked,
},
success: function (data) {
console.log(data);
},
error: function (data, msg) {
console.log("ERROR", data, msg);
}
});
})
});
</script>
Adjust the url to work with your project and don't forget to include the CSRF token in the header.
Then you can get the value of the checkbox in your view and update the value for your user:
def privacy_view(request):
if request.is_ajax():
enabled = request.POST["enabled"]
profile = Profile.objects.get_or_create(user=request.user)
profile.is_private = enabled
profile.save()
return render(request, "privacy.html")
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.
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.
I've searched through similar questions, but nothing seems relevant to my situation.
Why does this code work fine:
<form action="/signup/" method="post">
{% csrf_token %}
[FORM]
</form>
but
<form id="signup-form">
{% csrf_token %}
[FORM]
</form>
<script type="text/javascript">
$(function() {
$(".submit-signup").on("click", function() {
var user = $("#signup_form").serialize();
console.log(user);
$.post("/signup/", user, function() {
});
});
});
</script>
not work?
Here is signup in views.py:
#requires_csrf_token
def signup(request):
[STUFF]
return render(request, 'signup.html', {[STUFF}})
What else can I provide that would help? Basically I am trying to take a page and turn it into a modal that does the same thing.
Thanks!
you are doing an ajax post call for which you need to give csrf token also:
$.post("/signup/", {
user: user,
csrfmiddlewaretoken: '{{ csrf_token }}'
}, function() {
// success todo
}, function(){
// fail todo
});
I'm allowing users to remove posts through ajax. Posts have a boolean field live_until_removed. When set to false, the post disappears.
When clicking remove I'm given a 403, referencing:
xhr.send( ( s.hasContent && s.data ) || null );
How do I get this to run smoothly? Why this this error happening?
js:
$('#removeForm').submit(function() { // catch the form's submit event
$.ajax({
data: $(this).serialize(),
type: $(this).attr('method'),
url: $(this).attr('action'),
success: function(response) {
$('.close-post').html(response); // update the DIV
console.log(response);
},
error: function(response){
console.log(response);
}
});
return false;
});
template:
<div class="close-post">
{% if not post.live_until_removed %}
<form class="" id="removeForm" method="POST" action="">
<button type="submit" class="btn">Remove</button>
</form>
{% else %}
<button class="btn">Removed</button>
{% endif %}
</div>
views.py:
def post(request, id):
...
if request.is_ajax():
try:
post = Post.objects.get(id=id)
post.live_until_removed = False
post.save()
response = simplejson.dumps({"status": "Removed"})
except:
pass
You might have missed to send CSRF token in your request. Look at here; Django-Ajax