I'm trying to create an app with 2 pages, a general one an a view details page.
In both pages I need the image of the product. In the general view, the image appears, but not in the details page.
This is my html for details page:
<div class="span4">
<h2>{{ prod.name }}</h2><br>
<img alt="" src="{{ STATIC_URL }}{{prod.image}}"></a>
</div>
And here is the html for the general page (the same image is defined here as {{ values.3.0 }}):
{% for key, values in prodmatrix.items %}
<li class="span3">
<div class="product-box">
<span class="sale_tag"></span>
<p><img src="{{ STATIC_URL }}{{values.1.0}}" alt="" /></p>
{{ values.0.0 }}<br/>
Commodo consequat
<p class="price">#{{values.2.0}} #{{values.2.1}} #{{values.2.2}}</p>
</div></li>
{% endfor %}
Both templates are based on a base, which already imports:
{% load static %}
{% load i18n %}
{% load staticfiles %}
Here is the view for the detailed template:
def single_product(request, slug):
product = get_object_or_404(Product, slug=slug)
prod = Product.objects.get(slug=slug)
reviews = Review.objects.get(product=prod.id)
reviewmatrix = {}
i = 0
try:
for rev in reviews:
reviewmatrix[str(i)] = [[review.review_text]]
u = User.objects.get(username=rev.user)
i = i + 1
except:
u = User.objects.get(username=reviews.user)
reviewmatrix[str(i)] = [[reviews.review_text]]
return render_to_response('product_detail.html', {'prod':prod, 'reviews':reviews, 'user':u.first_name})
And here is the view for the general template
def home(request):
if request.user.is_authenticated():
user = request.user
prods = Product.objects.all()
i = 0
prodmatrix = {}
for prod in prods:
# 0 1 2 3
prodmatrix[str(i)] = [[prod.name], [prod.image], [], [prod.slug]]
review = Review.objects.get(product=prod.id) # ^ this is for tags
for tags in review.tag.all(): #
print tags.name
prodmatrix[str(i)][2].append(tags.name) # append only tags
i = i + 1
#for prod in prods:
# tags = Review.objects.filter(product=prod.id)
# for tag in tags:
# prodmatrix[str(i)] = [[prod.name], [prod.image], [tag]]
# i = i + 1
return render(request, 'home.html',{'prodmatrix':prodmatrix, 'prods':prods})
else:
products = Product.objects.all()
return render(request, 'home.html',{'products':products})
return render(request, 'home.html')
The second view is using the render shortcut, so the context processors are run, which includes the STATIC_URL variable in the context. The first view uses the old render_to_response shortcut, which by default does not run context processors. Change it to use render.
Related
I am putting together a template tag for active/currently visited links in a navigation bar so I can easily add the proper active CSS class to the link.
I am have created code that works fine for either a mix of passed in urls with the same url-parameters included, but it does not allow me to pass in urls that have different params.
{% make_active 'index' %} and {% make_active 'users' 1 %} could not be grouped together accurately as {% make_active 'index~users' 1 %} because I am using reverse() to see if the url exists.
What I want is to just check the names from each of the url pattern files in my project and if the name exists, then I return the appropriate active class...but I cannot figure out how to simply grab the names. Is this possible, or can someone help with the code?
#register.simple_tag(takes_context=True)
def make_active(context, view_names, *args, **kwargs):
print(args, kwargs)
if not kwargs.pop('class', None):
class_to_return = 'sidebar-item-active'
else:
class_to_return = kwargs.pop('class')
request = context.get('request')
if not request:
raise Exception('A request must be passed in for this to work')
names = view_names.split('~')
print(names)
current_url_active = False
for view in names:
print(view)
try:
# always include the client url
args_to_use = [request.client_url]
# append the passed args into the args for reversing the url name
args_to_use.extend(args)
reversed_path = reverse(view, args=args_to_use)
print(reversed_path)
current_url_active = True
except NoReverseMatch:
current_url_active = False
continue
if current_url_active:
break
return class_to_return if current_url_active else None
I figured out a way to gather the url names using dynamic imports, but after figuring out what I wanted to do I learned that I did not even need to go through the complexity of gathering all url names. Anyways here is that code:
def get_url_names():
from django.apps import apps
list_of_url_names = list()
list_of_all_urls = list()
for name, app in apps.app_configs.items():
mod_to_import = f'apps.{name}.urls'
try:
urls = getattr(importlib.import_module(mod_to_import), "urlpatterns")
list_of_all_urls.extend(urls)
except ImportError as ex:
# is an app without urls
pass
for url in list_of_all_urls:
list_of_url_names.append(url.name)
return list_of_url_names
While making that work I figured out all I needed to check was if I was on the current url name, which is easy to gather with request.path_info. So now my code can be changed like so
#register.simple_tag(takes_context=True)
def make_active(context, view_names, *args, **kwargs):
if not kwargs.get('class', None):
class_to_return = 'sidebar-item-active'
else:
class_to_return = kwargs.get('class')
request = context.get('request')
if not request:
raise Exception('A request must be passed in for this to work')
names = view_names.split('|')
current_url_name = resolve(request.path_info).url_name
for view in names:
if view == current_url_name:
return class_to_return
And now I can return the correct active link CSS class with my url tag like so:
<div class="collapse {% make_active 'users_index|users_actions|groups_index|groups_edit|users_create' class='show' %} " id="userCollapse">
<div class="card card-body">
{% if perms.users.view_customuser and perms.users.view_staff %}
<a class="dropdown-item {% make_active 'users_create|users_index|users_actions' %}"
href="{% url 'users_index' CLIENT.url_base %}"><i
class="fas fa-users"></i>
<span class="nav-item-text"> Users</span>
</a>
{% endif %}
{% if perms.auth %}
<div class="dropdown-divider"></div>
<a class=" dropdown-item {% make_active 'groups_index|groups_edit' %}"
href=" {% url 'groups_index' CLIENT.url_base %}">
<i class="far fa-user-plus"></i>
<span class="nav-item-text"> Group Permissions</span>
</a>
{% endif %}
</div>
</div>
[** found a fix, see below **]
I'm having trouble getting Django 2 Paginator to work with a modelformset. There are three models, Place & Hit (one-to-many), and Link. The 'validator' view pages through Place objects 1 at a time, builds a queryset of Hits filtered by the FK placeid. The context sent to the template includes 1) the formset=HitFormSet, 2) a 'records' list with only the one Place object, and 3) the Paginator page.
The template renders the single Place record on the left side, and a scrolling list of Hit forms on the right. The Hit form has two added fields, 'match' (3 radio buttons) and 'flag' (checkbox). The user selects those if one or more Hits match the Place. Upon submitting, a new Link record is created with a placeid, a hitid, and values from the radios and checkbox. Also, a 'reviewed' field in the Place record is set to True.
The code below works to load Place #1, then page through the records - displaying a Place and its Hits. Clicking the Save button creates a new Link record as desired. The problem is that after the save, although the next Page loads on the left, its corresponding hits don't. By displaying pprint(locals()) I can see the correct hits are in the queryset, but the Hit fields in the formset all retain the values from the previous set of forms. The Paginator is advancing and the next Place loads, but not its Hit formset.
I've banged at this for a couple days, read docs, searched, etc. Any ideas?
view.py
def validator(request):
record_list = Place.objects.order_by('placeid').filter(reviewed=False)
paginator = Paginator(record_list, 1)
page = request.GET.get('page')
records = paginator.get_page(page)
count = len(record_list)
context = {
'records': records,
'page': page if request.method == 'GET' else str(int(page)-1)
}
placeid = records[0].placeid
hitid = records[0].hitid
q = Hit.objects.filter(placeid=placeid)
HitFormset = modelformset_factory(
Hit, fields = ['id','hitid', ],form=HitModelForm,extra=0)
formset = HitFormset(request.POST or None, queryset=q)
context['formset'] = formset
if request.method == 'GET':
method = request.method
print('a GET')
else:
if formset.is_valid():
print('formset is valid')
for x in range(len(formset)):
link = Link.objects.create(
placeid = placeid,
hitid = formset[x].cleaned_data['hitid'],
match = formset[x].cleaned_data['match'],
flag = formset[x].cleaned_data['flag'],
)
# flag Place record as reviewed
matchee = get_object_or_404(Place, placeid = placeid)
matchee.reviewed = True
matchee.save()
else:
print('formset is NOT valid')
print(formset.errors)
pprint(locals())
return render(request, 'validator/template.html', context=context)
template.html
{% block content %}
<div class="pagination">
<span class="step-links">
... all standard, works fine
</span>
</div>
{% for record in records %}
{% if records.has_next %}
<!-- <form id="form_related" method="POST" action="" > -->
<form id="form_related" method="POST" action="?page={{ records.next_page_number }}" >
{% else %}
<form id="form_related" method="POST" action="" >
{% endif %}
{% csrf_token %}
{{ formset.management_form }}
<input type="hidden" name="placeid" value="{{ record.placeid }}" />
{% for form in formset %}
<div class="row">
<div class="col-sm-4 id="place-record">
<!-- Place attributes -->
</div>
<div class="col-sm-8" id="hit-forms">
<div id="review">
<span>{{ form.match }} flag: {{ form.flag_geom }}</span>
</div>
<div id="hit">
<!-- Hit attributes -->
</div>
</div>
</div>
{% endfor %}
{% endfor %}
{% endblock%}
The answer (or an answer) turned out to be doing a redirect immediately after the save/POST. The save of Link record removes the Place from the queue, so the page is always "1"
view.py
...
if formset.is_valid():
for x in range(len(formset)):
link = Link.objects.create(
placeid = placeid,
tgnid = formset[x].cleaned_data['tgnid'],
match = formset[x].cleaned_data['match'],
flag_geom = formset[x].cleaned_data['flag_geom'],
)
matchee = get_object_or_404(Place, placeid = placeid)
matchee.reviewed = True
matchee.save()
return redirect('/formset/?page='+page)
else:
print('formset is NOT valid')
print(formset.errors)
...
Even after going through similar STACKOVERFLOW solutions this doubt was not solved.
I have also been through other resources.
Been engaged in django since 2 days only !! :)
project -> winerama
app ->reviews
my views.py
def review_list(request):
latest_review_list =Review.objects.order_by('-pub_date')[:9]
context ={'latest_review_list': latest_review_list}
return render(request, 'reviews/review_list.html',context)
def wine_list(request):
wine_list =Wine.objects.order_by('-name')
context ={'wine_list':wine_list}
return render(request, 'reviews/wine_list.html',context)
def review_detail(request , review_id):
review = get_object_or_404(Review , pk = review_id)
context = {'review':review}
return render(request,'reviews/review_detail.html',context)
def wine_detail(request , review_id):
wine = get_object_or_404(Wine, pk = wine_id)
context = {'wine':wine}
return render(request,'reviews/wine_detail.html',context)
def add_review(request,wine_id):
wine = get_object_or_404(Wine , pk = wine_id)
form = ReviewForm(request.POST)
if form.is_valid():
rating = form.cleaned_data['rating']
comment = form.cleaned_data['comment']
user_name=form.cleaned_data['user_name']
review =Review()
review.wine = wine
review.user_name = user_name
review.user_name = user_name
review.rating =rating
review.comment = comment
review.pub_date = datetime.datetime.now()
review.save()
return HttpRespponseRedirect(reverse('reviews:wine_detail',args = (wine.id,)))
return render(request,'reviews/wine_detail.html',{'wine':wine,'form':form})`
reviews/urls.py
urlpatterns = [
# ex: /
url(r'^$', views.review_list, name='review_list'),
# ex: /review/5/
url(r'^review/(?P<review_id>[0-9]+)/$', views.review_detail, name='review_detail'),
# ex: /wine/
url(r'^wine$', views.wine_list, name='wine_list'),
# ex: /wine/5/
url(r'^wine/(?P<wine_id>[0-9]+)/$', views.wine_detail, name='wine_detail'),
url(r'^wine/(?P<wine_id>[0-9]+)/add_review/$', views.add_review, name='add_review'),
]
reviews/templates/reviews/base.html
{% block bootstrap3_content %}
<div class="container">
<nav class="navbar navbar-default">
<div class="navbar-header">
<a class="navbar-brand" href="{% url 'review_list' %}">Winerama</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>Wine list</li>
<li>Home</li>
</ul>
</div>
</nav>
<h1>{% block title %}(no title){% endblock %}</h1>
{% bootstrap_messages %}
{% block content %}(no content){% endblock %}
</div>
{% endblock %}
THANKS IN ADVANCE.
PLEASE HELP ME FOR THE SAME.
The error is self explanatory:
Somewhere in your template html you have written
{% url 'user_review_list' %}
That means you are calling user_review_list function, but it is not defined in views. Instead you have defined review_list function.
I use {extends 'xxx.html'} to make all templates have the same 'head' and 'tail', there's an user avatar area {{ avatar }} in head, but I use the same method to pass this avatar in every views, my index.html can't correctly show the avatar, but the other can, so I assume is something wrong with my index views.
Here's the index view:
def index(request):
if request.method == 'GET':
all_user = UserInfo.objects.all()
user = all_user.filter(username=request.user.username)
return render(request, 'index.html', {
"icon": user.icon,
"user": user.username,
})
And here's a part of views which could correctly show the avatar:
if request.user.is_authenticated():
my_fav = UserFavorite.objects.all()
my_fav_num = my_fav.filter(user=request.user).count()
my_posts_num = all_posts.filter(user=request.user).count()
my_msg = UserMessage.objects.all()
my_msg_num = my_msg.filter(user=request.user, has_read=False).count()
all_user = UserInfo.objects.all()
user = all_user.get(username=request.user.username)
return render(request, 'community.html', {
"all_posts": posts,
"post_num": post_num,
"animal_kind": animal_kind,
"post_kind": post_kind,
"sort": sort,
"my_fav_num": my_fav_num,
"my_posts_num": my_posts_num,
"my_msg_num": my_msg_num,
"icon": user.icon,
"user": user.username,
})
else:
my_fav_num = 0
my_msg_num = 0
my_posts_num = 0
return render(request, 'community.html', {
"all_posts": posts,
"post_num": post_num,
"animal_kind": animal_kind,
"post_kind": post_kind,
"sort": sort,
"my_fav_num": my_fav_num,
"my_posts_num": my_posts_num,
"my_msg_num": my_msg_num,
})
HTML code:
<div class="head_bar" style="z-index: 1;">
<a class="logo" href="{% url 'index' %}">Nostray</a>
<div class="nav_bar">
<a class="nav" href="{% url 'adopt:market' %}"><span class="roll" id="adopt">领养</span></a>
<a class="nav" href="{% url 'community:allpost' %}"><span class="roll" id="community">社区</span></a>
<a class="nav" href=""><span class="roll" id="charity">公益</span></a>
</div>
{% if request.user.is_authenticated %}
<div class="current_user"><a href="">
<img src="{{ MEDIA_URL }}{{ icon }}" title="登录状态:{{ user }}" class="curr_icon">
</a></div>
{% else %}
<button class="bar_btn1" onclick="location.href={% url 'login' %}">登录</button>
<button class="bar_btn2" onclick="location.href={% url 'registe' %}">注册</button>
{% endif %}
can't see why the index can't find the avatar.
In your index you have list of user but in you 'correctly show' user is single object and it has the attrs, you need replace
user = all_user.filter(username=request.user.username)
on
user = all_user.get(username=request.user.username)
# ^^^^
I'm trying to use django infinite pagination, but I'm getting this error:
TemplateSyntaxError at /
u'paginate' tag requires a variable name `as` argumnent if the queryset is provided as a nested context variable (prodmatrix.items). You must either pass a direct queryset (e.g. taking advantage of the `with` template tag) or provide a new variable name to store the resulting queryset (e.g. `paginate prodmatrix.items as objects`).
This is my template:
{% load endless %}
**{% paginate prodmatrix.items %}**
{% for key, values in prodmatrix.items %}
<li class="span3">
<div class="product-box">
<span class="sale_tag"></span>
<p><img src="{{ STATIC_URL }}{{values.1.0}}" alt="" /></p>
<h4>{{ values.0.0 }}</h4><br/>
<p class="category">{{values.2.0}} {{values.2.1}} {{values.2.2}}</p> </div>
</li>
{% endfor %}
{% show_pages %}
This is my view:
def home(request):
if request.user.is_authenticated():
print "login"
user = request.user
prods = Product.objects.all()
i = 0
print 'numero de produtos ' + str(len(prods))
prodmatrix = {}
for prod in prods:
# 0 1 2 3
prodmatrix[str(i)] = [[prod.name], [prod.image], [], [prod.slug]]
reviews = Review.objects.filter(product=prod.id) # ^ this is for tags
print str(len(reviews))
if len(reviews) != 0:
for review in reviews:
rev_alltags = review.tag.all()
for tags in rev_alltags[:3]: #
print tags.name
prodmatrix[str(i)][2].append(tags.name) # append only tags
print str(i)
i = i + 1
return render(request, 'home.html',{'prodmatrix':prodmatrix})
This error is occurring because you don't pass the template any variable called entries.
I don't know enough about the lib to give a solution but I believe you will need to do something along the lines of:
{% paginate prodmatrix.items %}