Iteration of instances inside controller and pass to context - python

I have started creating a personal expenses django app to learn python...
So far, I have written some models for categories, transactions, scheduled transactions (for example re-occuring bills), type of accounts etc. And I am stuck :)
What I am trying to do is to display all transactions in an html page. Those that re-occur, should be listed also, as my app displays all transactions you have until 365 days from now. I can't manage to display all instances of repeating transactions.
model
class Transaction(models.Model):
category = models.ForeignKey(Category)
kind = models.ForeignKey(Kind)
account = models.ForeignKey(Account)
userA = models.ForeignKey(User, related_name='userA')
userA_contribution = models.DecimalField(max_digits=9, decimal_places=2)
userB = models.ForeignKey(User, related_name='userB', blank=True, null=True)
userB_contribution = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
transaction_text = models.CharField(max_length=200)
transaction_date = models.DateTimeField('transaction date')
transaction_price = models.DecimalField(max_digits=9, decimal_places=2)
def __str__(self):
return self.transaction_text
# calculate days since transaction has been made
def days_ago(self):
days_ago = timezone.now() - self.transaction_date
return days_ago.days
class ScheduledTransaction(Transaction):
REPEATING_CHOICES = (
('0', 'Once'),
('1', 'Daily'),
('2', 'Every other day',),
('7', 'Every week'),
('14', 'Every two weeks'),
('30', 'Monthly'),
('90', 'Quarterly'),
('180', 'Six months'),
('365', 'Annually'),
)
repeated = models.CharField(max_length=30, choices=REPEATING_CHOICES)
def days_to_payment(self):
days_to_payment = self.transaction_date - timezone.now()
return days_to_payment.days
def cost_per_month(self):
cost_per_month = self.userA_contribution / int(self.repeated) * 30
return cost_per_month
controller
def index(request):
latest_transactions_list = Transaction.objects.all().order_by('-transaction_date')[:20]
scheduled_transactions = ScheduledTransaction.objects.all()
# create a list to save scheduleTransaction.object instances
s_instances = []
for sche in scheduled_transactions:
s_instances.append(sche)
next_payment_days = int(sche.repeated) # next payment day is the repeated value, e.g. = 30 days
base_trans_date = sche.transaction_date
while next_payment_days < 365:
sche.transaction_date = base_trans_date + datetime.timedelta(days=next_payment_days)
s_instances.append(sche)
next_payment_days = next_payment_days + int(sche.repeated)
accounts_dash = Account.objects.all().order_by('-name')
date_today = datetime.datetime.now()
context = { 'latest_transactions_list': latest_transactions_list,
'scheduled_transactions' : s_instances,
'accounts_dash' : accounts_dash,
'date_today' : date_today,
}
return render(request, 'transactions/index.html', context)
view
{% for strans in scheduled_transactions %}
{% if strans.repeated|add:0 <= 365 %}
<tr>
<td class="">{{ strans.transaction_date }}</td>
<td class="text-center"><span class="label label-default">{{ strans.kind }}</span></td>
<td class="text-center"><span class="label label-info">{{ strans.category }}</span></td>
<td class="text-center">{{ strans.transaction_text }}</td>
<td class="text-right">{{ strans.userA_contribution|floatformat:2 }}€</td>
<td class="text-center">{{ strans.repeated }}</td>
<td class="text-center">{{ strans.days_to_payment }}</td>
<td class="text-right">{{ strans.cost_per_month|floatformat:2 }}€</td>
</tr>
{% endif %}
{% endfor %}
The transaction is printed in the terminal webserver shell, but not displayed even once on the html.
Any help would be appreciated !
EDIT: Updated the controller. Now the iteration works, but I always get the latest date and the total of days_to_payment in all instances. Any ideas ?

Firstly, it's a view, not a controller.
Secondly, what you're doing with s_instances doesn't seem to make sense. First you declare it as global for no reason - it's local to the view function, so there's no need to make it global. Then you iterate through the transactions and for each one you redefine s_instances to be the value of the latest one. You should be appending to a list, not redefining it each time. And then you append two methods: days_to_payment and cost_per_month - without ever actually calling them. And finally, having converted your instances to a list of simple values, you attempt to call them from the template by their original property names, which they no longer have.
However, I must question why you think you need to do that at all. All the things you put into that list are simple model attributes or methods. Why not simply pass the transaction objects straight to the template? Then your template would actually work.

