django forloop counter as a variable - python

So I am trying to make an e-commerce pizza site where when a user adds an item to the basket it is stored as a cookie in the form
cart=[{"id":"2","quantity":"1"},{"id":"3","quantity":"5"},{"id":"5","quantity":"3"},{"id":"5","quantity":"3"}]
And my views.py is...
def cart(request):
cart = request.COOKIES.get('cart')
cart = json.loads(cart)
items =[]
basket=[]
for i in cart:
pizza = Product.objects.filter(pk=i['id']).first()
basket.append(int(i['quantity']))
items.append(pizza)
cart = len(cart)
context = {
"cart":cart,
"pizzas":items,
"basket":basket
}
return render (request, "store/cart.html", context)
And my models.py is ...
class Product(models.Model):
name = models.CharField(max_length=70)
price = models.IntegerField()
description = models.CharField(max_length=300)
image = models.ImageField(upload_to="pizza_images")
def save(self, *args, **kwargs):
super().save()
img = Image.open(self.image.path)
img.save(self.image.path)
def __str__(self):
return f"{self.name}"
In which my template code...
<table>
<thead>
<tr>
<th scope="col" class="small_col">Item</th>
<th id="product_col" scope="col">Product</th>
<th scope="col" class="small_col">Quantity</th>
<th scope="col" class="small_col">Price</th>
</tr>
</thead>
<tbody>
{% for pizza in pizzas %}
<tr>
<td class="center">{{forloop.counter}}</td>
<td>{{pizza.name}}</td>
<td class="quantity_row justify-content-center">
<input class="quantity_input" type="text" value="{{basket.forloop.counter0}}" id="pizza{{forloop.counter}}">
<div class="form_buttons">
<img onclick="add(this.getAttribute('data-attribute'))" data-attribute="pizza{{forloop.counter}}" src="https://s.svgbox.net/hero-outline.svg?ic=plus-sm&fill=000" >
<img onclick="minus(this.getAttribute('data-attribute'))" data-attribute="pizza{{forloop.counter}}" src="https://s.svgbox.net/hero-outline.svg?ic=minus-sm&fill=000">
</div>
</td>
<td class="center">
<h6>$25</h6>
</td>
<td class="small_col">
<a><img class="mb-1" src="https://s.svgbox.net/hero-outline.svg?ic=trash&fill=d90429" width="20" height="20"></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
And in the input field I want the quantity of the product to be displayed. The line which says...
<input class="quantity_input" type="text" value="{{basket.forloop.counter0}}" id="pizza{{forloop.counter}}">and for somereason the forloop.counter doesn't get the the value of the list and makes it null.
Any ideas on how i could make it work?
Thanks!

{{ basket.forloop.counter0 }} will not work, since this simply will look if basket has a forloop attribute or item, but that is not the case, since both basket.forloop and basket['forloop'] will raise an error.
It is also not a good idea, what you do here is writing business logic in the template. A template should only contain rendering logic: logic that explains how to render data in a pleaseant way, not what data to render.
You can make use of zip(…) [python-doc] to generate 2-tuples of items, and then enumerate over these 2-tuples in the template:
def cart(request):
cart = request.COOKIES.get('cart')
cart = json.loads(cart)
items = []
basket = []
for i in cart:
pizza = Product.objects.filter(pk=i['id']).first()
basket.append(int(i['quantity']))
items.append(pizza)
cart = len(cart)
context = {
"cart":cart,
'pizzabaskets': zip(items, basket),
}
return render (request, 'store/cart.html', context)
and then render this with:
{% for pizza, basket in pizzabaskets %}
<tr>
<td class="center">{{forloop.counter}}</td>
<td>{{pizza.name}}</td>
<td class="quantity_row justify-content-center">
<input class="quantity_input" type="text" value="{{basket}}" id="pizza{{forloop.counter}}">
<div class="form_buttons">
<img onclick="add(this.getAttribute('data-attribute'))" data-attribute="pizza{{forloop.counter}}" src="https://s.svgbox.net/hero-outline.svg?ic=plus-sm&fill=000" >
<img onclick="minus(this.getAttribute('data-attribute'))" data-attribute="pizza{{forloop.counter}}" src="https://s.svgbox.net/hero-outline.svg?ic=minus-sm&fill=000">
</div>
</td>
…
{% endfor %}
the basket it is stored as a cookie.
I would advise not to work with cookies. Cookies can easily be manipulated by the user through request forgery. This thus means that a user can alter the cookies and for example make an order with [{"id":"2","quantity":"-10"},{"id":"3","quantity":"5"},{"id":"5","quantity":"3"}]
so a person can order a negative amount of pizzas to reduce the price. The user has the freedom to submit a different structure and try to look for vulnerabilities. If you want to have data that is attached to the session, it is better to make use of session variables [Django-doc], since these are stored at the server side.

