An issue making addition through models.py making a simple calculation - python

Hello guys im practicing on django by now developping a simple expense tracker for a main project expample: Buying a flippable car for X amount and adding all the other expenses to get a single total.
my operation is mainly done in my model.py
models.py
from django.db import models
# Create your models here.
class Project(models.Model):
title = models.CharField(max_length=100)
amount = models.FloatField()
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.title
class Expenses(models.Model):
project = models.ForeignKey(Project, related_name='expenses', on_delete=models.CASCADE)
title = models.CharField(max_length=100)
amount = models.FloatField()
def __str__(self):
return self.title
def get_total_project_amount(self):
return self.amount + self.project.amount
What i wanna do is adding the main project and all the expenses togheter, but im not using the proper way, when i render the resuld it renders like this:
main project: 50$
expenses added from a model form : 2(new)
expense: 13(new)
expense: 25(new)
the total is: 52
total: 63
total: 75
I wanna render the main project and all the expenses to get a single result, something like 50+2+13+25
total : 90$ total amount soent to fix the car.
Anyone that understand addition lojic help please and thank you
.

You can sum upt the expenses with:
class Project(models.Model):
# …
#property
def total_amount(self):
subtotal = self.expenses.aggregate(
subtotal=Sum('amount')
)['subtotal'] or 0
return self.amount + subtotal
You can thus determine the total cost for a Project object myproject with:
myproject.total_amount
this will thus sum up the amount plus the sum of all the related Expenses.
Note: normally a Django model is given a singular name, so Expense instead of Expenses.
Note: When you make calculations with money, it is better to use a DecimalField [Django-doc],
not a FloatField [Django-doc]. Floats can generate rounding errors when you perform calculations.
You can also use django-money [GitHub] to specify a MoneyField. This has also specifies a currency, and can convert money to a different
currency.

Related

Django 4.0. Updating field once every day