Just remove this useless and insane for loop from your view and you should be better:
def index(request):
latest_transactions_list = Transaction.objects.order_by('-transaction_date')[:20]
scheduled_transactions = ScheduledTransaction.objects.all()
accounts_dash = Account.objects.order_by('-name')
date_today = datetime.now()
context = {'latest_transactions_list': latest_transactions_list,
'scheduled_transactions': scheduled_transactions,
'accounts_dash': accounts_dash,
'date_today': date_today,
}
return render(request, 'transactions/index.html', context)

Related

printing values django templates using for loop

I have two models interrelated items and broken :
class Items(models.Model):
id = models.AutoField(primary_key=True)
item_name = models.CharField(max_length=50, blank=False)
item_price = models.IntegerField(blank=True)
item_quantity_received = models.IntegerField(blank=False)
item_quantity_available = models.IntegerField(blank=True)
item_purchased_date = models.DateField(auto_now_add=True, blank=False)
item_units = models.CharField(max_length=50, blank=False)
def __str__(self):
return self.item_name
class Broken(models.Model):
item = models.ForeignKey(Items, default=1, on_delete=models.CASCADE)
item_quantity_broken = models.IntegerField(blank=True)
item_broken_date = models.DateField(auto_now_add=True, blank=False)
item_is_broken = models.BooleanField(default=True)
date_repaired = models.DateField(auto_now=True, blank=True)
def __str__(self):
return self.item.item_name
I wrote this view function to retrieve data to a table into a template:
def broken_items(request):
br = Broken.objects.select_related('item').all()
print(br.values_list())
context = {
'title': 'broken',
'items': br,
}
return render(request, 'store/broken.html', context)
this is the executing query:
SELECT "store_broken"."id",
"store_broken"."item_id",
"store_broken"."item_quantity_broken",
"store_broken"."item_broken_date",
"store_broken"."item_is_broken",
"store_broken"."date_repaired",
"store_items"."id",
"store_items"."item_name",
"store_items"."item_price",
"store_items"."item_quantity_received",
"store_items"."item_quantity_available",
"store_items"."item_purchased_date",
"store_items"."item_units"
FROM "store_broken"
INNER JOIN "store_items"
ON ("store_broken"."item_id" = "store_items"."id")
looks like it gives me all the fields I want. In debugger it shows data from both tables,
so I wrote for loop in template,
{% for item in items %}
<tr>
<td>{{item.id}}</td>
<td>{{item.item_id}}</td>
<td>{{item.item_quantity_broken}}</td>
<td>{{item.item_broken_date}}</td>
<td>{{item.item_is_broken}}</td>
<td>{{item.date_repaired}}</td>
<td>{{item.item_name }}</td>
<td>{{item.item_item_quantity_received}}</td>
<td>{{item.item_quantity_available}}</td>
<td>{{item.item_purchased_date}}</td>
<td>{{item.items_item_units}}</td>
</tr>
{% endfor %}
The thing is this loop only gives me data from broken table only. I can't see data from Items table.
can someone help me to find the reason why other details are not showing?
Your items query is of Broken objects. So in order to access the Items values you need to change your table. For better understanding change your view like this:
brokens = Broken.objects.select_related('item').all()
context = {
'title': 'broken',
'brokens ': brokens,
}
and then your table:
{% for broken in brokens %}
<tr>
<td>{{broken.id}}</td>
<td>{{broken.item.pk}}</td> # This is the item id
<td>{{broken.item_quantity_broken}}</td>
<td>{{broken.item_broken_date}}</td>
<td>{{broken.item_is_broken}}</td>
<td>{{broken.date_repaired}}</td>
<td>{{broken.item.item_name}}</td>
<td>{{broken.item.item_quantity_received }}</td>
<td>{{broken.item.item_quantity_available}}</td>
<td>{{broken.item.item_purchased_date}}</td>
<td>{{broken.item.items_item_units}}</td>
</tr>
{% endfor %}
you loop over a List of Broken objects
to access the related item objects
item.item.item_name

How to save address form data and display in template using Django

