I'm stuck on a problem. I need to filter all of the listings using the list.id in the for loop. Unfortunately, the filter function in Django could not be parsed. Is there another solution or is there a way to work around it? How can you run a function in Django HTML template. Thanks!
index.html
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Active Listings</h2>
{% if not listing %}
<h3>Nothing listed...</h3>
{% endif %}
{% for list in listing %}
<h3>Listing: {{ list.title }}</h3>
{% if list.photo != "" %}
<img src="{{ list.photo }}">
{% endif %}
<p>{{ list.description }}</p>
{% if not bids.filter(listing=list.id) %} #This line could not be parsed
<h5>${{ list.price }}</h5>
{% else %}
<h5>${{ bids.filter(listing=list.id).order_by(-bids).first().bids }}</h5> #This line could not be parsed
{% endif %}
<p>
{% if not bids.filter(listing=list.id).count() %} #This line could not be parsed
0
{% else %}
{{ bids.filter(listing=list.id).count() }} #This line could not be parsed
{% endif %}
bid(s) so far.
{% if bids.filter(listing=list.id).order_by(-bids).first().bidder == user.username %} #This line could not be parsed
Your bid is the current bid.
{% elif not bids.filter(listing=list.id).order_by(-bids).first().bidder %} #This line could not be parsed
There is no bid.
{% elif bids.filter(listing=list.id).order_by(-bids).first().bidder != user.username %} #This line could not be parsed
{{ bids.filter(listing=list.id).order_by(-bids).first().bidder }} is the current bid. #This line could not be parsed
{% endif %}
</p>
{% if user.username != list.user and user.is_authenticated %}
<form action="{% url "index" %} method="post">
{% for form in forms %}
{{ form }}
<input type="submit" value="Bid">
</form>
{% endfor %%}
{% endif %}
<h4>Details</h4>
<ul>
{% if user.username == list.user %}
<li>Listed by: You</li>
{% else %}
<li>Listed by: {{ list.user }}</li>
{% endif %}
<li>Category: {{ list.category }}</li>
</ul>
<hr>
{% endfor %}
{% endblock %}
views.py
from .models import User, AuctionList, Bids, Comments
from .forms import AuctionForm, BidsForm
def index(request):
if request.method == "POST":
pass
else:
AL = AuctionList.objects.all()
Bd = Bids.objects.all()
forms = BidsForm()
return render(request, "auctions/index.html", {
"listing": AL.order_by("id"),
"bids": Bd,
"forms": forms
})
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class AuctionList(models.Model):
CATEGORY_CHOICES = [
('Books', 'Books'),
('Business & Industrial', 'Business & Industrial'),
('Clothing, Shoes & Accessories', 'Clothing, Shoes & Accessories'),
('Collectibles', 'Collectibles'),
('Consumer Electronics', 'Consumer Electronics'),
('Crafts', 'Crafts'),
('Dolls & Bears', 'Dolls & Bears'),
('Home & Garden', 'Home & Garden'),
('Motors', 'Motors'),
('Pet Supplies', 'Pet Supplies'),
('Sporting Goods', 'Sporting Goods'),
('Sports Mem, Cards & Fan Shop', 'Sports Mem, Cards & Fan Shop'),
('Toys & Hobbies', 'Toys & Hobbies'),
('Antiques', 'Antiques'),
('Computers/Tablets & Networking', 'Computers/Tablets & Networking')
]
id = models.AutoField(primary_key=True)
user = models.CharField(max_length=20, default='None')
title = models.CharField(max_length=20)
category = models.CharField(
max_length=30, choices=CATEGORY_CHOICES, default='Books')
description = models.TextField()
price = models.FloatField()
photo = models.URLField(max_length=200, blank=True)
def __str__(self):
return f"({self.id}) | Title: {self.title} | Category: {self.category} | Price: {self.price} | Posted by: {self.user}"
class Bids(models.Model):
bidder = models.CharField(max_length=20, default='None')
listing = models.ForeignKey(
AuctionList, on_delete=models.CASCADE, related_name="bids")
bids = models.FloatField()
def __str__(self):
return f"Listing Key: {self.listing} | Bids: {self.bids}"
You can create another function in your views.py and pass it in your index function (example below to give you some idea in views.py & index.html)
def build_auctions_layout(username):
final_html = None
for list in listing:
final_html = '<h3>Listing: {}</h3>'.format(list.title)
if list.photo:
final_html += '<img src="{}"'.format(list.photo)
final_html += '<p>{}</p>'.format(list.description)
if not list.bids: #This line could not be parsed
final_html += '<h5>${}</h5>'.format(list.price)
else:
final_html += '<h5>${}</h5>'.format(list.bids.order_by(-bids).first().bids ) #This line could not be parsed
final_html += '<p>{} bid(s) so far'.format(list.bids.count())
if list.bids.order_by(-bids).first().bidder == username:
final_html += 'Your bid is the current bid.</p>'
else:
final_html += 'There is no bid.</p>'
return final_html
def index(request):
if request.method == "POST":
pass
else:
AL = AuctionList.objects.all()
Bd = Bids.objects.all()
forms = BidsForm()
return render(request, "auctions/index.html", {
"listing": AL.order_by("id"),
"bids": Bd,
"forms": forms,
"auctions_layout": build_auctions_layout(request.user.username)
})
#auctions/index.html
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Active Listings</h2>
{% if not listing %}
<h3>Nothing listed...</h3>
{% endif %}
{{auctions_layout|safe}}
......
The answer is yes you can run filter function inside your html template. Infact filter functions are meant for and frequently used everywhere in django templates which you can find in django more precisely as Custom template filters
You can also create one filter function as per your requirement and use it anywhere inside your template which is known as Django Templatetags. These template tags are nothing but a sort of functions which you define yourself and implement in templates.Here I explain you step by step:
For referene, my project name is "working_blog_python" and app name is "branch"
1. open your terminal and type
(working_blog_python) $ cd branch
(working_blog_python) $ mkdir templatetags
(working_blog_python) $ touch templatetags/any_name_tags.py
2.Now inside your
any_name_tags.py
you can write your filter function like this
from django import template
register = template.Library()
#register.filter_function
def hrs(self):
return self.name.replace('-', ' ')
3.Now you can use this hrs() function anywhere in your templates, but don't forget to load {% load name_tags %} name_tag inside your template.
<p>Shop is located in {{branch.state | hrs | title}}.</p>
Related
What I want to do :
Display the human readable value of a charfield with choices via get_F00_display or other in views.py and then in template.
I have a Leave model for leaves management and want to display a template with all the leaves associated with the authenticated user.
What I have done :
Of course, I've read Django documentation (4.1) and find something interesting with get_F00_display but cannot make it works fine.
model.py (simplified)
class Leave(CommonFields):
LEAVES_TYPES = [
('10', _('Type 1')),
('20', _('Type 2')),
('30', _('Type 3')),
]
owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
type = models.CharField(max_length=3, choices=LEAVES_TYPES, null=True, default="10")
def __str__(self):
return self.owner.first_name + " " + self.owner.last_name + " : du " + self.begin_date.strftime("%d-%m-%Y") + " au " + self.end_date.strftime("%d-%m-%Y")
views.py
from django.shortcuts import render
from django.utils.translation import gettext as _
from .models import Leave
from django.views import generic
class LeaveListView(generic.ListView):
model = Leave
context_object_name = 'leave_list'
def get_queryset(self):
return Leave.objects.filter(is_active=True).values('type', 'begin_date','end_date','range','comment','status')
def get_context_data(self, **kwargs):
# Call the base implementation first to get the context
context = super(LeaveListView, self).get_context_data(**kwargs)
# Create any data and add it to the context
context['colHeaders'] = ['Type',
'From',
'To',
'Range',
'Comment',
'Status',]
return context
leave_list.html
{% extends "main/datatables.html" %}
<!-- TABLE TITLE -->
{% block tableTitle %}Leaves{% endblock %}
<!-- TABLE HEADER -->
{% block tableHeader %}
{% if colHeaders %}
{% for header in colHeaders %}
<th>{{header}}</th>
{% endfor %}
{% else %}
<p>No results</p>
{% endif %}
{% endblock %}
<!-- TABLE BODY -->
{% block tableBody %}
{% if leave_list %}
{% for leave in leave_list %}
<tr>
<td>{{leave.type}}</td>
<td>{{leave.begin_date}}</td>
<td>{{leave.end_date}}</td>
<td>{{leave.range}}</td>
<td>{{leave.comment}}</td>
<td>{{leave.status}}</td>
</tr>
{% endfor %}
{% else %}
<p>No results</p>
{% endif %}
{% endblock %}
<!-- TABLE FOOTER -->
{% block tableFooter %}
{% if colHeaders %}
{% for header in colHeaders %}
<th>{{header}}</th>
{% endfor %}
{% else %}
<p>No results</p>
{% endif %}
{% endblock %}
Problem :
{{leave.type}}
returns the key of the choices but I'm trying to display the human readable name in LEAVES_TYPES like "Type 1"...
What I've tried :
Using get_F00_display this way : get_type_display in my views.py :
def get_queryset(self):
return Leave.objects.filter(is_active=True).values(get_type_display, 'begin_date','end_date','range','comment','status')
Same thing in the template but no readable name displayed...
I want to customize django-admin's change form for video objects by adding block with moderation tools.
When I use custom simpletags in if condition - it doesn't work.
models.py:
class Video(models.Model):
class Meta:
db_table = 'video'
DRAFT = 1
MODERATION = 2
PUBLISHED = 3
REJECTED = 4
HOSTING_UPLOADING = 5
SUSPICIOUS = 6
PUBLICATION_STATUSES = (
(DRAFT, 'draft'),
(MODERATION, 'moderation'),
(PUBLISHED, 'published'),
(HOSTING_UPLOADING, 'hosting uploading'),
(REJECTED, 'rejected'),
(SUSPICIOUS, 'suspicious')
)
video_pk = models.AutoField(primary_key=True)
name = models.CharField(max_length=150, blank=True)
hosting_id = models.CharField(max_length=20, blank=True)
publication_status = models.PositiveSmallIntegerField(choices=PUBLICATION_STATUSES, default=MODERATION)
templatetags video_publication_statuses.py:
from api.models import Video
from django import template
register = template.Library()
#register.simple_tag
def moderation(status):
return status == Video.MODERATION
#register.simple_tag
def suspicious(status):
return status == Video.SUSPICIOUS
#register.simple_tag
def published(status):
return status == Video.PUBLISHED
#register.simple_tag
def hosting_uploading(status):
return status == Video.HOSTING_UPLOADING
#register.simple_tag
def rejected(status):
return status == Video.REJECTED
change_form.html:
{% extends "admin/change_form.html" %}
{% load video_publication_statuses %}
{% suspicious original.publication_status as suspicious_status %}
{% moderation original.publication_status as moderation_status %}
{% hosting_uploading original.publication_status as hosting_uploading_status %}
{% published original.publication_status as published_status %}
{% rejected original.publication_status as rejected_status %}
{% block after_related_objects %}
{% if original.pk %}
{% for fieldset in adminform %}
{% if fieldset.name == 'Moderation' %}
{% include "admin/includes/fieldset.html" %}
{% endif %}
{% endfor %}
<div class="submit-row">
{% if rejected_status or moderation_status or suspicious_status %}
<input type="submit" value="Publish" name="publish" >
{% endif %}
{% if published_status %}
<input type="submit" value="Reject" name="reject" >
{% endif %}
</div>
{% endif %}
{% endblock %}
When I use explicit values instead of tags it works:
{% if original.publication_status == 3 %}
<input type="submit" value="Reject" name="reject" >
{% endif %}
Please help me understand what is wrong with tags?
I believe this is happening because template tags pass strings and you're checking a string against an integer e.g. return "3" == 3
Broadly speaking though, you're putting a lot of logic in a template and I typically avoid that situation. Template tags are reserved for "presentation logic" and I take that to mean "changing the way something is presented", not changing what is viewed. That logic belongs in a view or the model itself.
It should be easy enough to put this logic on your model.
class Original(...):
def rejected(self):
return self.status == Video.rejected
I need to print the list of persons whose birthdays are today.
I do not know the correct way to introduce the current data variable in the if loop.
personal_list.html
{% for personal in personals %}
{% ifequal personal.data_nastere|date:"d/m" '??/??' %}
<ul>
<li><a class="titleOmagiat" href="{% url 'personalomagiat_detail' pk=personal.pk %}">
{{ personal.name }} {{ personal.surname }} </a>, {{ personal.birth_day|date:"d/m/Y" }}
</li>
</ul>
{% endifequal %}
{% endfor %}
models.py
class Personal(models.Model):
name = models.CharField(max_length=20)
surname = models.CharField(max_length=20)
birth_day = models.DateField(blank=True, null=True)
class Meta:
ordering = ['name']
def __str__(self):
return '%s %s' % (self.name, self.surname)
views.py
def personal_list(request):
personals = Personal.objects.order_by('name')
return render(request, 'blog/personal_list.html', {'personals': personals})
urls.py
urlpatterns = [
url(r'^personal/$', views.personal_list, name='personal_list'),
]
Tell me the correct answer in code.
The filtering must be done at the database level, not in the template, otherwise you are reading data from disk that you are not using which results in poor performances.
Update your view this way:
from django.utils import timezone
def personal_list(request):
today = timezone.now().date()
personals = Personal.objects.order_by('name').filter(
birth_day__month=today.month,
birth_day__day=today.day)
return render(request, 'blog/personal_list.html', {'personals': personals})
And your template this way:
<ul>
{% for personal in personals %}
<li><a class="titleOmagiat" href="{% url 'personalomagiat_detail' pk=personal.pk %}">
{{ personal.name }} {{ personal.surname }} </a>, {{ personal.birth_day|date:"d/m/Y" }}
</li>
{% endfor %}
</ul>
I am trying to follow this previous question here:
Django: getting the list of related records for a list of objects
but can't seem to get it to work.
I get a list of owners but do not get a list of pet names. The html code doesn't seem to execute the 2nd FOR loop. Any ideas?
models.py
class Teacher(models.Model):
teacher = models.CharField(max_length=300, verbose_name="teacher")
def __unicode__(self):
return self.teacher
class Owner(models.Model):
relevantteacher = models.ForeignKey(Teacher, verbose_name="teacher")
owner = models.CharField(max_length=300, verbose_name="owner")
def __unicode__(self):
return self.owner
class PetName(models.Model):
relevantowner = models.ForeignKey(Owner, verbose_name="owner")
pet_name = models.CharField(max_length=50, verbose_name="pet Name")
def __unicode__(self):
return self.pet_name
views.py
def ownersandteachers(request):
owners = Owner.objects.all()
context = {'owners': owners}
return render(request, 'ownersandpets.html', context)
template
{% for i in owners %}
{{ i.owner }} has pets:<br />
{% for v in owners.petname_set.all %} //this doesn't seem to be executing
- {{ v.pet_name }}<br />
{% endfor %}
{% endfor %}
You are doing
{% for v in owners.petname_set.all %}
where you should be doing
{% for v in i.petname_set.all %}
owners is the queryset, but you need to get the petname_set for the individual object in the queryset which is i in this case.
Also, I would recommend a condition check if i.petname_set exists. If not, do not show the has pets: text.
{% for i in owners %}
{{ i.owner }}
{% if i.petname_set.count %} has pets:<br />
{% for v in i.petname_set.all %} //this doesn't seem to be executing
- {{ v.pet_name }}<br />
{% endfor %}
{% endif %}
{% endfor %}
I'm having some trouble using get_absolute_url in a template. It seems to work fine if I just pass in one of my store objects and say {{ store.get_absolute_url }}, but if I have to iterate through a dictionary of stores and then use the get_absolute_url function, it returns nothing. Exactly what I'm doing is below:
class Store(EthicalObject):
type = "Store"
name = models.CharField(max_length=50)
company = models.ForeignKey(Company, verbose_name="Company", null=True, blank=True)
location = models.OneToOneField(Location, verbose_name="Location", null=True, blank=True)
products = models.ManyToManyField('Product', related_name="%(class)s_related", db_table=u'ethicsdb_products_to_stores', blank=True)
companies = models.ManyToManyField('Company', related_name="%(class)s_related", db_table=u'ethicsdb_companies_to_stores', blank=True)
def get_absolute_url(self):
return ('store_details', [str(self.id)])
get_absolute_url = models.permalink(get_absolute_url)
This works:
views.py:
def fetch_sidebar_data(shop_object):
sidebar_modules = {}
if shop_object.content_type.name == 'company':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'store':
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'product':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['tags'] = shop_object.tags
return sidebar_modules['related_stores'][1]
def company_details(request, company_id):
company = get_object_or_404(Company, id=company_id)
sidebar_modules = fetch_sidebar_data(company)
return render_to_response('company/details.html', {'company': company, 'sidebar_modules': sidebar_modules}, context_instance=RequestContext(request))
template:
{% extends "base-onecol.html" %}
{% block page_div_extra_attr %}class="twocol"{% endblock %}
{% block sidebar_content %}
<div id="sidebar-right">
<h1>{{ sidebar_modules.name }}{{sidebar_modules.get_absolute_url }}</h1>
</div>
{% endblock %}
This doesn't work:
views.py:
def fetch_sidebar_data(shop_object):
sidebar_modules = {}
if shop_object.content_type.name == 'company':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'store':
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['related_products'] = shop_object.products.all()
if shop_object.content_type.name == 'product':
sidebar_modules['related_stores'] = shop_object.stores.all()
sidebar_modules['related_companies'] = shop_object.companies.all()
sidebar_modules['tags'] = shop_object.tags
return sidebar_modules
template:
{% extends "base-onecol.html" %}
{% block page_div_extra_attr %}class="twocol"{% endblock %}
{% block sidebar_content %}
<div id="sidebar-right">
{% for module_name,module in sidebar_modules.items %}
{% ifequal module_name "related_stores" %}
<h3>Sold Here</h3>
{% for related_store in module.values %}
{{ related_store.name }}<br/>
{% endfor %}
{% endifequal %}
{% ifequal module_name "related_products" %}
<h3>Buy Local</h3>
{{ module }}<br/>
{% endifequal %}
{% ifequal module_name "related_companies" %}
<h3>
{{ module }}<br/>
{% endifequal %}
{% ifequal module_name "tags" %}
{{ module }}<br/>
{% endifequal %}
{% endfor %}
</div>
{% endblock %}
In the second one, I just get no return from get_absolute_url. I know it's working in other places when I print it out. Is this a Django bug, the inability to use get_absolute_url in a dictionary of dictionaries?
Wow, that was a rather convoluted question.
Your problem is here: {% for related_store in module.values %}
module is a QuerySet. .values is calling the QuerySet method which returns a dictionary containing the field values for each row. A dictionary has no get_absolute_url attribute, and get_absolute_url isn't a field in the model.
Just use {% for related_store in module %} and you'll be dealing with actual model instances rather than dictionaries, which means {{ related_store.get_absolute_url }} will work fine.