I am working on a Django project that serves as a grocery store. I am trying to set it up so that when people click on checkboxes and press the confirm purchase button, then the values from the checkboxes will print to a new HTML template. The problem I am having is that when I go to the new template it doesn't print the values from the checkboxes.
Views.py
class PostListView(ListView):
model = Post
template_name = 'blog/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
def inventory(request):
products = request.POST.getlist('products')
for product in products:
a = Post.objects.get(title=product)
a.quantity = a.quantity -1
a.save()
print(products)
return render(request, 'blog/confirm.html')
Home.html
{% extends "blog/base.html" %}
{% block content %}
<form action="{% url 'inventory' %}" method="POST" id="menuForm">
{% for post in posts %}
{% if post.quantity > 0 %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2">{{ post.category }}</a>
</div>
<h2><a class="article-title" >{{ post.title }}</a></h2>
<p class="article-content"> Price: ${{ post.Price }}</p>
<p class="article-content"> Sale: ${{ post.Sale }}</p>
<input type="checkbox" id="product_{{ post.id }}" value="{{ post.title }}" form="menuForm" name="products" > Inventory count: {{ post.quantity }}
</input>
</div>
</article>
{% else %}
{% endif %}
{% endfor %}
<button type="submit" form="menuForm">Confirm Purchase</button>
</form>
{% endblock content %}
confirm.html
{% extends "blog/base.html" %}
{% block content %}
{% for post in posts %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2">{{ post.category }}</a>
</div>
<h2><a class="article-title" >{{ post.title }}</a></h2>
<p class="article-content"> Price: ${{ post.Price }}</p>
<p class="article-content"> Sale: ${{ post.Sale }}</p>
<input type="checkbox" id="product_{{ post.id }}" value="{{ post.title }}" form="menuForm" name="products" > Inventory count: {{ post.quantity }}
</input>
</div>
</article>
{% endfor %}
{% endblock %}
urls.py
path('list/', PostListView.as_view(), name='blog-home'),
path('confirm', views.inventory, name='inventory'),
It's happening because of this you did not passed posts on confirm.html page
def inventory(request):
posts = Post.objects.get(title=product)
products = request.POST.getlist('products')
for product in products:
a = Post.objects.get(title=product)
a.quantity = a.quantity -1
a.save()
print(products)
return render(request, 'blog/confirm.html',{'posts':posts})
Related
I have a problem on a custom widget for a RadioField Wtforms used inside a Flask app.
The custom widget is rendered well, but it DOES NOT WORK because it does not set the "checked" on the field after choosing it. If instead I use the default widget everything is fine and it works.
I also tried another more standard way, that is the "real" custom widget called inside the form class definition ... but I have the exact same result.
Below is the code, any suggestions? Thanks :-)
#### ROUTE
bp = Blueprint('auth', __name__, url_prefix='/auth')
#bp.route('/generic_crud', methods=('GET', 'POST'))
#login_required
def generic_crud():
form = forms.BaseGenericForm()
if form.validate_on_submit():
# Insert the msg
models.BaseGenericFormTable.add_record( title_select = form.titleSelect.data,
title_radio = form.titleRadio.data,
title_checkbox = form.titleCheckbox.data )
return render_template('sample_wtforms/success.html')
return render_template('sample_wtforms/crud_generic.html', form=form)
#### FORM
class BaseGenericForm(FlaskForm):
titleSelect = SelectField( 'Title Select',
validators=[DataRequired(message='Title Select missed')],
choices=[ ('farmer' , 'Farmer'),
('politician', 'Corrupt Politician'),
('cop', 'No-nonsense City Cop'),
('rocket', 'Professional Rocket League Player'),
('lonely', 'Lonely Guy At A Diner'),
('pokemon', 'Pokemon Trainer')],
render_kw={"class":"custom-select"}
)
titleRadio = RadioField('Title Radio',
validators=[DataRequired(message='Title RadioBox missed')],
choices=[ ('farmer' , 'Farmer'),
('politician', 'Politician'),
('cop', 'No-nonsense Cop'),
('lonely', 'Lonely Guy'),
('pokemon', 'Trainer')]
)
titleCheckbox = RadioField('Title Checkbox',
validators=[DataRequired(message='Title CheckBox missed')],
choices=[ ('farmer' , 'Farmer'),
('politician', 'Politician'),
('cop', 'No-nonsense Cop'),
('lonely', 'Lonely Guy'),
('pokemon', 'Trainer')]
)
submit = SubmitField( 'Submit',
render_kw={"class":"btn btn-primary"}
)
#### TEMPLATE jinja2
{% block content %}
<form method="POST" class="container">
<!-- titleSelect -->
<div class="form-group row">
{{ form.titleSelect.label(class='col-4 col-form-label') }}
<div class="col-8">
{{ form.titleSelect }}
{% if form.titleSelect.errors %}
<div class="alert alert-danger" role="alert">
<ul class="errors">
{% for error in form.titleSelect.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
<!-- titleRadio -->
<div class="form-group row">
{{ form.titleRadio.label(class='col-4 col-form-label') }}
<div class="col-8">
{#{{ form.titleRadio }}#}
{% for value, label, selected in form.titleRadio.iter_choices() %}
<div class="custom-control custom-radio custom-control-inline">
<input id="radio{{ loop.index0 }}" name="titleRadio" type="radio" class="custom-control-input" value="{{ value }}" {% if selected %} checked="checked" {% endif %}>
<label for="radio{{ loop.index0 }}" class="custom-control-label">{{ label }}</label>
</div>
{% endfor %}
{% if form.titleRadio.errors %}
<div class="alert alert-danger" role="alert">
<ul class="errors">
{% for error in form.titleRadio.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
<!-- titleCheckbox ################################################ -->
<div class="form-group row">
{{ form.titleCheckbox.label(class='col-4 col-form-label') }}
<div class="col-8">
{#{{ form.titleCheckbox }}#}
{% for value, label, selected in form.titleCheckbox.iter_choices() %}
<div class="custom-control custom-checkbox custom-control-inline">
<input id="checkbox{{ loop.index0 }}" name="checkbox" type="checkbox" class="custom-control-input" value="{{ value }}" {% if selected %} checked="checked" {% endif %}>
<label for="checkbox{{ loop.index0 }}" class="custom-control-label">{{ label }}</label>
</div>
{% endfor %}
{% if form.titleCheckbox.errors %}
<div class="alert alert-danger" role="alert">
<ul class="errors">
{% for error in form.titleCheckbox.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
{{ form.csrf_token }}
<div class="form-group row">
<div class="offset-4 col-8">
{{ form.submit }}
</div>
</div>
</form>
{% endblock %}
For a custom widget I do:
<div id="{{ field.id }}">
{{ field.label(class="form-label") }}<br>
{% for subfield in field %}
<div class="form-check form-check-inline">
<input {% if subfield.checked %}checked {% endif %}type="radio" class="form-check-input" id="{{ subfield.id }}" name="{{ field.id }}" value="{{ subfield.id[-1] }}">
{{ subfield.label(class="form-check-label") }}
</div>
{% endfor %}
</div>
The relevant part for you should be "{% if subfield.checked %}checked {% endif %}"
I have set up my blog so that when a user clicks on the displayed name, it will go to that user's blogs (filtered that so only that person's blogs will show up). I used {{ view.kwargs.username }} to show the person's username, but I'd rather show the first name. What can I change to accomplish this?
blog/templates/blog/user_post.html:
{% extends 'blog/base.html' %}
{% block content %}
<h1 class="mb-3">Posts by {{ view.kwargs.username }} ({{ page_obj.paginator.count }})</h1>
{% for post in posts %}
<article class="media content-section">
<img class="rounded article-img mt-2" src="{{ post.author.profile.image.url }}" alt="">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="{% url 'user-posts' post.author.username %}">{{ post.author.profile.user.first_name }} {{ post.author.profile.user.last_name }}</a>
<small class="text-muted">{{ post.date_posted|date:"F d, Y" }}</small>
</div>
<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content }}</p>
</div>
</article>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info mb-4" href="?page=1">First</a>
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-info mb-4" href="?page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="btn btn-outline-info mb-4" href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}
{% endblock content %}
blog/urls.py:
path('user/<str:username>/', UserPostListview.as_view(), name='user-posts'),
blog/views.py:
class UserPostListview(ListView):
model = Post
template_name = 'blog/user_posts.html'
context_object_name = 'posts'
# ordering = ['-date_posted']
paginate_by = 10
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-date_posted')
You can use a django templatetags:
In your app, create a directory called templatetags and create a file
myapp/templatetags/mytemplates.py
from django import template
def extractFirstName( username ):
return username.split()[0] # or whatever to return the first name
register = template.Library()
register.filter( 'extractFirstName', extractFirstName )
Then in your html
{% extends 'blog/base.html' %}
{% load mytemplates %}
{% block content %}
<h1 class="mb-3">Posts by {{ view.kwargs.username | extractFirstName }} ...>
<!-- all your other stuff -->
{% endblock %}
I've been trying to add a like button that changes to unlike when the User clicks on it, however the button isn't changing because I am unable to pass the context to the home.html file. I know the logic i used will throw an error as the get_object_or_404() will not receive an id from the server however if I pass an argument id to the home() function it will also throw an error as the server doesn't provide an id to the page. I'm sorry for asking a question related to logic and not concepts but I haven't been able to understand which concept could i use here
views.py
from django.shortcuts import render,get_object_or_404
from django.views.generic import ListView
from .models import Blog
from django.http import HttpResponseRedirect
def home(request):
post=get_object_or_404(Blog,id=id)
context={
'posts':Blog.objects.all(),
'is_liked':post.likes.filter(id=request.user.id).exists()
}
return render(request,'blog-home',context)
def like_post(request, blog_id):
post = get_object_or_404(Blog, id=blog_id)
is_liked=False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
is_liked=False
else:
post.likes.add(request.user)
is_liked=True
context={
'is_liked':is_liked
}
return HttpResponseRedirect(Blog.get_absolute_url(blog_id))
def post_detail(request, id):
post=get_object_or_404(Blog, id=id)
context={
'post':post,
'is_liked': post.likes.filter(id=request.user.id).exists(),
}
return render(request, 'blog/post_detail.html',context)
def check_liked(request):
post = get_object_or_404(Blog, id=blog_id)
is_liked=False
if post.likes.filter(id=request.User.id).exists():
is_liked=True
else:
is_liked=False
context={
'is_liked':is_liked
}
return render(request, 'blog/post_detail.html',context)
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class Blog(models.Model):
title=models.CharField(max_length=100)
content=models.TextField()
date_posted=models.DateTimeField(default=timezone.now)
author=models.ForeignKey(User, on_delete=models.CASCADE)
likes=models.ManyToManyField(User,related_name='likes',blank=True)
def __str__(self):
return self.title
def get_absolute_url(blog_id):
return reverse('post-detail',args=[str(blog_id)])
urls.py
from django.urls import path
from . import views
urlpatterns=[
path('',views.home,name='blog-home'),
path('<int:blog_id>/like/', views.like_post, name='like_post'),
path('post/<int:id>/', views.post_detail, name='post-detail'),
]
home.html
{% block content %}
{% for post in blogs %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}">
<div class="media-body">
<div class="article-metadata">
<h2>{{ post.author }}</h2>
<small class="text-muted">{{ post.date_posted|date:"F d, Y" }}</small>
</div>
<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content }}</p>
</div>
<div>
<form action="{% url 'like_post' post.id %}">
{% csrf_token %}
<form action="{% url 'is_liked' %}">
{% if is_liked %}
<button type='submit' name='blog_id' value="{{ post.id }}" class="btn btn-danger">Unlike</button>
{% else %}
<button type='submit' name='blog_id' value="{{ post.id }}" class="btn btn-primary">Like</button>
{% endif %}
</form>
</form>
</div>
</article>
{% endfor %}
{% endblock %}
post_detail.html
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}">
<div class="media-body">
<div class="article-metadata">
<h2>{{ post.author }}</h2>
<small class="text-muted">{{ post.date_posted|date:"F d, Y" }}</small>
</div>
<h2>{{ post.title }}</h2>
<p class="article-content">{{ post.content }}</p>
</div>
<div>
<form action="{% url 'like_post' post.id %}">
{% csrf_token %}
{% if is_liked %}
<button type='submit' name='blog_id' value="{{ post.id }}" class="btn btn-danger">Unlike</button>
{% else %}
<button type='submit' name='blog_id' value="{{ post.id }}" class="btn btn-primary">Like</button>
{% endif %}
</form>
</div>
</article>
You can use ajax for getting the functionality you want. In your home.html, you can make changes as:
{% block content %}
{% for post in blogs %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}">
<div class="media-body">
<div class="article-metadata">
<h2>{{ post.author }}</h2>
<small class="text-muted">{{ post.date_posted|date:"F d, Y" }}</small>
</div>
<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content }}</p>
</div>
<div>
<button type='button' onclick="change_status(this)" id="{{post.id}}" name='blog_id' value="{{ post.id }}" class="btn btn-primary"></button>
</div>
</article>
{% endfor %}
{% endblock %}
<script>
function change_status($this){
var request_data = $this.id;
console.log("data: " + request_data);
$.post({
url: "url that leads to your view",//url to like_post in your case(pass the request_data value in the url as the url needs the post id)
data : { request_data: request_data},
success : function(json) {
if(data.is_liked == True){ //perform a check of returned data(dont know actual implementation but you can google it)
document.getElementByName('blog_id').innerHTML = "Unlike" }
else{
document.getElementByName('blog_id').innerHTML = "Like"
}
}
})}
</script>
The functionality can be achieved by something like this but you may need to perform some changes in it.
I am having some trouble getting a drilldown for mptt in my template.
I have the following model.
models.py
class Dimension_value(MPTTModel):
name = models.CharField(max_length = 200, null=True, blank = True, default = '')
parent = TreeForeignKey("self", on_delete=models.CASCADE, null=True, blank=True, related_name="children")
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
return self.name
views.py
def show_dimensions(request):
return render(request, "accounts/dimension_detail.html", {'dimensions': Dimension_value.objects.all()})
template.py
{% extends 'base.html' %}
{% block head %}
{% endblock %}
{%block body%}
<div class="container-fluid">
<div class="card">
<div class="card-body">
<h2>My dimensions</h2>
{% load mptt_tags %}
{% drilldown_tree_for_node dimensions as drilldown cumulative count accounts.Dimension_value.name in game_count %}
{% for node,structure in drilldown|tree_info %}
{% if structure.new_level %}<ul><li>{% else %}</li><li>{% endif %}
{% if node == dimension %}
<strong>{{ node.name }}</strong>
{% else %}
{{ node.name }}
{% if node.parent_id == dimension.pk %}({{ node.game_count }}){% endif %}
{% endif %}
{% for level in structure.closed_levels %}</li></ul>{% endfor %}
{% endfor %}
</div>
</div>
<br>
<br>
<a class="btn btn-primary" href="{% url 'add_plan' %}" role="button">Add a plan</a>
<button onclick="goBack()" class = "btn btn-secondary">Go Back</button><br><br><a class="btn btn-primary" href="{% url 'subscribeusertoplan' %}" role="button">Add a user to plan</a>
</div>
{%endblock%}
I have added the view according to the documentation found here: https://django-mptt.readthedocs.io/en/latest/templates.html?highlight=examples#examples
However I get the following error.
Exception Type: AttributeError
Exception Value:
'TreeQuerySet' object has no attribute '_tree_manager'
Hope someone can nudge me in the right direction. Thanks!
You can do this by using some css and jquery
{% block head %}
{% endblock %}
{%block body%}
<div class="container-fluid">
<div class="card">
<div class="card-body">
<h2>My dimensions</h2>
{% load mptt_tags %}
{% recursetree dimensions %}
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{node.level}}" aria-expanded="false" aria-controls="collapsed">
{{ node.name }}</a>
{% if not node.is_leaf_node %}
<ul class="children">
<div id="collapse{{node.level}}" class="children panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
{{ children }} </div>
</div>
</ul>
{% endif %}
{% endrecursetree %}
</div>
</div>
<br>
<a class="btn btn-primary" href="{% url 'add_plan' %}" role="button">Add a plan</a>
<button onclick="goBack()" class = "btn btn-secondary">Go Back</button><br><br><a class="btn btn-primary" href="{% url 'subscribeusertoplan' %}" role="button">Add a user to plan</a>
</div>
{%endblock%}
I have a django for loop that is supposed to add items inside a form element. However, when the code executes, django just puts the first element inside the form and puts the following element outside the form html tag.
The code is:
<form action="." method="post" class="basket_summary" id="basket_formset">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{% with line=form.instance product=form.instance.product %}
{% purchase_info_for_line request line as session %}
<div class="row no-margin cart-item">
{{ form.id }}
<div class="col-xs-12 col-sm-2 no-margin">
{% with image=product.primary_image %}
{% thumbnail image.original "100x100" upscale=True as thumb %}
<a href="{{ product.get_absolute_url }}" class="thumb-holder">
<img class="lazy" alt="" src="{{ thumb.url }}" />
</a>
{% endthumbnail %}
{% endwith %}
</div> <!-- /.thumbnail holder -->
<div class="col-xs-12 col-sm-5 ">
<div class="title">
{{ line.description }}
</div>
{% trans "Update" %}
{% if user.is_authenticated %}
| {% trans "Save for later" %}
{% endif %}
<div style="display:none">
{{ form.save_for_later }}
{{ form.DELETE }}
</div>
{% for field_errors in form.errors.values %}
{% for error in field_errors %}
<span class="error-block"><i class="icon-exclamation-sign"></i> {{ error }}</span>
{% endfor %}
{% endfor %}
</div> <!-- /.Title holder -->
<div class="col-xs-12 col-sm-3 no-margin">
<div class="quantity">
<div class="le-quantity">
<form>
<a class="minus" href="#reduce"></a>
<input name="form-0-quantity" id="id_form-0-quantity" readonly="readonly" type="text" value="{{ form.quantity.value }}" />
<a class="plus" href="#add"></a>
</form>
</div>
</div>
</div><!-- /.Quantity Holder -->
<div class="col-xs-12 col-sm-2 no-margin">
<div class="price">
{% if line.is_tax_known %}
{{ line.unit_price_incl_tax|currency:line.price_currency }}
{% else %}
{{ line.unit_price_excl_tax|currency:line.price_currency }}
{% endif %}
</div>
</div> <!-- /.Price Holder -->
</div><!-- /.cart-item -->
{% endwith %}
{% endfor %}</form>
What I expect is that django should have multiple <div class="row no-margin cart-item"> items in the form tag but that isn't happening.
How do I fix this?
Looks like you are missing closing form tag </form> at the end.
EDIT: as others mentioned in comments it could be because you have forms inside form. This will result in unpredictable behavior.