Django Object Filter - python

I have a simple filter where a user enters a string, term, which is compared against the column companyId in my local database. If there is a match, the appropriate record/s are then rendered in a table within my template. However, no data is being rendered in the template, only rows of empty fields matching the number of records for a particular query. I have similar logic used for displaying these records unfiltered which works fine.
Edit:
When I removed the key value and tried to render only the object such as {{ object }}, the following is displayed: (Opportunity: Opportunity object (8)
views.py
def opportunity_dashboard(request):
try:
term = request.GET.get('search_query')
if term:
filtered_objects = Opportunity.objects.filter(companyId__icontains=term)
filtered_local_zip = zip(filtered_objects)
context = {
'term': term,
'filtered_local_zip': filtered_local_zip,
'filtered_connectwise_zip': filtered_connectwise_zip
}
return render(request, 'website/opportunity_dashboard.html', context)
template.html
{% if term %}
{% for object in filtered_local_zip %}
<tr>
<th style="text-align: center;">
✎
</th>
<td>
<div class="select">
<select disabled id="bw_status" name="status">
<option value="{{ object.status }}">{{ object.status }}</option>
</select>
</div>
</td>
<td>
<a{{ object.opportunityName }}</a>
</td>
<td>{{ object.companyId }}</td>
<td>
<div class="select">
<select id="bw_account_manager" name="account_manager">
<option value="{{ object.accountManager }}">{{ object.accountManager }}</option>
</select>
</div>
</td>

You don't need zip() nor list() to iterate over a queryset in a Django template.
Simply pass it to the context.
filtered_local_zip = filtered_objects
and in the template iterate over it like you're already doing:
{% for object in filtered_local_zip %}
If you need to iterate over zip(), read this: https://stackoverflow.com/a/4238261/1307020
Which suggests either this
{% for object0, object1 in filtered_local_zip %}
or this
{{ object.0.property }}
Demonstration: https://repl.it/repls/UntidyLimpingCollaborativesoftware

Related

How to get class attributes in HTML

I have a few forms in my forms variable, which I took from my DB.
views.py:
def settings(request):
new_form = TrafficSourcesForm()
forms = [TrafficSourcesForm(instance=x) for x in TrafficSources.objects.all()]
return render(request, 'mainpage/dashboard.html', {'new_form': new_form, 'forms': forms, 'error': error})
MY HTML:
<h3>{{ error }}</h3>
{% for form in forms %}
<form method="POST" id="{{form.name.name}}">{% csrf_token %}</form>
{% endfor %}
<form method="POST" id="new-form"> {% csrf_token %}</form>
{% for form in forms %}
<tr>
<td>{{ form.name }}</td>
<td>{{ form.token }}</td>
<td><button class="btn btn-lg btn-success w-100">Save</button></td>
</tr>
{% endfor %}
<tr>
<td><input class="form-control" placeholder="Name" form="new-form"></td>
<td><input class="form-control" placeholder="API-token" form="new-form"></td>
<td><button class="btn btn-lg btn-success w-100" form="new-form">Add</button></td>
</tr>
I am making a kind of editable grid and using a table for my layout ( so I cannot put a form direct to a row). So I am making the forms separately with the new HTML 5 form tag.
But I cannot take out the name(HTML attr on my inputs) which == the name field in the DB. So I could make different forms for every single row in my database. Can you help me?
I was thinking about setting the id of the form from my forms object but it makes the same forms for every row.

Using distinct() with filter() in django

I'm trying to create a query in Django that calls unique rows (using distinct) that meet some condition of a filter (using filter)
here are the used files :
views.py
def cat_details(request, pk):
current_user = request.user
selected_cat = get_object_or_404(Category, pk=pk)
selected_items = ItemIn.objects.all().filter(item_category=selected_cat).values_list('item_name', flat=True).distinct()
all_cats = Category.objects.all()
cat_count = all_cats.count()
item_count = ItemIn.objects.values_list('item_name', flat=True).distinct().count() # returns a list of tuples..
#all_units = Item.objects.aggregate(Sum('item_quantity'))['item_quantity__sum']
context = {
#'all_units': all_units,
'item_count': item_count,
'cat_count': cat_count,
'selected_items': selected_items,
'selected_cat': selected_cat,
'current_user': current_user,
}
return render(request, 'townoftech_warehouse/cat_details.html', context)
The variable called selected_items is where the problem!
and here is how I used this view function
HTML
{% extends 'townoftech_warehouse/base.html' %}
{% block content %}
{% load static %}
<div class="card">
<div class="card-header">
الاصناف فى المخزن
</div>
<div class="card-body">
<h3 align="right"> {{ selected_cat }}</h3>
<footer><button type="button" class="btn btn-dark">تعديل إسم الفئة</button>
<button type="button" class="btn btn-dark">مسح الفئة</button>
</footer>
</div>
</div>
<div style="overflow: auto;height: 280px">
<table class="table table-bordered">
<tbody>
{% for item in selected_items %}
<tr align="right">
<th scope="row">{{ item.item_name }}</th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<br>
<br>
<div align="right"><button type="button" class="btn btn-danger">رجوع</button></div>
{% endblock %}
whenever I try to open this page the error I get is :
error
NoReverseMatch at /category/15/
Reverse for 'items' with arguments '('',)' not found. 1 pattern(s) tried: ['item\\/(?P<pk>[0-9]+)\\/$']
update
I've removed the link from the HTML files
changed
{% for item in selected_items %}
{{ item.item_name }}
{% endfor %}
to be like
{% for item in selected_items %}
<tr align="right">
<th scope="row">{{ item.item_name }}</th>
</tr>
{% endfor %}
the error disappeared but it gives me a list of empty values now!
selected_items variable contains list of string objects(item names). String dont have pk attribute, so item.pk in template returns nothing.
Istead of values_list you neet pass to template list of objects. If you are using postgres you can use distinct() with argument.
selected_items = ItemIn.objects.all().filter(item_category=selected_cat).distinct('item_name')
Otherwise you can try to use values with 'item_name', 'pk':
selected_items = ItemIn.objects.all().filter(item_category=selected_cat).values('item_name', 'pk').distinct()

Jinja dictionary value not showing

I'm working on a Flask App where I create a form with RadioFields as choices, and I also pass a param2 dict through to the jinja client-side.
I successfully render the individual Radiofields as subfields but I can not seem to render the text for the dict value that accompanies the key.
The label of the radiofield is also the key of the dict in param2, and I'm trying to get it's value printed next to the subfield.label text.
param2 looks like this:
param2{'Text Label1': 'completed', 'Text Label2': 'busy'}
When I print {{ param2 }} on the page, I get the dict as it should be.
{'Text Label1': 'completed', 'Text Label2': 'busy'}
Here is how I print the subfield and call the dict.
<form method="post">
<table>
{% for subfield in form.display %}
<tr>
<td> {{ form.csrf_token }} </td>
<td> {{ subfield }} {{ subfield.label }} </td>
<td> {{ param2[subfield.label] }} </td>
</tr>
{% endfor %}
</table>
<input type="submit" value="Generate">
<button type="reset" value="Reset">Reset</button>
</form>
When the code renders, the param2's <td> </td> is empty:
<tr>
<td> <input id="display-0" name="display" type="radio" value="5"> <label for="display-0">Text Label1</label> </td>
<td> </td>
</tr>
Output I'm trying to get
<> Text Label1 completed
<> Text Label2 busy
I found the problem.
As #sergey-shubin said, the subfield.label property of the form is an HTML construct,
meaning:
if you call {% subfield.label %}
then you will get <label for="display-0">Text Label1</label>. <-- HTML Construct
Solution:
You can extract the label itself from the construct by calling the text method subfield.label.text which yields Text Label1 from the HTML construct.
Answer found here

get nth item from for loop in a form - python/google app engine/jinja2

I have a list of members, from a for loop in jinja2 with select and option
I would like to be able to select one of the members from the for loop,
and add that member to another list of entries to an event, with the extra options available to the user. (getting the member is easy, from the value of the button, getting the options is the problem)
For example:
Jinja2 Template:
<form method="post" action="add_member_to_list">
<table>
{% for member in members %}
<tr>
<th>{{ member.name }}</th>
<td><input type="checkbox" name="in_out"></td>
<td><select name="day">
<option>Monday</option>
<option>Wednesday</option>
</select>
</td>
<td><button type="submit" name="id" value="{{ member.id }}">Add</button></td>
</tr>
{% endfor %}
</table>
</form>
in Google App Engine - Python
class AddUser(BaseHandler):
def post(self):
in_out = self.request.get("in_out")
id = self.request.get("id")
day = self.request.get("day")
In this scenario, self.response.get("day") only ever returns the option selected for the first iteration of the for loop.
The checkbox; self.request.get("in_out"), returns on or off as expected.
So submitting the nth iteration of the for loop:
"Monday" is always returned from select/option.
How can I get the select/option corresponding to the nth iteration of the for loop?
Thanks!
The simplest solution will be to move the form tag into your for loop
<table>
{% for member in members %}
<form method="post" action="add_member_to_list">
<tr>
<th>{{ member.name }}</th>
<td><input type="checkbox" name="in_out"></td>
<td><select name="day">
<option>Monday</option>
<option>Wednesday</option>
</select>
</td>
<td><button type="submit" name="id" value="{{ member.id }}">Add</button></td>
</tr>
</form>
{% endfor %}
</table>
So your resulting form has multiple fields with the same name, right?
Like for the first member, there is a and for the second member, there is also a ?
If so, forms don't support that. You have to have a unique name for each field. You'll have to throw in a memberID on each iteration of the loop, or come up with a better design. Something like <select name="day{{member.id}}"> would be a hacky fix.
Another way is you just leave the in_out and day OUT of the for loop, keep it outside.
I hope that helps.
I found a quite simple solution for this:
instead of
day = self.request.get("day")
I used
day = self.request.get_all("day")
Which returns a list of all the options from the select, including the option the user choose for the member.
Then, for the Add Button, instead of
<td><button type="submit" name="id" value="{{ member.id }}">Add</button></td>
I assigned the name "loop" and a value of {{ loop.index0}}
so,
self.request.get("loop")
returns the position of the member selected, corresponding the position on the day list of the target. voila.
The member I get from a hidden td instead of from the submit button.
The final code:
<form method="post" action="add_member_to_list">
<table>
{% for member in members %}
<tr>
<th>{{ member.name }}</th>
<td><input type="checkbox" name="in_out"></td>
<td>
<select name="day">
<option>Monday</option>
<option>Wednesday</option>
</select>
</td>
<td class="hidden"><input name="id" value="{{ member.id }}"></td>
<td><button type="submit" name="loop" value="{{ loop.index0 }}">Add</button></td>
</tr>
{% endfor %}
</table>
</form>
class AddUser(BaseHandler):
def post(self):
day = self.request.get_all("day")
id = self.request.get_all("id")
loop = self.request.get("loop")
target_day = day[int(loop)]
target_id = id[int(loop)]
Niiice.

How can i get the object in django admin change_list template

I want to override the django admin change_list page but i am not able to find how to get the actual object so that i can access the proerties like object.name
In the template they have this code
<tr >{% for item in result %}{{ item }}{% endfor %}</tr>
where is the actual object which i can use
EDIT:
It look like result is the row and item is the column. i want something like result.pk
This yield the list if results
https://github.com/django/django/blob/master/django/contrib/admin/templatetags/admin_list.py#L175
The context fed to change_list.html includes a cl entry corresponding to a contrib.admin.views.main.ChangeList object, which is the object containing the result list.
You can access the result list directly like this:
{% for object in cl.result_list %}
{{ object.field }}
{% endfor %}
The change list results are rendered as part of the change_list_results.html template through use of the result_list template tag. The change_list_results.html template also has the cl context variable present when rendering the template.
When the Django template is iterating over result in your example, result is a ResultList object which contains pre-rendered html, the underlying object which is being rendered is not made available.
To override the template at this level, it's likely you'll need to implement your own result_list type template tag which can return a list of results with the underlying objects attached as an attribute to each result.
In short it is likely that you will need to:
Create your own result_list template tag, based on the Django's implementation. Rather than have it return a results context as a list of ResultList prerendered html, have it return results containing objects which are both capable of being rendered to html, as well as each item having the original underlying object attached for later use in your template.
Override the change_list.html template to use your new tag rather than Django's result_list template tag.
Override the change_list_results.html template to make use of the extra information available from your template tag such as the presence of each underlying object.
As you've probably gathered, the admin app is quite tightly integrated through the layers. Changing its operation is non-trivial and requires changes and overrides in multiple parts of the source.
You can also override template you use for admin with "change_list_template" and then extend change_list template.
Like
class NoiseFilter200Admin(admin.ModelAdmin):
change_list_template = 'currencies/nf200_change_list.html'
list_filter = ['sectors',]
search_fields = ['name']
#list_filter = ( MarketCapFilter )
def market_cap_value(self, obj):
return obj.market_cap_value > 1000000000
def changelist_view(self, request, extra_context=None):
response = super().changelist_view(
request,
extra_context=extra_context,
)
try:
qs = response.context_data['cl'].queryset
except (AttributeError, KeyError):
return response
metrics = {
'total_volume': Sum('volume'),
'total_mcap': Sum('market_cap'),
}
response.context_data['nf_200_list'] = list(
qs
.values('rank','ticker','name','priceUSD','market_cap','volume','change_24h')
# .annotate(**metrics)
.order_by('-market_cap')[:200]
)
response.context_data['nf_200_totals'] = dict(
qs.aggregate(**metrics)
)
return response
Then in your template you go like this and iterate over results and you will have a look you want
{% extends "admin/change_list.html" %}
{% load humanize %}
{% load math_tags %}
{% block content_title %}
<h1> Noise Filter 200 </h1>
{% endblock %}
{% block result_list %}
<style>
.results table {
counter-reset: rowNumber;
}
.results tbody tr{
counter-increment: rowNumber;
}
.results tbody td.rank::before {
content: counter(rowNumber);;
}
</style>
<div style="margin: 10px 0;">Total MCap today: {{ nf_200_totals.total_mcap | intword }}, Total volume today: {{ nf_200_totals.total_volume | intword }} </div>
<div class="results">
<table>
<thead>
<tr>
<th>
<div class="text">
Rank
</div>
</th>
<th>
<div class="text">
Name
</div>
</th>
<th>
<div class="text">
Ticker
</div>
</th>
<th>
<div class="text">
PriceUSD
</div>
</th>
<th>
<div class="text">
Market cap
</div>
</th>
<th>
<div class="text">
Volume
</div>
</th>
<th>
<div class="text">
Change 24
</div>
</th>
</tr>
</thead>
<tbody>
{% for row in nf_200_list %}
<tr class="{% cycle 'row1' 'row2' %}">
<td class="rank"> </td>
<td> {{ row.name }} </td>
<td> {{ row.ticker }} </td>
<td> $ {{ row.priceUSD|to_string }} </td>
<td> {{ row.market_cap | intword }} </td>
<td> {{ row.volume | intword }} </td>
<td> {{ row.change_24h | percent}} </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block pagination %}{% endblock %}
Downside is you may use some functionality here that you get (like sorting).
My solution was to override result_list templatetag to add object in results
add custom result_list tag, I named it result_list_ext
from django.contrib.admin.templatetags.admin_list import result_headers, result_hidden_fields, ResultList, \
items_for_result
from django.contrib.admin.templatetags.base import InclusionAdminNode
from django.template import Library
register = Library()
def results(cl):
if cl.formset:
for res, form in zip(cl.result_list, cl.formset.forms):
yield (res, ResultList(form, items_for_result(cl, res, form)))
else:
for res in cl.result_list:
yield (res, ResultList(None, items_for_result(cl, res, None)))
def result_list(cl):
"""
Display the headers and data list together.
"""
headers = list(result_headers(cl))
num_sorted_fields = 0
for h in headers:
if h['sortable'] and h['sorted']:
num_sorted_fields += 1
return {
'cl': cl,
'result_hidden_fields': list(result_hidden_fields(cl)),
'result_headers': headers,
'num_sorted_fields': num_sorted_fields,
'results': list(results(cl)),
}
#register.tag(name='result_list_ext')
def result_list_tag(parser, token):
return InclusionAdminNode(
parser, token,
func=result_list,
template_name='change_list_results.html',
takes_context=False,
)
Actually all that we changed here is add res in yield
yield (res, ResultList(None, items_for_result(cl, res, None)))
In change_list_results.html in for loop we receive result and object. That's it, now we have object in our for loop and can use it
{% for object, result in results %}
{% if result.form.non_field_errors %}
<tr id="id_{{ object.pk }}" class="grp-errors">
<td colspan="{{ result|length }}">{{ result.form.non_field_errors }}</td>
</tr>
{% endif %}
<tr id="id_{{ object.pk }}" class="grp-row {% cycle 'grp-row-even' 'grp-row-odd' %}">
{% for item in result %}{{ item }}{% endfor %}
</tr>
{% endfor %}
Use custom result_list_ext instead of django result_list and don't forget to load this new template tag in the beginning of template with load tag
<!-- CHANGELIST-RESULTS -->
{% block result_list %}
{% result_list_ext cl %}
{% endblock %}

Categories

Resources