Brand new to Django/Python and have almost completed my first big project. I've built a small ecommerce store with a staff backend to update/delete and create products. I would like to display the address entered in by the User at checkout with in the Staff template.
My code so far looks like this:
models.py:
class Address(models.Model):
ADDRESS_CHOICES = (
('B', 'Billing'),
('S', 'Shipping'),
)
user = models.ForeignKey(
User, blank=True, null=True, on_delete=models.CASCADE)
street_address = models.CharField(max_length=150)
town_or_city = models.CharField(max_length=100)
county = models.CharField(max_length=100, default=True)
postcode = models.CharField(max_length=20)
address_type = models.CharField(max_length=1, choices=ADDRESS_CHOICES)
default = models.BooleanField(default=False)
def __str__(self):
return f"{self.street_address}, {self.town_or_city}, {self.county}, {self.postcode}"
class Meta:
verbose_name_plural = 'Addresses'
I would like to captcha the data from the 'street_address', 'town_or_city', 'county' and 'postcode' fields and have that info displayed with in my staff template.
The idea I had was to import my Address model and grab all objects using Address.objects.all() and have this display with in the template using something like {{ user_address}}
views.py / StaffView:
class StaffView(LoginRequiredMixin, generic.ListView):
template_name = 'staff/staff.html'
queryset = Order.objects.filter(ordered=True).order_by('-ordered_date')
paginate_by = 10
context_object_name = 'orders'
def get_address(self):
user_address = Address.objects.all()
return user_address
staff.html:
<tr>
<td><a class="order-ref-number-link" href="{% url 'cart:order-detail' order.pk %}">#{{ order.reference_number }}</a>
</td>
<td>{{ order.ordered_date }}</td>
<td>{{ order.user.email }}</td>
<td>£{{ order.get_total }}</td>
<td>{% if order.ordered %}Paid{% else %}Not Paid!{% endif %}</td>
<td>{{ user_address }}</td> <--HERE IS WHERE I'M TRYING TO DISPLAY ADDRESSES
</tr>
{% empty %}
So far this method i've tried alone returns nothing, im still finding my way around Django so would really appreciate if someone could help me find a simple solution for this. If any additional info is needed I'll be happy to provide. Thanks in advance.

Possible to delete an object's specific row in django?

I have model that creates several different rows. Like this...
class Myteam(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
QB = models.CharField(max_length=80, null=True)
RB1 = models.CharField(max_length=80, null=True)
WR = models.CharField(max_length=80, null=True)
TE = models.CharField(max_length=80, null=True)
D = models.CharField(max_length=80, null=True)
K = models.CharField(max_length=80, null=True)
In my template, I'm looping through the rows and displaying them as html table rows. I've added a delete function to each row because I'd like the app's user to be able delete a player from their "Myteam" object. Problem is, I can only delete the entire object because there's only one id which is for the entire object. The template looks like this right now. Here's two rows as an example.
<tbody>
{% for t in team %}
<tr>
<td id="" > {{ t.QB }}
Delete
</td>
<tr>
<td> {{ t.RB1 }}
Delete
</td>
</tr>
<tr>
I did come across one possible solution here which suggested using {{ forloop.counter }} to assign individual id's to the row, but I can't get this to work how I would like.
Just in case, here's the views.py
def delete_player(request, id):
player = Myteam.objects.get(id=id)
player.delete()
return redirect('show')
I feel like there's probably a pretty basic solution to this but I'm new to django and am having trouble finding such answers. Any help is greatly appreciated.
Ok, so those model fields are database table columns, not rows. Instances of the model are table rows.
You don't delete columns, instead you set them to null. Your view could for example take the column name as a string argument:
def delete_player(request, id, col_name):
player = Myteam.objects.get(id=id)
setattr(player, col_name, None)
player.save()
return redirect('show')
Also since your fields are CharFields, it's best practice to not make them nullable (meaning, don't set null=True), but instead use an empty string "" to indicate an unset value. This way you don't have two different values that indicate emptyness. Thus in the view you would use setattr(player, col_name, "").

Sum Foreignkey objects to loop