I have a Book model that has a integer field count which is the number of users that have this book in their readlist. Users can add a book to their ReadList model (many to many field). I want to update the count in the book model once a day...how should I go about doing this?
Will be using this to displaying trending books and book rank based on user count.
Book Model:
class Book(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.TextField()
user_count = models.IntegerField()
pages = models.IntegerField()
genres = models.ManyToManyField(Genre)
def __str__(self):
return self.name
ReadList Model:
class ReadList(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
readlist = models.ManyToManyField(Book, related_name='readlist', blank=True)
def __str__(self):
return self.user.username
Django unfortunately doesn't do scheduling very well. You can actually generate this information already, via the related_name, with the advantage this will be realtime!
Let's start with a queryset for all books. Imagine you put this in one of your views.
books = Book.objects.all()
Now you have all your books, but no data on booklist numbers. So we can annotate that information via the query
from django.db.models import Count
books = Book.objects.all().annotate(user_count = Count('readlist')
Useful, but in no particular order, lets arrange it from highest to lowest.
books = Book.objects.all().annotate(user_count = Count('readlist') .order_by('-user_count')
But do we want it for every book in the store? Let's limit to the top 10.
books = Book.objects.all().annotate(user_count = Count('readlist') .order_by('-user_count')[:10]
The books don't necessarily know their own place in the heirarchy, though. Lets cycle through them and give them another impromptu field (Querysets aren't really indexed, so we can do this ourselves)
for index, book in enumerate(books):
book.placing = index
Pass context['books'] = books to your template and you should be able to do the following:
{% for book in books %}
Title:{{book.title}} <br>
Position:{{book.placing}} <br>
In :{{book.user_lists}} reading lists<br>
And there you have it, an up to the minute list of the top 10 books sorted by user_count without having to use external scheduling. Make sure you add the palcing last, as any further DB queries on the queryset will cause the query to be remade.

Django: how to sum up numbers in django

i want to calculate the total sales and display the total price, i dont know how to write the function to do this. I have tried writing a little function to do it in models.py but it working as expected. This is what i want, i have a model named UserCourse which stored all the purchased courses, now i want to calculate and sum up all the price of a single course that was sold.
models.py
class Course(models.Model):
course_title = models.CharField(max_length=10000)
slug = models.SlugField(unique=True)
price = models.IntegerField(default=0)
class UserCourse(models.Model):
user = models.ForeignKey(User , null = False , on_delete=models.CASCADE)
course = models.ForeignKey(Course , null = False , on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
and also how do i filter this models in views.py so i can display the total price of courses a particular creator have sold.
Try this approach using aggregate where you filter all UserCourse objects from a particular course, then run an aggregate on the price for that course:
my_course = Course.objects.first()
total_amount_sold = UserCourse.objects.filter(
course=my_course,
).aggregate(total_amount_sold=Sum("course__price"))["total_amount_sold"]
You can use the aggregate functionality in your view:
from django.db.models import Sum
price_total = UserCourse.objects.filter(
course__title="a title"
).aggregate(
aggregate_price = Sum("course__price")
)["aggregate_price"]
To break it down:
First we get filter all the UserCourse objects where the course has a title of "a title"
Then we aggregate them, finding the sum of the course prices for all those courses picked up by the filter
By naming a variable in our Sum expression, the queryset will now have a named value that we can get by the name ['aggregate_price'] and assign to price_total
Now you can pass price_total via context to use in your template.
You can specify other filters to get price totals for different querysets. So if your creator is the user field in your UserCourse model, you can repeat the process with user__username = "my_username" as the filter

How to reduce quantity of an item in main table when it is being used in another table - django

I am creating my model in Django and I have a many to many relationship between supplies and van kits. The idea is that an "item" can belong to many "van kits" and a "van kit" can have many " items. I created an intermediary model that will hold the relationship, but I am struggling to figure out a way to relate the quantity in the van kit table to the quantity in the main supplies table. For example, if I wanted to mark an item in the van kit as damaged and reduce the quantity of that supply in the van kit, I would also want to reduce the total count of that supply in the main "supplies" table until it has been replenished. I am thinking that maybe I'll have to create a function in my views file to carry out that logic, but I wanted to know if it could be implemented in my model design instead to minimize chances of error. Here's my code:
class supplies(models.Model):
class Meta:
verbose_name_plural = "supplies"
# limit the user to selecting a pre-set category
choices = (
('CREW-GEAR','CREW-GEAR'),
('CONSUMABLE','CONSUMABLE'),
('BACK-COUNTRY','BACK-COUNTRY')
)
supplyName = models.CharField(max_length=30, blank=False) # if they go over the max length, we'll get a 500 error
category = models.CharField(max_length=20, choices = choices, blank=False)
quantity = models.PositiveSmallIntegerField(blank=False) # set up default
price = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True) # inputting price is optional
def __str__(self):
return self.supplyName
class van_kit(models.Model):
supply_name = models.ManyToManyField(supplies, through='KitSupplies',through_fields=('vanKit','supplyName'), related_name="supplies")
van_kit_name = models.CharField(max_length=100)
vanName = models.ForeignKey(vans, on_delete=models.CASCADE)
def __str__(self):
return self.van_kit_name
class KitSupplies(models.Model):
supplyName = models.ForeignKey(supplies, on_delete=models.CASCADE)
vanKit = models.ForeignKey(van_kit, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField(blank=False)
def __str__(self):
return str(self.supplyName)
class Meta:
verbose_name_plural = 'Kit Supplies'
I am fairly new to django, I have to learn it for a class project so if my logic is flawed or if a better way to do it is obvious, please respectfully let me know. I'm open to new ways of doing it. Also, I've read through the documentation on using "through" and "through_fields" to work with the junction table, but I'm worried I may not be using it correctly. Thanks in advance.
One option would be to drop/remove the field quantity from your supplies model and just use a query to get the total quantity.
This would be a bit more expensive, as the query would need to be run each time you want to know the number, but on the other hand it simplifies your design as you don't need any update logic for the field supplies.quantity.
The query could look as simple as this:
>>> from django.db.models import Sum
>>> supplies_instance.kitsupplies_set.aggregate(Sum('quantity'))
{'quantity__sum': 1234}
You could even make it a property on the model for easy access:
class supplies(models.Model):
...
#property
def quantity(self):
data = self.kitsupplies_set.aggregate(Sum('quantity'))
return data['quantity__sum']

admin django. Add the total price in admin

hello I have to add a line or for example total_price = 123312 in admin
models.py
class Exit(models.Model):
description= models.CharField(max_length=50)
data_uscita = models.DateField('data uscita')
price = models.DecimalField(decimal_places=2, null=True,blank=True)
admin.py
class ExitAdmin(admin.ModelAdmin):
list_display =['description','price','total_exit']
def total_exit(self, request):
total = Exit.objects.all().aggregate(tot=Sum('price'))['tot']
return total
but is not ok because j have a columns with the total_exit that are repeated. I want total write only just once
I'm using Python 2.7.11
If what you need it's a function that returns the total of all outcomes (exits in your case), this is how the function goes:
from django.db.models import Sum
#other code you may need
def get_total(self, request):
return Exit.objects.aggregate(total=Sum('price'))
But, as you only got one price by outcome it doesn't make any sense to make a aggregate function because you should need multiple prices by outcome and a cost model perse.

hidden form to save aggregated values to model

I am creating a small django invoicing system for my first python project and I am stuck on this rather large issue handling data. I have a hierarchy of models that I use to easily input the data from paper. I have "services", which are migrated to "invoice", which are then migrated to "Bill Period" that the user will view all of their services provided for that month. The code will explain it better. What I need is a final model with an "Agency To Bill" and "Total" fields with a "Paid" booleanfield so I can keep track of payments and use these value with django-authorizenet. Using models is still new for me, so I'm stumped on how to do this. I am thinking that when the user views the invoice-detail page, a hidden form will be submitted with the cost values added together.
# models.py tiers
# compiled invoice with sum of all "cost" in
# bill period would be the last step
class Service(models.Model):
name_of_service = models.CharField(max_length="50")
cost = models.CharField(max_length="50")
def __unicode__(self):
return unicode(self.name_of_service)
class Bill_Period(models.Model):
start_date = models.DateTimeField(blank=True, null=True)
end_date = models.DateTimeField(blank=True, null=True)
def __unicode__(self):
return unicode(self.start_date)
class invoice(models.Model):
date_of_service = models.DateTimeField(default=timezone.now(),blank=True)
agency_to_bill = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True)
patient = models.ForeignKey('users.Patient', blank=True)
therapy_completed = models.ForeignKey('Service', blank=True)
def __unicode__(self):
return unicode(self.agency_to_bill)
class compiled_invoice(models.Model):
# month, total, paid
# views.py i use to handle the information
# error message "Relation fields do not support nested lookups"
def InvoiceDetail(request, month, year):
current_user = request.user
invoice_detail = invoice.objects.filter(date_of_service__year=year,
date_of_service__month=month,
agency_to_bill=current_user)
c = invoice.objects.filter(paid=False,
date_of_service__year=year,
date_of_service__month=month,
agency_to_bill=current_user)
total = invoice.objects.filter(therapy_completed__Service__cost__isnull=True).aggregate(Sum('cost'))
return render_to_response('invoice-detail.html', {'invoice_detail': invoice_detail,
'current_user': current_user,
'month': month,
})
Any help/advice would be appreciated, because at this point I'm stuck. This hidden form is my last ditch effort.

Categories

Resources