Related

Django - paginator table i need to show the most recent activity first

i have a table showing data from the database but i need it to show the most recent first
Table
if u see the picture there is in "monto" a 0.03 thats shown like the last one but it is the most recent in the database, i need the table to show the most recent activity first
Views.py
def index(request):
monto = Transacciones.objects.filter(owner = request.user)
paginator = Paginator(monto , 7)
page_number = request.GET.get('pagina')
page_obj= Paginator.get_page(paginator,page_number)
context = {
'page_obj': page_obj ,
}
return render(request, 'Admin/Index.cshtml',context)
table html
<div class="">
<div class="">
<table class="table h1color bgcolorwhite">
<thead>
<tr>
<th>FECHA</th>
<th>MONTO</th>
<th>TIPO</th>
<th>MONTO COMPRADO BTC</th>
<th>MONTO RETIRADO CLP</th>
<th>ESTADO</th>
</tr>
</thead>
<tbody>
{% for a in page_obj %}
<tr>
<td style="">{{a.date}}</td>
<td style="font-weight:bold;">{{a.amount}}</td>
<td style="text-align:left">{{a.tipo_transaccion}}</td>
<td style="font-weight:bold;">{{a.monto_comprado_btc}}</td>
<td style="font-weight:bold;">{{a.monto_retirado_clp}}</td>
<td style="">{{a.status}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
srry if my english was bad... Thanks a lot!!
If views.py file fetch the data like the following to get the activities in order "recent to last":
monto = Transacciones.objects.filter(owner = request.user)[::-1]

Django cumulative value displayed in template

I’m new to Django and Python and have been plugging through Python Crash Course. I have finished that and now have been making my own Django project, adding some extra bits in.
Currently, I have a table of entries from my model which I am displaying with a template, each entry in the table has a time and some other data. What I would like is the value for the cumulative time in a column, next to each entries time ie
Lesson
Lesson time
cumulative time
Lesson1
0.5
0.5
Lesson2
1
1.5
Lesson3
1.3
2.8
I’m just really stuck on how to get this done, I have looked at lot’s of stack overflow and tried various ways that I just can’t get to work correctly. Looking at other examples they use annotate() and cumsum, but I’ve not been able to get that to work. I’ve done count and sum of other values but this has got me stuck. I think I need to loop over it in my view, but not sure how to associate each value to a cumulative time.
Any help would be greatly received.
Also, sorry this isn't very well written or succinct, programming doesn't come naturally to me.
My topics.py
def topics(request):
"""Show all the topics"""
# Get the public topics
public_topics = Lessontopic.objects.filter(public=True).order_by('date_added')
# Get the private topics
if request.user.is_authenticated:
private_topics = Lessontopic.objects.filter(owner=request.user).order_by('date_added')
topics = private_topics
"""By Adding private into topics, seeing all public topics not just users
this way any topic added by authenticated user comes up in private, even if
it is also visible in public"""
time = Lessontopic.objects.aggregate(Sum('lesson_time'))
total_time = time.get('lesson_time__sum')
total_time = float(total_time)
lessons = Lessontopic.objects.all().count()
print(f"There has been {lessons} lessons ")
solo = (Lessontopic.objects.filter(solo_lesson=True)
.aggregate(Sum('lesson_time')))
solo_time = solo.get('lesson_time__sum')
print(f"solo lesson flying time {solo_time} hours")
solo_num = Lessontopic.objects.filter(solo_lesson=True).all().count()
dual = (Lessontopic.objects.filter(solo_lesson=False)
.aggregate(Sum('lesson_time')))
dual_time = dual.get('lesson_time__sum')
remaining_time = 50 - total_time
#Make a pie chart.
labels = ['Solo', 'Dual']
values = [solo_time, dual_time]
chat = ['this is long']
# Visualise the results
data=[Pie(labels=labels,text=chat,values=values,pull=[0.1, 0],
textposition='outside')
]
x_axis_config = {'title': 'Hours'}
y_axis_config = {'title': 'Lesson type'}
my_layout = Layout(title='Flying time Solo vs Dual Instruction',title_font_color='black' ,
title_font_size=30, title_x=0.5, legend_bordercolor='green', legend_borderwidth=5 )
fig = ({'data': data, 'layout': my_layout})
div = offline.plot(fig, auto_open=False, output_type='div')
cumulative_time = Lessontopic.objects.annotate(
cumulative_times=Window(
expression = Sum('lesson_time'),
order_by=F('date_added').asc(),
frame=RowRange(start=None, end=0)
)
)
context = {'topics': topics, 'cumulative_time':cumulative_time,'lessons':lessons, 'solo_time':solo_time,
'solo_num':solo_num, 'dual_time':dual_time,'solo_num':solo_num,
'remaining_time':remaining_time, 'dual':dual,'graph':div,}
else:
topics = public_topics
context = {'topics': topics}
return render(request, 'flying_logs/topics.html', context)
my model.py
from django.db import models
from django.contrib.auth.models import User
from django.forms.widgets import DateInput
from django import forms
import json
import requests
# Create your models here.
class Lessontopic(models.Model):
"""The topic of each lesson or day flying"""
text= models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False, verbose_name="Make post public?",
help_text="click on this form if you want it to be viewed by anyone")
lesson_number = models.PositiveIntegerField(blank=True, null=True)
lesson_time = models.DecimalField('enter flight time', max_digits=2, decimal_places=1)
solo_lesson = models.BooleanField(default=False, verbose_name="Were you solo for the lesson",
help_text="Click if were flying solo for the lesson")
runway_direction = models.PositiveIntegerField(
verbose_name="Select runway direction: 07 or 25")
number_landings = models.PositiveIntegerField(blank=True, default=1,
help_text="Enter how many landings")
date = models.DateTimeField()
time_of_lesson = models.PositiveIntegerField(
verbose_name="time that the lesson started")
weather_data = models.CharField(max_length=200)
adding = models.TextField(default=None, null=True, blank=True)
def __str__(self):
"""Return a string representation of the modeel"""
return self.text
My template topics.html
{% extends "flying_logs/base.html" %}
<h1>Topics</h1>
{% block page_header %}
{% endblock page_header %}
{% block content %}
<div class="container">
<table class="table text-center table-hover table-bordered" >
<tr><tr class="table-primary">
<th style="width: 10%">Lesson No.</th>
<th scope="col">Date</th>
<th scope="col">Lesson</th>
<th scope="col">Dual/Solo
<th scope="col">Flying time</th>
<th scope="col">Cumulative</th>
</tr>
</thead>
{% for topic in topics %}
{% if topic.solo_lesson %}
<tr class="table-success">
{% endif %}
<td class="text-center"> {{topic.lesson_number}}</td>
<td>{{ topic.date|date:'d/m/Y'}}</td>
<td>{{ topic }}</td>
<td>{{ topic.solo_lesson|yesno:"Solo, Dual" }}</td>
<td class="text-center">{{topic.lesson_time}}</td>
<td>Time so far{{ cumulative_time}}</td>
</tr>
{% endfor %}</table>
</div>
<div class="container">
<table class="table text-center table-hover table-bordered" >
<thread>
<tr><tr class="table-primary">
<th style="width: 5%">Solo</th>
<th style="width: 20%">Dual</th>
<th style="width: 20%">total time</th>
<th style="width: 20%">Time remaing</th>
<th style="width: 20%"> Solo Lessons</th>
<th style="width: 35%">Number of lessons</th>
</tr>
</thead>
<td>{{solo_time|floatformat:1}}</td>
<td>{{dual_time|floatformat:1}}</td>
<td>{{total_time}}</td>
{% if remaining_time >= 0 %}
<td class="table-danger">{{ remaining_time|floatformat:1 }}</td>
{% elif remaining_time <= 0 %}
<td class="table-success">You've done the minimum hours!!</td>
{% endif %}
<td class="text-center"> {{ solo_num}} </td>
<td>{{lessons}}</td>
</tr>
</tr>
</table>
</div>
<h3><a href="{% url 'flying_logs:new_topic' %}"><button name="new entry"
class="btn btn-primary">Add a new topic</button></a></h3>
{% if graph %}
<div style="width:600;height:500">
{{ graph|safe }}
</div>
{% endif %}
{% endblock content %}

