Issue
I’m making a Django APP (required) to calculate every month the profits and losses.
There’s a feature that I wanted to put that in N months you’ll be paying the value/N (i.e: $100/5 that equals to $20 per month).
This feature would be like a Bank APP shows how many you have yet to pay (i.e: from this month to October)
By the way, there’s only one record from the losses (I’m trying not to change this)
So far so good, but the record appear only in the month of my search (view below) and when I try to use:
Account.objects.filter(date__year__gte=y) or Account.objects.filter(date__month__gte=m)
or
Account.objects.filter(date__year__lt=y) or Account.objects.filter(date__month__lt=m)
The record shows the entire year or the months whose are greater or less than the month saved (with no filter, so if it’s from July to November, it’ll show until December or in January)
View.py
def account(request, pk):
search = f"{datetime.now().year} - {datetime.now().month:02}"
account = Account.objects.get(id=pk)
ctx = {
'search': search
}
if request.GET.get('month'):
search = request.GET.get('month')
y, m = search.split('-')
ctx.update({
'search': search
})
date_loss = filter_by_model_date(Loss, m, y)
date_profit = filter_by_model_date(Profit, m, y)
profit = filter_by_account(date_profit, account)
loss = filter_by_account(date_loss, account)
ctx.update({
'profit': profit, 'loss': loss
})
return render(request, 'account/account.html', ctx)
Functions.py
def filter_by_model_date(model, month, year):
"""
Filter by Model by month and year
"""
return model.objects.filter(date__month=month, date__year=year)
def filter_by_account(model, field):
"""
Logs Filter by account
"""
return model.filter(account=field)
Models.py
class Account(models.Model):
name = models.CharField(max_length=200)
class Profit(models.Model):
[...]
value = models.FloatField()
date = models.DateField(default=datetime.today)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
class Loss(models.Model):
[...]
months = models.IntegerField()
value = models.FloatField()
date = models.DateField(default=datetime.today)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
So there aren’t any error messages, I’m just trying to put that feature in my app, a way to make an N month Loss to appear from the month it is saved to it’s last.
I tried to make the reverse, save the Loss in the last month with timedelta
, but couldn’t do backwards, and I’m struggling not to save the same record N times
Solution
So I managed to do it using list… It’s not sophisticated (I don’t know if it’s pythonic) but I did it this way, and it’s working !
I thank every one who tried to answer my question, and I’m putting my code here for every one who wants to do an app like that !
I just want to say one thing: "Good Luck and never give up !"
View.py
def account(request, pk):
search = f"{datetime.now().year} - {datetime.now().month:02}"
account = Account.objects.get(id=pk)
ctx = {
'search': search
}
if request.GET.get('month'):
search = request.GET.get('month')
y, m = search.split('-')
ctx.update({
'search': search
})
date_loss = filter_by_model_date(Loss, m, y)
date_profit = filter_by_model_date(Profit, m, y)
profit = filter_by_account(date_profit, account)
loss = filter_by_account(date_loss, account)
ctx.update({
'profit': profit, 'loss': loss
})
list_month = check_is_month(Loss, account, y, m) # Added this line of code
data.update({
'month': list_month
})
return render(request, 'account/account.html', ctx)
Functions.py
def check_is_month(model, field, year, month):
"""
Return a list with all the losses
"""
buy_loss = filter_by_model_account(model, field)
list_loss = []
for b in buy_loss: #Run through the filter
if get_date_iso_format(year, month) >= b.date: #If the b.date is lesser or equal the search, this if not to show in earlier months (P.S: Had to transform in isoformat)
list_loss.append(b) #Append the record
final_date = check_final_date(b.date, c.months) #Get Final Date
m = (int(month) - b.date.month) #Get The number of months (Just for show)
if final_date > replace_month_year(get_date_iso_format(year, month), month, year): # If Final date is greater than the month searched (P.S: Had to transform in isoformat)
if m > 0: #Another just for show
b.months = f"{m}/{b.months}"
else:
b.months = f"{m + 12}/{b.months}"
b.date = replace_month_year(b.date, month, year) #Change the date like a Bank APP
elif final_date < replace_month_year(get_date_iso_format(year, month), month, year): #If the date is less
list_loss.remove(b)
return list_loss
def get_date_iso_format(year, month):
"""
Return String date year/month/01
"""
return datetime.fromisoformat(f"{year}-{month}-01").date()
def replace_month_year(date, month, year):
"""
Replace function
"""
return date.replace(month=int(month), year=int(year))
def check_final_date(date, months):
"""
Return final date
"""
return date + timedelta(seconds=months* 30 * 24 * 60 * 60)
def filter_by_model_account(model, field):
"""
Filter by Model and Account
"""
return model.objects.filter(account=field)
In template, you can run through Loss, Profits and Months, be my guest to do whatever it pleases you !
Answered By – Marrows
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0