deleting objects without refresh django - python

I am trying to delete selected objects in django it works but when I select an item then click delete button it does not delete but after it when I refresh the page selected object is deleted. Here is
views.py
#login_required
def delete_contact(request):
if request.is_ajax():
selected_contacts = request.POST['contact_id']
selected_contacts = json.loads(selected_contacts)
for i, contact in enumerate(selected_contacts):
if contact != '':
ClientContact.objects.filter(author_id__in=selected_contacts).delete()
return redirect('contacts')
in templates
<table class="table table-hover contact-list">
<thead>
</thead>
{% for contact in contacts %}
<tbody>
<tr data-id="{{ contact.id }}" class="clickable-row"
data-href="{% url 'contact-detail' contact.id %}"
style="cursor: pointer; ">
<th scope="row"><input type="checkbox" id="check"></th>
<td>{{ contact.client_name }}</td>
<td>{{ contact.client_company_name }}</td>
<td>{{ contact.email }}</td>
<td>{{ contact.work_phone }}</td>
<td>{{ contact.work_phone }}</td>
</tr>
</tbody>
{% endfor %}
</table>
{% csrf_token %}
</div>
</div>
</div>
</div>
{% include 'users/footer.html' %}
<script type="text/javascript">
$(document).ready(function () {
$(".delete-btn").click(function () {
var selected_rows = [];
$('.contact-list').find('tr').each(function () {
var row = $(this);
if (row.find('input[type="checkbox"]').is(':checked')) {
console.log(row.attr('data-id'));
selected_rows.push(row.attr('data-id'));
}
});
var selected_rows = JSON.stringify(selected_rows);
$.ajax({
url: "{% url 'contact-delete' %}",
type: 'POST',
data: {
'contact_id': selected_rows,
'csrfmiddlewaretoken': $("[name=csrfmiddlewaretoken]").val()
},
});
});
});
</script>
it works fine but with refreshing the page. How can I delete selected objects
as soon as I click the delete button.
Any help please?
Thank you!

You are deleting the objects, what you are missing is that after sending the request to Django, if the request is successful you need to update the HTML accordingly.
The HTML of your page is rendered when you request the view. At this point the for loop in your template gets executed and iterates over all existing contacts
{% for contact in contacts %}
{% endfor %}
Afterwards, when the user clicks the delete button a request is sent through AJAX to Django which effectively deletes the selected objects yet the HTML code is not updated automagically.
When you refresh the page, the template code is executed once more by Django and thus the for loop is run again but this time the list of contacts has changed, that's why you see the changes in this case.
You can solve your issue in different ways:
1) Instead of calling a Django view via AJAX, make a proper HTML+Django form that is posted to a Django view that after processing the form redirects to the same view again. This would require no Javascript or AJAX. You can read more about forms here. In this way your template is re-rendered after every post and therefore you will see your table updated.
2) Probably the worst option, but also the easiest to implement at this point, would be to refresh your page via Javascript after the AJAX request returns successfully. For this you can bind a function to the success property of your $.ajax call that triggers a refresh, something like location.reload();. Note that this is not a good choice since you are making all the effort to call the delete view using AJAX but you are not getting any of its benefits, getting only the worst of both worlds.
3) The third option is to edit your HTML (your DOM actually) using javascript when the AJAX call returns successfully. If you choose to follow this path (which is your intention I presume) and do not know how to do it I suggest that you post another question regarding specifically how to change the rendered HTML via Javascript.

django actually call for every related model pre_delete and post_delete signals. So calling some function for every related models was found not inefficient.
And I think, that not calling delete() method leads to destroy the integrity of data.
For example: we have model myModel with FileField. In case, when we call delete() from some of myModel's object, this object and related file will be deleted.
If we call delete of related to myModel's object, this object will be deleted, but file will remain.

Related

Accessing model data in Django template