I'm trying create a table with 2 columns:
1) Collections and 2) Qualified Sales.
Like the image above.
Each book count the own qualified_sales.
The Qualified sales(column in the table) must sum all qualified_sales of all books of each collection.
models.py
class Publishing_company(models.Model):
title = models.CharField(max_length=50)
class Collection(models.Model):
publishing_company = models.ForeignKey(Publishing_company, on_delete=models.CASCADE)
class Book(models.Model):
publishing_company = models.ForeignKey(Publishing_company, on_delete=models.CASCADE)
class Sale(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
qualified_sale = models.IntegerField(default=0)
views.py
def qlf_sales(request):
book = Collection.objects.filter(user=request.user)
qualified_sum = Sale.objects.filter(user=request.user, book__publishing_company__collection__in=book).aggregate(Sum('qualified_sale'))['qualified_sale__sum'] or 0
context = {'qualified_sum': qualified_sum}
return render(request, 'template.html', context)
template.html
{% for collection in collections %}
<tr>
<td>{{collection}}</td>
<td>{{qualified_sum}}%</td>
</tr>
{% endfor %}
But this code not work. Dont appear any debug error, but in the all fields in the Qualified Sales' column appear the same value: the sum of all qualified_sales of all sales of all book.
why didn't separate by collection?
If anyone can help me. Please i go a lot grateful.

Django - How to use a database table lookup

I'm trying to display some data on a webpage using a foreach loop and django.
I do not seem to understand how to use a lookup table that I have created in my Database.
These are the columns from the DB:
budget_audit_table:
-BudgetID
-BudgetTypeID <- Foreign Key
-ObjectAuditID
-CustomerID
-DateOfTransaction
-BudgetObject
-Amount
budget_type:
-BudgetTypeID
-BudgetType
As you can probably assume in the model.py, the BudgetTypeID is a foreign key.
In the budget_type table I currently have 2 rows:
- Expense: ID 1
- Income: ID 2
Now the problem I'm having is I have searched for a few days now trying to understand Django's API more and I'm struggling to understand how do I for each row that is displayed from the budget_audit_table, how do I instead of displaying the BudgetTypeID (eg 1), it displays the BudgetType (eg Expense)?
Here is my view & template
view.py
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.template import RequestContext, loader
from models import BudgetAuditTable
from models import BudgetType
#login_required
def index(request):
budgetauditlist = BudgetAuditTable.objects.order_by('-budgetid')
template = loader.get_template('budget/budget.html')
context = RequestContext(request, {
'budgetauditlist': budgetauditlist,
})
return HttpResponse(template.render(context))
Template
{% for budgetauditobject in budgetauditlist %}
<tr>
<td>{{ budgetauditobject.budgetid }}</td>
<td>{{ budgetauditobject.budgettypeid }}</td>
<td>{{ budgetauditobject.objectauditid }}{{ budgetauditobject.customerid }}</td>
<td>{{ budgetauditobject.amount }}</td>
</tr>
{% endfor %}
Now perhaps you're wondering why I don't use the "Choices" django offers. Because I'm a very database driven person who believes the DB should handle as much as possible and leaving the python as the ask and receive part.
EDIT
models.py
class BudgetAuditTable(models.Model):
budgetid = models.IntegerField(db_column='BudgetID', primary_key=True)
budgettypeid = models.ForeignKey('BudgetType', db_column='BudgetTypeID', blank=True, null=True)
objectauditid = models.IntegerField(db_column='ObjectAuditID', blank=True, null=True)
customerid = models.IntegerField(db_column='CustomerID', blank=True, null=True)
dateoftransaction = models.DateField(db_column='DateOfTransaction', blank=True, null=True)
budgetobject = models.CharField(db_column='BudgetObject', max_length=255, blank=True)
amount = models.DecimalField(db_column='Amount', max_digits=10, decimal_places=2, blank=True, null=True)
class Meta:
managed = False
db_table = 'budget_audit_table'
class BudgetType(models.Model):
budgettypeid = models.IntegerField(db_column='BudgetTypeID', primary_key=True)
budgettype = models.CharField(db_column='BudgetType', max_length=25, blank=True)
class Meta:
managed = False
db_table = 'budget_type'
You should really have shown your models. If budgettypeid is the Django ForeignKey field, then budgetauditobject.budgettypeid would give you the actual BudgetType object, and then you can access its fields with the normal dot notation.
Instead of:
<td>{{ budgetauditobject.budgettypeid }}</td>
have you tried:
<td>{{ budgetauditobject.budgettypeid.budgettype }}</td>
?

Categories