In a simple view I pass a family in template like this:
def page(request):
family= Author.objects.all()
return render(request, "myapp/page.html", {'family':family})
and I render in template like this:
{% for item in family %}
{{ item.pk }}
{% endfor %}
But, if I put my family inside a for cycle; for example:
def page(request):
family = []
for i in range(5):
family= Author.objects.filter(name='John')[i]
return render(request, "myapp/page.html", {'family':family})
it not render anything in template...
Any idea?
EDIT 1
I have more users in my app, every user has different blog and every blog has different post...
So when user is logged i need to show his blog and for every blog show last 5 post.
I do:
#login_required
def page(request):
user = request.user.id
numblog = Blog.objects.filter(user_id=user).aggregate(c=Count('id'))
for i in range(numblog['c']):
blogquery = Blog.objects.filter(user_id=user)[i]
postquery = Post.objects.filter(blog_id=blogquery.pk)[:5]
return render(request, "myapp/page.html", {'blogquery ':blogquery,'postquery ':postquery })
expected result in template:
{% for b in blogquery %}
{{ b.name }} ### here name of blog
{% for p in postquery %}
{% if p.blog_id == b.pk %}
{{ p.content }} ### here last 5 post of THAT blog
{% endif %}
{% endfor %}
{% endfor %}
EDIT 2
In a view, if I print result it work but not render in template
#login_required
def page(request):
user = request.user.id
numblog = Blog.objects.filter(user_id=user).aggregate(c=Count('id'))
for i in range(numblog['c']):
blogquery = Blog.objects.filter(user_id=user)[i]
postquery = Post.objects.filter(blog_id=blogquery.pk)[:5]
for p in postquery:
print (blogquery.pk, p.pk)
return render(request, "myapp/page.html", {'blogquery ':blogquery,'postquery ':postquery })
It is surprising how you don't understand that repeatedly assigning to the same variable within a loop will just give you the last value.
But nevertheless, you don't need any of this code. You should just follow the relationship in the template.
#login_required
def page(request):
blogs = Blog.objects.filter(user=user).prefetch_related('post_set')
return render(request, "myapp/page.html", {'blogs ': blogs })
{% for blog in blogs %}
{{ blog.name }}
{% for post in blog.post_set.all|slice:"5" %}
{{ post.content }}
{% endfor %}
{% endfor %}
(You haven't shown your models so I presume the related_name from Blog to Post is called post_set, change as necessary.
UPDATE
That's not correct. You don't need to use for loop. If you need to get the last 5 rows you can do this i.e.:
def page(request):
family= Author.objects.all().order_by('-pk')[:5]
return render(request, "myapp/page.html", {'family':family})
another approach is to limit the results in your template:
{% for item in family %}
{% if forloop.counter < 6 %}
{{ item.pk }}
{% endif %}
{% endfor %}
I don't want to display a link if the list returns empty.
template.html
{% for item in cart %}
<h1>{{ item.product.product_title }}</h1>
Remove item
{% empty %}
<p>No items in cart</p>
{% endfor %}
{% if item is not None %}
<p>
Checkout
</p>
{% endif %}
views.py
def cartview(request):
if request.user.is_authenticated():
cart = Cart.objects.filter(user=request.user.id, active=True)
orders = ProductOrder.objects.filter(cart=cart)
#total = 0
count = 0
for order in orders:)
count += order.quantity
context = {
'cart': orders,
'count': count,
}
return render(request, 'store/cart.html', context)
else:
return redirect('index:index')
I want to hide checkout link if the cart list is empty. putting it in the for loop would make the link appear many times. I want to display checkout button only once.
Instead of 'item' check for 'cart' in the template.
{% if cart %}
<p>
Checkout
</p>
{% endif %}
have a table with websites and a many to one table with descriptions
trying to get a list, firstly getting the latest descriptions and then displaying them ordered by the content of the descriptions...
have the following in views.py
def category(request, category_name_slug):
"""Category Page"""
context_dict = {}
try:
category = Category.objects.get(slug=category_name_slug)
subcategory = SubCategory.objects.filter(category=category)
websites = Website.objects.filter(sub_categories=subcategory, online=True, banned=False)
sites = websites
descriptions = WebsiteDescription.objects.prefetch_related("about")
descriptions = descriptions.filter(about__in=sites)
descriptions = descriptions.order_by('about', '-updated')
descs = []
last_site = "" # The latest site selected
# Select the first (the latest) from each site group
for desc in descriptions:
if last_site != desc.about.id:
last_site = desc.about.id
desc.url = desc.about.url
desc.hs_id = desc.about.id
desc.banned = desc.about.banned
desc.referral = desc.about.referral
descs.append(desc)
context_dict['descs'] = descs
context_dict['websites'] = websites
context_dict['subcategory'] = subcategory
context_dict['category'] = category
except SubCategory.DoesNotExist:
pass
return render(request, 'category.html', context_dict)
this gives me a list with sites and their latest descriptions, so i have the following in category.html
{% if category %}
<h1>{{ category.name }}</h1>
{% for subcategory in category.subcategory_set.all %}
{{ subcategory.name }} ({{ subcategory.website_set.all|length }})
{% endfor %}
{% if descs %}
{% load endless %}
{% paginate descs %}
{% for desc in descs|dictsortreversed:"description"|dictsortreversed:"officialInfo" %}
<ul id='list' class='linksteps'>
<a href="/{{ desc.about_id }}" rel="nofollow" target="_blank">
<img src="/static/screenshots/{{ desc.about_id }}.png" />
</a>
<li><h3>{{ desc.about_id }}{% if desc.title %} - {{ desc.title }} {% endif %}</h3>
{% if desc.description %}<b>Description: </b>{{ desc.description }}
<br />{% endif %} {% if desc.subject %}<b>Keywords: </b>{{ desc.subject }}
<br />{% endif %} {% if desc.type %}<b>Type: </b>{{ desc.type }}
<br />{% endif %} {% if desc.officialInfo %} {% if desc.language %}<b>Language: </b>{{ desc.language }}
<br />{% endif %} {% if desc.contactInformation %}<b>Contact info: </b>{{ desc.contactInformation }}
<br />{% endif %}
{% else %}
{% endif %}
</li>
</ul>
</div>
{% endfor %}
{% show_pages %}
{% else %}
<strong>No websites currently in category.</strong>
{% endif %}
{% else %}
The specified subcategory {{ category_name }} does not exist!
{% endif %}
Initially i used dictsort
{% for desc in descs|dictsortreversed:"description"|dictsortreversed:"officialInfo"|dictsortreversed:"referral" %}
to give me the list in the desired order, so i was all happy ;)
Then however i decided i needed some pagination because the lists became too long.
django-endless-pagination works fine and does what its supposed too, however it splits up my list before the dictsort kicks in.
is there a way to sort before pagination happens and after i ordered_by at the initial query to have the latest descriptions selected?
much obliged
EDIT:
not getting any answers so my question might not be clear.
as far as i understand i need to sort the values in context_dict at the end in views.py replacing the dictsort as in the template
SOLVED:::
doing this did the trick for me to replace the dictsort.
descs1 = sorted(descs, key=operator.attrgetter('referral', 'officialInfo', 'description'), reverse=True)
context_dict['descs'] = descs1
SOLVED:::
doing this did the trick for me to replace the dictsort.
descs1 = sorted(descs, key=operator.attrgetter('referral', 'officialInfo', 'description'), reverse=True)
context_dict['descs'] = descs1
I am trying to get a batch notification to work, but the badge throws several badges with the below code, and it does not show the number. I want the badge to display the number of content within several posts matches with an interest.
I am still a beginner at django, so please bear over with me, if this is a total bad approach.
interest.html
{% for item in interest %}
<ul class='nav nav-pills nav-stacked'>
<li><a href='/'>
<span class='badge pull-right'>
{% for word in post %}
{% if word == interest %}
{{ word.as_number }}
{% else %}
0
{% endif %}
{% endfor %}
</span>
{{ item.interest }}
</a></li>
</ul>
{% endfor %}
context_processors.py
def user_interest(request):
interest = Interests.objects.all()
interests_form = InterestsForm(request.POST or None)
post = Posts.objects.all()
if interests_form.is_valid():
new_interest = interests_form.save(commit=False)
new_interest.save()
#return HttpResponseRedirect('/')
#apparently it is not needed here
return {'interest': interest,
'interests_form': interests_form,
'post': post,
}
models.py
class Interests(models.Model):
interest = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
I'm not fully understanding, but part of your problem may be this part:
{% if word == interest %}
You're comparing a particular Post with all of your Interests (since 'interest' = Interests.objects.all()). At the very least I would change that to:
{% if word == item %}
As this iterates through your interest list (using 'item') and compares it to each 'word' in your post list.
I want users to be able to query my database via several different parameters (name, year, etc), dynamically add more fields, and join them with boolean operators; the net result would be something like "year = 1900 AND name = chicken AND location = San Francisco." I think I'm doing something wrong, since it's not returning anything, even when I try just one field with a value that I know matches some data (e.g., I can get objects back when I use .filter() from the Django shell). Anyone know how I can fix it?
Relevant view (ignore the sloppy indentation, I didn't want to go through and fix all of it, but it's right in my actual code):
class BaseSearchFormSet(BaseFormSet):
def clean(self):
if any(self.errors):
return self.errors
queries = []
valid_courses = ["appetizer","main","dessert"]
valid_period = re.compile(r'\d\d\d0-\d\d\d5|\d\d\d5-\d\d\d0')
valid_year = re.compile(r'\d{4}')
multi_rows = ["year","period","course"]
for x in xrange(0,self.total_form_count()):
form = self.forms[x]
query = form.cleaned_data.get("query")
row = form.cleaned_data.get("row")
if query in queries and row not in multi_rows:
raise forms.ValidationError("You're already searching for %s.")
queries.append(query)
if row == "course" and query.lower() not in valid_courses:
raise forms.ValidationError("%s is not a valid course option."%(form.cleaned_data["query"]))
if row == "period" and not re.match(valid_period,query):
raise forms.ValidationError("%s is not a properly formatted period. Valid five-year periods span either the first or second half of a decade. For example: 1910-1915, 1925-1930."%(form.cleaned_data["query"]))
if row == "year" and not re.match(valid_year,query):
raise forms.ValidationError("Please enter a four-digit year.")
def search(request):
errors = []
searchFormSet = formset_factory(F.SearchForm, extra=1,formset=BaseSearchFormSet)
if request.GET:
formset = searchFormSet(request.GET)
forms = []
if formset.is_valid():
for x in xrange(0,formset.total_form_count()):
form = {}
form["row"]= formset[x].cleaned_data.get("row",None)
form["query"] = formset[x].cleaned_data.get("query",None)
form["bools"] = formset[x].cleaned_data.get("bools",None)
if form["query"]:
q = form["query"]
else:
errors.append("no query found")
if form["row"]:
row = form["row"]
else:
errors.append("no row found")
filter_keys = {"dish_name":Q(dish__name__icontains=q),
"regex":Q(dish__full_name__regex=r'%s'%(q)),
"course":Q(dish__classification=q.lower()),
"year":Q(page__menu_id__year__exact=q),
"period":Q(page__menu_id__period__exact=q),
"location":Q(page__menu_id__location__icontains=q),
"restaurant":Q(page__menu_id__restaurant__icontains=q)}
forms.append(form)
final_query=Q()
def var_reduce(op,slice):
if op == "and":
return reduce(lambda x,y: x & y,slice)
elif op == "or":
return reduce(lambda x,y: x | y,slice)
for x in xrange(len(forms)):
try:
try:
if final_query:
slice = [final_query,filter_keys[forms[x]["row"]],filter_keys[forms[x+1]["row"]]]
else:
slice = [filter_keys[forms[x]["row"]],filter_keys[forms[x+1]["row"]]]
final_query = var_reduce(forms[x]["bools"],slice)
except IndexError:
if final_query:
slice = [final_query,filter_keys[forms[x]["row"]]]
else:
slice = [filter_keys[forms[x]["row"]]]
final_query = var_reduce(forms[x]["bools"],slice)
items = MenuItem.objects.filter(final_query)
return render_to_response("search_results.html",{"items":items,"formset":formset})
except KeyError as e:
errors.append(e)
formset = searchFormSet(None)
return render_to_response("search_page.html",{"errors":errors,"formset":formset})
else:
formset = searchFormSet(None)
return render_to_response("search_page.html",{"errors":errors,"formset":formset})
else:
formset = searchFormSet(None)
return render_to_response("search_page.html",{"formset":formset})
models:
from django.db import models
class MenuItem(models.Model):
def format_price(self):
return "${0:0<4,.2f}".format(float(self.price))
def __unicode__(self):
return self.dish
dish=models.OneToOneField('Dish',to_field='mk')
price=models.CharField(max_length=5,blank=True)
page=models.OneToOneField('MenuPage')
mk=models.CharField(max_length=10,unique=True)
formatted_price = property(format_price)
class Menu(models.Model):
def period(self):#adapted from http://stackoverflow.com/questions/2272149/round-to-5or-other-number-in-python
try:
p=int(10*round(float(int(self.year))/10))
if p < self.year:
return "%s-%s"%(p,p+5)
else:
return "%s-%s"%(p-5,p)
except (ValueError,TypeError):
return ""
def __unicode__(self):
if self.restaurant:
return self.restaurant
else:
return self.mk
restaurant=models.TextField(unique=False,blank=True,null=True)
year=models.CharField(max_length=4,unique=False,blank=True,null=True)
location=models.TextField(unique=False,blank=True,null=True)
status=models.CharField(unique=False,max_length=20)
mk=models.CharField(max_length=8,unique=True,primary_key=True)
period=property(period)
language = models.CharField(unique=False,max_length=30)
#objects=MenuManager()
class MenuPage(models.Model):
mk=models.CharField(max_length=10,unique=True)
menu_id=models.OneToOneField("Menu",to_field='mk')
#objects=MenuPageManager()
class Dish(models.Model):
def __unicode__(self):
return self.name
full_name = models.TextField()
name=models.CharField(unique=True,max_length=255)
mk=models.CharField(max_length=10,unique=True)
class Classification(models.Model):
def __unicode__(self):
if self.classification:
return self.classification
else:
return "none"
dish=models.OneToOneField('dish',to_field='name')
classification=models.CharField(unique=False,max_length=9)
mk=models.CharField(max_length=10,primary_key=True)
html of my search page:
{% extends "base.html" %}
{% block style %}
<link rel="stylesheet" type="text/css" href="/static/search_style.css" />
{% endblock %}
{% block java %}
<script type="text/javascript" src="/static/searches.js"></script>
{% endblock %}
{% block title %}Search{% endblock %}
{% block head %}Search{% endblock %}
{% block content %}
{% autoescape off %}
<div id="searches">
<form id="search" action="" method="get">
<table border="0" cellpadding="0" cellspace="0">
<tbody class="search">
{% for form in formset.forms %}
<tr>
<td class="row">{{ form.row }}</td>
<td class="query">{{ form.query }}</td>
<td class="bool">{{ form.bools }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{ formset.management_form }}
<input type="submit" value="Submit" id="submit">
</form>
</div>
{% if formset.errors or errors %}
<div id="errors">
<h3>The following errors were encountered while trying to submit your search:</h3>
{% for x,y in formset.errors.items %}
<p>{{ x }} : {{ y }}</p>
{% endfor %}
{{ errors }}
</div>
{% endif %}
<div id="notes">
<p>Searching by dish names, locations, and restaurants is case-insensitive.</p>
<p>Searching by course uses case-insensitive exact matching. Valid courses are Appetizer, Main, and Dessert.</p>
<p>Years should be entered YYYY. Five-year periods span either the first or second half of a decade, and should be entered YYYY-YYYY. Example valid five-year periods are 1900-1905, 1995-2000, etc.</p>
<p>Regular expression search follows MySQL regular expression syntax, as described here.</p>
</div>
{% endautoescape %}
<br /><br /><br /><br /> <br /><br /><br />
{% endblock %}
{% block footer %}
<div id="warning">
<p>NOTE: This site and the information it contains are still in development. Some information may be missing or inaccurate.</p>
</div>
<div class="credits">
Created and maintained by Sam Raker and Rachel Rakov
<br />
Data graciously provided by What's on the Menu?
</div>
{% endblock %}
Sorry, my original post was more than you needed. To clarify, all you should need to do is:
Q(year__icontains=year_input_variable) | Q(city__icontains=city_input_variable) & Q(name__icontains=name_input_variable)
Use & for and, | for or.
What I had posted earlier is for if a query contains multiple words, it would either check to see if all of the words matched using operator.and or if any of the words matched using operator.or.