I am using the below lines to pass data to my template index.html, model1 being the class in my models.py.
data = model1.objects.all()
return TemplateResponse(request, 'index.html', {'data': data})
I am able to access data on the front end by using a for loop as shown below
{% for x in data %}
<h3>{{x.name}}</h3>
<h4>{{x.department}}</h4>
{% endfor %}
Since there are mutliple objects in this data, my question is if I want to access only the department of particular object with certain name, how can I do that?
For example here I am using a for loop, consider there are two objects in the data. Then the output would be
name1
department1
name2
department2
So now if I need to access only name2 without any loop, how can i do that?
Updating the question: I am updating this question with html, so that the question looks clear.
table id="example" class="table table-striped" cellspacing="1" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Department</th>
<th>View/Edit</th>
</tr>
</thead>
<tbody>
{% for x in data %}
<tr>
<td>{{x.id}}</td>
<td>{{x.name}}</td>
<td>{{x.department}}</td>
<td>View</td>
<button type="button" class="btn-sm btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
view</button></td>
</tr>
{% endfor %}
</tbody>
This is how my html looks, I am using data-table here. So all the data is captured in a table automatically. As you can see every row has a view button that I would implement. Once the user clicks the view button, I should pop up a modal dialog to show all the other details like {{x.dateJoined}} etc which I don't show in the table. But if I use a separate view to pop this dialog, I should send a request to the view from my template saying which row(with some ID) the user has clicked. How can i achieve that? How can I bind the view button with respective rows here?
You need to write custom template tag which will take the queryset and filtering parameters and returns you appropriate object, you can use simple_tag:
myapp/templatetags/myapp_tags.py
from django import template
register = template.Library()
#register.simple_tag
def get_model1_object(queryset, **filters):
if not filters:
raise template.TemplateSyntaxError('`get_model1_object` tag requires filters.')
retrun queryset.filter(**filters).first()
Then in template:
{% load get_model1_object from myapp_tags %}
{% get_model1_object data name='blah' as obj %}
Note: Your filtering criteria might yield multiple results but in get_model1_object i am only returning the first object assuming your criteria will be strict, change it according to your needs.
The first thing to understand is that template rendering happens on the server, before the user sees anything in their browser. The template is not sent to the user, only the HTML that the template generated. When the user is interacting with the page, the original template is not involved. So, you have two choices here:
You can render the data for all the objects in hidden div's on your page, then use javascript with something like a jquery dialog to display them on demand. This is only realistic if you have very few records.
You can create a second view with its own template, which renders just the HTML for the modal dialog contents. You could then, again using javascript/jquery, make an AJAX request to load the contents of the dialog that you need when you need it. In your first view template, the list of departments, include the url of the object you want to fetch, eg:
{% for x in data %}
<tr>
<td>{{x.name}}</td>
<td><a class="deptlink" href="{% url 'dept_detail' x.pk %}">
{{ x.department }}</a></td>
</tr>
{% endfor %}
Where dept_detail is the name of the urls.py entry for your view that supplies the contents of the dialog.
Then in your javascript, hook the a tag so it opens your dialog instead of leaving the page:
$('.deptlink').click(function (event) {
event.preventDefault();
# then the code after this is up to you, but something that'll
# load the url into your dialog and open it.
$('yourdialog').load($(event.target).attr('href'));
Since you say you are an intermediate in javascript I won't get into the details of implementation, but basically, the moral of the story is that the output of django is going to be an HTML page. Anything that you need to have on the client side either has to be in that page, or you will have to make another request to the server to get it... Either way, you'll need some javascript to do this, since you want a modal dialog with client side interaction.

How to redirect a Django template and use the 'Next' variable?

I am using Django's built in login view as can be seen in the following snippets:
urls.py
url(r'^login$',login,{'template_name': 'login.html'},name="login"),
template.html
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
How can I use the next variable to redirect to a URL different than the default /accounts/profile/ that django redirects to? I know of people referring to the settings.py file but I am wondering how I can utilize the next variable to do this?
(I'm not really sure of how the next variable works even after referring to documentation, an explanation of this would be much appreciated)
if you are using django login view ie,
from django.contrib.auth.views import login
you just need to pass the next url to the template. so when the request is sent to the login view , the code is in place to redirect to that url. is no next url is found
settings.LOGIN_REDIRECT_URL is used
you can simple pass the next url just like,
<form method="post" action="{% url 'login' %}?next={{next_url}}">
Pass the "next_url" value via context.
The next case, if you need the next url redirection for any of you custom views, simple write a code inside the view to get next url and after doing the job inside the view you can redirect to the next url.
from django.utils.http import is_safe_url
def your_view(request):
# do your codes
redirect_to = request.GET.get(next, '') # use get or Post as per your requirement
if is_safe_url(url=redirect_to, host=request.get_host()):
HttpResponseRedirect(redirect_to)
else:
# your response
To clear your doubt how the next variable works: In the above view we get a get a http request and if we have passed the next url as query params. we will be getting it in the view. "request.GET.get(next, '')" will get you the next url you sent from view. from view level you can do the functionalities you need and then if the next url is present and valid you can use HttpResponseRedirect to redirect to the next url.
For login ref: Django: Redirect to previous page after login

Django Forms: Capture clicked value from template

I have a template which has a code like
<td>{{ contact.Tag_ID }}</td>
to list the Tag_ID of items in a table. Now when I click on ot it goes to as os page which is a form with the Tag_ID field. I some how want to catch the Tag_ID when I click on it and pass it to the view ans set it as the initial value. I know how to set the initial value but cannot figure how to catch the Tag_ID or its associated data.
A simple solution would be to pass the value in the url:
<td>{{ contact.Tag_ID }}</td>
or
<td>{{ contact.Tag_ID }}</td>
In the second case, it is just an old-style query string, which you can use javascript to read. But, the better (django) way would be to use the first method, and do a pretty url.
In urls.py:
(r'^os/(?P<tag_id>[a-zA-Z0-9]*)/*', 'os_view_handler'),
Then in views.py:
def os_view_handler(request, tag_id=None):
...
url code:
<a class="item" href="{% url "your_views_funct" contact.Tag_ID %}">{{ contact.Tag_ID }}</a>
and add this to your urls.py:
(r'^os/(?P<tag_id>[a-zA-Z0-9]*)/*', 'your_views_funct'),
Without knowing too much about your app, I'm guessing you want a URL like /os/<ID>/
First of all, you should declare this URL in your app's url.py. Second of all, use the {% url %} tag in the template. https://docs.djangoproject.com/en/dev/ref/templates/builtins/ And thirdly, your view should be able to accept this ID as a parameter and act accordingly.

Deleting elements from database in Flask

I want to make sure I'm following best practices here. I have a table of data that pulls from the database and in the last column I have links to edit or delete that row. I feel like I've always been told to never modify data on the server with a GET request. How would I handle deleting this data row with anything other than a GET request?
Here's the code for the data table:
<table class="table table-hover notifications">
<thead><tr><th>Search Parameter</th><th>Subreddits</th><th>Actions</th></thead>
{% for notification in notifications %}
<tr>
<td>{{ notification.q }}</td>
<td>{% for s in notification.subreddits %} {{ s.r }}<br> {% endfor %}</td>
<td>Edit | Delete</td>
</tr>
{% endfor %}
</table>
I guess I'm not sure how to approach building the url for Delete. I can build a delete method and pass the id of the element I want to delete (ex: /delete/1), but is that not modifying data with a GET request then?
You can create a form that makes a POST request on submit, connected to a view that deletes the object when request.method is POST (passing the object ID in the URL, as you said).
I am not a Flask expert, but taking this code as example, your view should look something like:
#app.route('/delete/<int:id>', methods=['POST'])
def remove(id):
object = Object.query.get_or_404(id)
delete(object)
return redirect(url_for('index'))
And your form like:
<form method="post" action="{{ url_for('remove', id=object.id) }}">
<button type="submit">Delete</button>
</form>
The form action attribute forces the form to submit its information to the given URL/view.

How do I submit multiple forms with a single submit button in django?

I have managed to create the forms I need using modelformset_factory.
avaluos = Avaluo.objects.filter(Estatus__contains='CONCLUIDO',Factura__isnull=True)
FacturaFormset = modelformset_factory(Avaluo,form=FacturaForm,extra=0)
Currently this is generating the following HTML for each of the rows found:
<form id="id-FacturaForm" class="blueForms" method="post">[..]</form>
<form id="id-FacturaForm" class="blueForms" method="post">[..]</form>
<form id="id-FacturaForm" class="blueForms" method="post">[..]</form>
I want to submit all the forms using a single submit button.
Any ideas?
UPDATE
I ended up using django-crispy-forms which allowed me to gerate inputs for each row, and then I just manually added the form and submit.
self.helper.form_tag = False
{{example_formset.management_form }}
{% for a,b in olist %}
{{ b.id }}
<tr>
<td style="width:10px;"> {% crispy b %} </td>
<td> {{a.id}} </td>
</tr>
{% endfor %}
Read more into model formsets. You don't need to have separate form tags, it's the whole point of using a formset.
<form method="post" action="">
{{ factura_formset.management_form }}
<table>
{% for form in factura_formset %}
{{ form }}
{% endfor %}
</table>
</form>
Also, every time you use the id attribute more than once on a pageā€¦ a developer cries themselves to sleep somewhere in the world.
I suspect you will need to do it using Ajax - otherwise as soon as one form is submitted you will not be able to go the other way.
There are a few jQuery form libraries that should make it relatively straightforward. For example, http://malsup.com/jquery/form/.
It would look something like:
$('#button-id').click(function() {
$('.blueForms').ajaxSubmit();
});
Of course, you'll then need to deal with error handling and waiting for all the forms to have submitted.
If you're trying to create many instances of the "same" form (this is, they all look equal), as if it were one of many childs belonging to a single, master element, you don't actually need to create a form tag for each of the formsets.
If I'm not mistaken, you're trying to edit many facturas for a single avaluo object. Am I right? The representation would be a single "avaluo" form with many inline formsets, one for each "factura".
Check out the inline formsets factory instead of the modelformset factory.

Categories

Resources