I am creating an app when a user can search for recipes by inputing some ingredients in search-field.
I would like to do that when search-field is empty or string is empty a user get error.message 'Please put input.' But after i have implemented message.error into views and template it only returns the same page without this informaton 'Please put input.'. Do you know what i made wrong here?
My views:
from django.shortcuts import render
from django.db.models import Q #new
from .models import Recipe
from .models import Ingredient
from django.contrib import messages
from django.shortcuts import redirect
def drink_list(request):
template = "drinks/drink_list.html"
return render(request, template)
def search_results(besos):
query = besos.GET.get('q')
if not query or query == ' ' or query == ' ' or query == ' ':
messages.error(besos, "Please put input")
return redirect('drink_list')
else:
q = Q()
for queries in query.split():
q |= (Q(ingredients__ingredient_name__icontains=queries))
#why it look for 'sok z cytryny' and show as well sok z limonki
results = Recipe.objects.filter(q)
template = "drinks/search_results.html"
context = {
'results' : results,
}
return render(besos, template, context)
My template search_results:
{% if results %}
{% for drink in results %}
<div>
<p>{{ drink.recipe_name }}</p>
<p>Preparation: {{ drink.preparation }}</p>
<p>Ingredients:
{% for ingredient in drink.ingredients.all %}
{{ingredient.ingredient_name}}{% if not forloop.last %},{% endif %}
{% endfor %}
</p>
</div>
{% endfor %}
{% elif messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% else %}
<div>Such ingredients do not exist</div>
{% endif %}
If there is no query term , you are currently redirecting to:
return redirect('drink_list')
but you are not passing the message on to the drink_list view.
In case of redirect, you can pass the message string as argument
return redirect('{}?message=Please put input'.format(reverse('drink_list)))
Then your drink_list template must include:
<ul class="messages">
<li>{{ message }}</li>
</ul>
You need to further modify your drink_list function to get the message argument:
def drink_list(request):
template = "drinks/drink_list.html"
message = request.GET.get('message', ''))
return render(request, template, message=message)
And finally your url must include the optional message argument :
path('drink_list/', views.drink_list,name='drink_list'),
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'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>
I'm trying to allow for dynamic template tags. Specifically, I have a menu setup that I'm defining in code vs templates. And I would like to render the menu label as {{ request.user }}. So how can I define that as a string in Python, and allow the template to parse and render the string as intended. And not just variables too, templatetags as well ({% provider_login_url 'google' next=next %}).
What am I missing?
Update with code:
I'm specifically designing my menus with django-navutils, but that's less important (basically the package just stores the defined data and then uses templates to render it).
from navutils import menu
top_horizontal_nav = menu.Menu('top_nav')
left_vertical_nav = menu.Menu('left_nav')
menu.register(top_horizontal_nav)
menu.register(left_vertical_nav)
sign_in = menu.AnonymousNode(
id='sign_in',
label='Sign In',
url='{% provider_login_url "google" next=next %}',
template='nav_menu/signin_node.html',
)
user = menu.AuthenticatedNode(
id='user_menu',
label='{{ request.user }}',
url='#',
template='nav_menu/username_node.html'
)
top_horizontal_nav.register(sign_in)
top_horizontal_nav.register(user)
What I would like to do, is now render these string values ('{{ request.user }}') in my templates
{% load navutils_tags %}
<li
class="{% block node_class %}nav-item menu-item{% if node.css_class %} {{ node.css_class }}{% endif %}{% if is_current %} {{ menu_config.CURRENT_MENU_ITEM_CLASS }}{% endif %}{% if has_current %} {{ menu_config.CURRENT_MENU_ITEM_PARENT_CLASS }}{% endif %}{% if viewable_children %} has-children has-dropdown{% endif %}{% endblock %}"
{% for attr, value in node.attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>
<a href="{{ node.get_url }}" class="nav-link"{% for attr, value in node.link_attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>{% block node_label %}{{ node.label }}{% endblock %}</a>
{% if viewable_children %}
<ul class="{% block submenu_class %}sub-menu dropdown{% endblock %}">
{% for children_node in viewable_children %}
{% render_node node=children_node current_depth=current_depth|add:'1' %}
{% endfor %}
</ul>
{% endif %}
</li>
So, for the above, where I'm rendering {{ node.label }}, how can I get the value stored in node.label to actually be parsed as a request.user? This similarly applies for the URL of value {% provider_login_url "google" next=next %}.
You can create a custom template tag and render those. Like this
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def render_nested(context, template_text):
# create template from text
tpl = template.Template(template_text)
return tpl.render(context)
Then in template
...
<a href="{{ node.get_url }}" class="nav-link"
{% for attr, value in node.link_attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>
{% block node_label %}{% render_nested node.label %}{% endblock %}
</a>
...
Haven't tested but I think it will work.
More on template: https://docs.djangoproject.com/en/dev/ref/templates/api/#rendering-a-context
More on custom tags: https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags
If I understand you well, you want to write template code that renders to template code and then be processed again. Something like ... meta-templates?
I can see you already figured out the first part, but now you need the resulting code to be parsed again in order to set the respective value for {{ request.user }}.
I achieve that by using middleware, but since parsing a template is an expensive operation I implemented some a mechanism to apply the "re-parsing" process just to urls/views of my selection.
The model.
class ReparsingTarget(models.Model):
url_name = models.CharField(max_length=255)
Simple enough, just a model for storing those URL names I want to be affected by the middleware.
The middleware.
class ReparsingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# We are no interested in whatever happens before
# self.get_response is called.
response = self.get_response(request)
# Now we will re-parse response just if the requested url
# is marked as target for re-parse.
if self._marked(request) and isinstance(response, TemplateResponse):
# Decode the template response code ...
content = response.content.decode('utf-8')
# Create a Template object ...
template = Template(content)
# Provide request to de context ...
context_data = response.context_data
context_data.update({'request': request})
# ... and renders the template back the the response.
response.content = template.render(Context(response.context_data))
return response
def _marked(self, request):
url_name = resolve(request.path_info).url_name
return ReparsingTarget.objects.filter(url_name=url_name).exists()
It is a really simple implementation, the tricky part for me was to figure out how to put the idea into Django code.
In practice.
Some model.
class Foo(models.Model):
label = models.CharField(max_length=255)
The template:
{% for foo in foos %}
{% comment %} Remember foo.label == '{{ request.user }}' {% endcomment %}
<p> Username: {{ foo.label }} </p>
{% endfor %}
The stored Foo instance:
And the result:
I have a template tag that renders some custom form widgets for me. When I upgraded to Django 1.8, it stopped working. I'm trying to figure out how to fix this issue.
What ends up rendering in the template for the form field is:
<project.appname.widgets.RadioFeedbackInput object at 0x10a8e5d50>
Below, in the template tag, I believe the issue is in the render_to_string. Any suggestions?
Here's my template tag:
from django import template
from django.template import loader, RequestContext
from django.template.defaultfilters import slugify
register = template.Library()
#register.tag
def render_form(parser, token):
"""Renders dynamic form accordingly"""
bits = token.split_contents()
if len(bits) < 2:
raise template.TemplateSyntaxError("%r tag takes at least one argument" % bits[0])
form = bits[1]
args = {}
# Parse extra "asvar" if given
if len(bits) > 2:
biter = iter(bits[2:])
for bit in biter:
if bit == "as":
args["asvar"] = biter.next()
else:
raise template.TemplateSyntaxError("%r tag got an unknown argument: %r" % (bits[0], bit))
return RenderFormNode(form, **args)
class RenderFormNode(template.Node):
def __init__(self, form, asvar=None):
self.form = form
self.asvar = asvar
def render(self, context):
context = context or {}
form = template.Variable(self.form).resolve(context)
try:
request = template.Variable('request').resolve(context)
except template.VariableDoesNotExist:
raise template.VariableDoesNotExist("The `render_form` template tag requires that the request context processor be enabled.")
# The question type is used to build out the template type.
template_path_context = {
'type': slugify(form.template_type)
}
template_list = [
'appname/question_types/%(type)s/form.html' % template_path_context,
'appname/question_types/%(type)s.html' % template_path_context,
'appname/%(type)s/form.html' % template_path_context,
'appname/form.html' % template_path_context
]
# Renders form, and saves to self.asvar if requested
context.update({'form': form})
rendered = loader.render_to_string(
template_list,
context
)
if self.asvar:
context[self.asvar] = rendered
return ''
return rendered
here's the widget template:
<div class="radio-button-block">
{% for fields in form %}
{% if forloop.first %}
<label>{{ fields.label|linebreaks }}</label>
<div class="radio-button">
{% endif %}
{% for field in fields %}
<div class="field">
{{ field }}
{% if field.errors %}
{% for error in field.errors %}
<div class="ui negative message">
{{ error }}
</div>
{% endfor %}
{% endif %}
{% if field.choice_feedback %}
<div class="feedback">
{{ field.choice_feedback|linebreaks }}
<a class="close-feedback ss-icon">close</a>
</div>
{% endif %}
</div>
{% endfor %}
{% endfor %}
</div>
</div>
I have a condition within a loop in my template like this:
{% for message in message_trash %}
<td><a href="#">
{% if request.session.user_email == message.message_user_reciever.user_email %}
{{ message.message_user_reciever.user_firstName }} {{ message.message_user_reciever.user_lastName }}
{% elif request.session.user_email == message.message_user_sender.user_email %}
{{ message.message_user_sender.user_firstName }} {{ message.message_user_sender.user_lastName }}
{% endif %}
</a><small>Friends</small></td>
{% endfor %}
but i don't know why i get this error when applying the url?
TemplateSyntaxError: Could not parse the remainder: '==message.message_user_reciever.user_email' from 'request.session.user_email==message.message_user_reciever.user_email'
Update:
this is the view and variables that i render to the template:
def trashMessages(request, userId):
if isMessageOwner(request, userId):
user = Users.objects.get(user_id=userId)
message_trash = Messages.objects.filter(Q(message_user_reciever= user, message_sender_type='TRASH') | Q(message_user_sender=user, message_reciever_type='TRASH'))
return render(request, 'navigation_messages.html', {'user': user, 'message_trash': message_trash, 'type': 'trash'})
On testing your code out, I can only replicate your issue is by swapping:
{% if request.session.user_email == message.message_user_reciever.user_email %}
for
{% if request.session.user_email ==message.message_user_reciever.user_email %}
Note the missing space. Is the snippet in your question exactly as it is in your template?