Accessing model data in Django template - python

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.

Related

Nested Django view with .html inserted using include tag

I would like to know if anyone has any best practice recommendations for rendering a view within a view in Django, or something with a similar effect where both views can have their own context and methods.
I am currently rendering the dropdown using the built-in include tag. So the nested .html is using the same Django view as the rest of the page. And all the context is coming from the main view as shown below. I would like to give this dropdown its own Django view so that I only perform certain database queries and other calculations if the dropdown is opened.
<div class="container-fluid">
<div class="row">
<div class="col-6">
</div>
<div class="col-2 d-flex justify-content-center">
{% include nested.html %}
</div> ...
It would be nice if someone with experience in this could let me know what they think, and if it even makes sense to try and split this into 2 views.
In summary. I would like to know if I can somehow render a separate view using something similar to the include Django tag. So that I have control over where the view gets rendered.
Below I have outlined my implementation of the solution below, using custom inclusion tags as suggested in the comments to my question.
You can make a custom template tag file in project directory and then register these in the template library. e.g:
template_tags.py
from django import template
from users.models import Organisation
register = template.Library()
#register.inclusion_tag('nested.html', takes_context=True)
def nested_template(context, param=None): #param to pass variables from main view
context.update({
'data_list': get_data_list(param)
'organisation_id': param,
})
return context
def get_data_list(self,param):
data_list = ... #do all queries needed.
return data_list
In the template tag you point to your nested.html which does whatever you need it to do. For example:
nested.html
{% for data in data_list %}
<h4> {{data}} </h4>
{% endfor %}
Then to include the template, in your main view template:
{% load nested_template %} #at the top or anywhere before using it
{% nested_template param %} #where you want the template included
Hopefully clear enough and may assist someone

deleting objects without refresh django

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.

How can I get a Django view.py to request a selected posts information such as primary key?

I have a Django project with an HTML file that lists all of the CSV files that have been uploaded to my Postgresql database and when you click on the CSV of interest a new page is rendered with the CSV model's basic information (name/time submitted).
This is the First Page:
{% for csv in Data_List %}
<button class="btn btn-primary" style = "font-size:1.2em;" >{{csv.name}}</button>
<br><br>
{% endfor %}
This is the second page:
<p>{{request.user.username}}'s Note
<h6>{{worklog.name}}
<br>
{{worklog.date}}
<br>
{{worklog.notes|safe}}
<br>
{{worklog.mycsv|safe}}
</h6>
</p>
However, my goal is that when you click the button a python VIEW will be passed (or just retrieve) the chosen posts primary key (or other information). I want to do this so the view can ask the database for the actual CSV and do some work.
How can I get a view.py to request a selected posts information such as primary key?
Thanks and Happy Coding
#The url
url(r'^anote/(?P<pk>\d+)$', views.A_Note, name = 'anote'),
#The view
def A_Note(request, pk):
#the rest of code here
return render(request, "some.html", {"thing":thing, "pk":pk, "etc":etc})
I learned that sharp brackets <> in a url passes the value through to the view where it can then be accessed as an argument when defining the view. From there it can easily be used in the code.
Thanks!

save dictionary to database from html template in flask

I will try my best to be as concise as possible.
In my back end, I have a list of dictionaries saved to a variable. Each dictionary represents a post from reddit and includes the score, url, and title.
Respectively, the template will loop through this list and then return the values of each of these keys to the user like so:
<table>
<tr>
{% for x in data[0:5] %}
<td>
{{ x['score'] }}
{{ x['title'] }}
<br>
<a href='/add_to_favorites'> Add To Favorites </a>
</td>
{% endfor %}
</tr>
</table>
As you can see, there's an tag which is linked to a function on my utils.py that is attempting to save the respective dictionary to the database (I have a model that represents the url, title, and score).
I feel as though my template is not representing the dictionary in the correct way, for my link to include the html as when it is pressed I receive a 404 error (though I have this route already defined in views.py - '/add_to_favorites' which calls my 'save_post' function).
def save_post():
data = get_info()
for post in data:
fav= Favorite(title=post.get('title'), url=post.get('url'), score=post.get('score'), user_id=current_user.id)
db.session.add(fav)
db.session.commit()
return redirect(url_for('favorites'))
and:
#app.route('/add_to_favorites')
#login_required
def add_to_favorites():
return save_post()
Am i going about this the wrong way? How can i make sure that the link/button is associated with only the html of the that it is included in?
Just need some guidance into the right direction here, not necessarily the code to fix it. Thank you

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