how to add a style in django

I want change the row color in a table whit class, how to put html classes if something happens. And I use bootstrap.
models.py
class Car(models.Model):
name = models.CharField(max_length=20)
color = models.CharField(max_length=20)
views.py
from .models import Car
def index(request):
cars = Car.objects.all()
context = {
'cars' = cars
}
return (request, 'index.html', context)
index.html
<div class="table-responsive-md">
<table class="table tableh-hover">
<thead>
<tr>
<td>Name</td>
<td>Color</td>
</tr>
</thead>
<tbody>
{% for car in cars %}
<tr>
<td>{{ car.name }}</td>
<td {if car.color == red } style="background-color: red;"{% endif %}>{{car.color}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<td {if car.color == red } style="background-color: red;"{% endif %}>{{car.color}}</td>
this line is what i want to make work
I`m improving my english, please be patiente :D
There are two mistakes here:
a template tag, like {% if … %} [Django-doc] is wrapped in curly brackets with percentages ({% … %}), you are missing the percentages (%); and
a string literal is wrapped between quotes, so 'red', instead of red.
You thus implement this with:
<td {% if car.color == 'red' %}style="background-color: red;"{% endif %}>{{car.color}}</td>

Django: Trying to click on a link and remove an assigned client

Good morning. I am having an issue trying to remove a client from an assigned bed. I created a one-item form called "RoomUpdate" that will allow a user to add a client to a bed that is empty via a dropdown through a ModelChoiceField.
When the bed is full, it does not allow the access to the drop down, instead, I have a link that states "remove client." What I want to happen is when I click that button, it assigns the default value of None to that bed in that room.
What's tricky, at least to my new-ish to Django mind, is how I do this through multiple tables. Having looked for multiple answers and tried different things, I know I've lost track of what I'm doing so I definitely could use some help.
models.py
class Room(models.Model):
room_id = models.AutoField(primary_key=True)
room_number = models.CharField(max_length=5)
shelter_id = models.ForeignKey(Shelter)
max_occupancy = models.CharField(max_length=3)
floor_location = models.CharField(max_length=3)
def __str__(self):
return self.room_number
class Bed(models.Model):
bed_id = models.AutoField(primary_key=True)
room_id = models.ForeignKey(Room, related_name='beds')
bed_size = models.ForeignKey(BedSize)
client_assigned = models.ForeignKey(Clients, null=True, blank=True, default=None)
forms.py
class RoomUpdate(forms.ModelForm):
client_assigned = forms.ModelChoiceField(queryset=Clients.objects.all(), required=False)
#def __init__(self, *args, **kwargs):
#super(RoomUpdate, self).__init__(*args, **kwargs)
#self.fields['client_assigned'].choices.insert(0, ('','---------' ) )
class Meta:
model = Room
fields = ( 'client_assigned', )
views.py
def room_update(request, pk, template_name='shelter/room_edit.html'):
rooms = get_object_or_404(Room, pk=pk)
form = RoomUpdate(request.POST or None, instance=rooms)
beds = Bed.objects.filter(room_id=pk)
if form.is_valid():
form.save()
return redirect('/shelter/')
return render(request, template_name, {'form': form, 'rooms': rooms, 'beds':beds,})
def remove_client(request, pk):
rooms = get_object_or_404(Room, pk=pk)
bed = Bed.objects.filter(room_id=pk)
form = RoomUpdate(request.POST)
template_fail = 'clients/invalid_permissions.html'
if request.method=='POST':
if form.is_valid():
bed.objects.update(client_assigned=None)
bed.save()
else:
return redirect(request, template_fail)
return render_to_response(request, {'rooms': rooms, 'bed': bed})
template
<form action="" method="POST">
{% csrf_token %}
<div class="room box-shadow">
<h4>Room {{ rooms.room_number }}</h4>
<table>
{% for i in rooms.beds.all %}
<tr>
<td>Bed ID: </td>
<td>{{i.bed_id }}</td>
</tr>
<tr>
<td>Bed Size: </td>
<td>{{i.bed_size }}</td>
</tr>
<tr>
<td valign="top">Client: </td>
<td>
{% if i.client_assigned %}
{{ i.client_assigned }}
<br \>
Remove Client
{% else %}
{{ form.client_assigned }}
{% endif %}
</td>
</tr>
<tr>
<td colspan="2">
<hr class="style-two" />
</td>
</tr>
{% endfor %}
<tr>
<td><input type="submit" value="Submit" /></td>
<td></td>
</tr>
</table>
</div>
</form>
I've been playing around with this a bit and making some sort of progress. If I change the url from the same as the edit, I get it to work in that it deletes from the table and redirects the user to a new page.
I would prefer it not redirect the user to a new page, but rather, update the page that's there.
Thoughts?
The new view looks like this:
def remove_client(request, pk, template_name='shelter/test.html'):
bed = Bed.objects.filter(bed_id=pk).update(client_assigned=None)
return render(request, template_name, { 'bed':bed })
Further diving into this, I found a solution I rather like and actually works in a way I wanted but couldn't figure out. Instead of focusing on the room, I realized that I needed to focus on the smaller container -- the bed -- and since it can move around, it would be the better choice.
Currently, this functionality allows me to move beds to different rooms, remove clients by selecting the '----' selector, and allows me to add clients.
So here is the answer I came up with:
forms.py
class RoomUpdate(forms.ModelForm):
bed_id = forms.CharField()
room_id = forms.ModelChoiceField(queryset=Room.objects.all())
bed_size = forms.ModelChoiceField(queryset=BedSize.objects.all(), required=False)
client_assigned = forms.ModelChoiceField(queryset=Clients.objects.all(), required=False)
class Meta:
model = Bed
fields = ('bed_id', 'client_assigned', 'room_id', 'bed_size' )
views.py
def room_update(request, pk, template_name='shelter/room_edit.html'):
beds = get_object_or_404(Bed,pk=pk)
form = RoomUpdate(request.POST or None, instance=beds)
if form.is_valid():
form.save()
return redirect('/shelter/')
return render(request, template_name, {'form': form, 'beds':beds,})
room_edit.html
<form action="" method="POST">{% csrf_token %}
<div class="room box-shadow">
<h4>Room </h4>
<table>
<tr>
<td>Room: </td>
<td>{{ form.room_id }}</td>
</tr>
<tr>
<td>Bed ID: </td>
<td>{{ form.bed_id }}</td>
</tr>
<tr>
<td>Bed Size: </td>
<td>{{ form.bed_size }}</td>
</tr>
<tr>
<td valign="top">Client: </td>
<td>{{ form.client_assigned }}</td>
</tr>
<tr>
<td colspan="2"><hr class="style-two" /></td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
<td></td>
</tr>
</table>
</div>
</form>

Using Flask and WTForms how can i have a table where some columns are inputs?

I'm struggling to see how this is done, and the documentation doesn't seem to help much.
I need to generate a table, the row size will be variable, but not dynamic (i know how much rows i need before generating the page).
For the sake of simplicity lets imagine a page where you grade n exams with an integer.
i tried this:
the form.
class InputInteger(Form):
grade = IntegerField('Grade')
the view
#decorator..
def grade():
form = InputInteger()
names = student_list
return render_template("grade.html", form=form, names=names)
the template
<table>
<tr>
<th>Name</th>
<th>Grade</th>
</tr>
{% for name in names %}
<tr>
<td>
{{name}}
</td>
<td>
{{form.grade}}
</td>
</tr>
</table>
But how do i read back the inputed values?
How do i distinguish who's grade that belongs too?
Am fairly confused, i've read about FieldList(FormField(IntegerField)), but isn't that just one field with a list of integers?
What about the Table Widget, do i need that?
Please help.
For anyone looking at this now, the OP was correct to think about FieldLists and FormFields. Here is a solution:
forms.py:
class GradeForm(FlaskForm):
student = IntegerField('Student ID')
grade = IntegerField('Grade')
delete = BooleanField('Delete')
class GradeFormSet(FlaskForm):
gradeset = FieldList(FormField(GradeForm), min_entries=0)
view.py:
def grade():
# create a dict of student IDs and their initial grades (or None for now)
init_merits = [dict(student=s.id, grade=None) for s in myStudentTable.query.all()]
gradeform = GradeFormSet(gradeset=init_merits)
if form.validate_on_submit():
...
# meritforms.data['gradeset'] contains a list of dictionary values for further processing
# check 'delete' == True to handle deletion of that student from your table
...
return render_template('template.html', form=gradeform)
Template:
<table>
{% for merit in form.gradeset %}
<tr>
<td>{{ merit.placing(readonly=true) }} {{ merit.csrf_token }} {{ merit.hidden_tag() }}</td>
<td>{{ merit.grade }}</td>
<td>{{ merit.delete }}</td>
</tr>
{% endfor %}
</table>
<input type="submit" name="finish" value="Save">
<input type="submit" name="cancel" value="Cancel">
You're almost right. Put your table inside a html form and catch in a function where you can retrieve your input fields.
Here is an example:
<form action="/grade">
<table>
<tr>
<th>Name</th>
<th>Grade</th>
</tr>
{% for name in names %}
<tr>
<td>{{name}}</td>
<td><input id='{{name}}' value='{{ form.grade }}'></td>
</tr>
</table>
</form>
And your Flask function:
#app.route('/grade', methods=['GET', 'POST'])
def grade():
if request.method == 'POST':
return 'Form posted.'
When you post your form to your function, you can access your input field by this way: request.form['inputfieldname'] and then you do your stuff. I hope my explanation is clear.

Categories

Resources