i need to display previous balance of users , i have used pre save signal to assign to the old balance before the transaction happens
class Payment(models.Model):
admin = models.ForeignKey(User,on_delete=models.CASCADE)
client_seller = models.ForeignKey(ClientSeller,on_delete=models.CASCADE,blank=True)
type_of_payment = models.CharField(choices=type_of_payment,max_length=60,default=retrieve)
price = models.DecimalField(max_digits=20,decimal_places=2)
previous_balance = models.DecimalField(max_digits=20,decimal_places=3,blank=True,default=0)
class ClientSeller(models.Model):
admin = models.ForeignKey(User,on_delete=models.CASCADE)
name = models.CharField(max_length=40,unique=True)
balance = models.DecimalField(decimal_places=3,max_digits=30,default=0)
i need to assign previous_balance in Payment to balance in ClientSeller , balance in ClientSeller i change every time , but i need to show the users what was previous balance when a transaction happens
def pre_save_balance(sender,instance,*args,**kwargs):
if not instance.pk:
Payment.objects.update(
previous_balance = Subquery(
Payment.objects.filter(client_seller__name=instance.client_seller.name).annotate(
pre_balance=F('client_seller__balance')
).values('pre_balance')[:1]
)
)
pre_save.connect(pre_save_balance,sender=Payment)
but it only show the default previous_balance value which is 0 !?
is there something i have missed ? or not understanding in pre_save signal good ?!
thank you for helping
Every time you're getting the first payment you made and maybe then the seller had 0 balance. You need to order your queryset and use the latest() method in order to gey the latest payment.
So you need to add something like .latest('payment_date') in your Subquery and lose the [:1] at the end.
Related
There is a race condition situation, when I want to create a new instance of model Order.
There is a daily_id field that everyday for any category starts from one. It means every category has its own daily id.
class Order(models.Model):
daily_id = models.SmallIntegerField(default=0)
category = models.ForeignKey(Categoty, on_delete=models.PROTECT, related_name="orders")
declare_time = models.DateField()
...
}
daily_id field of new record is being calculated using this method:
def get_daily_id(category, declare_time):
try:
last_order = Order.objects.filter(declare_time=declare_time,
category=category).latest('daily_id')
return last_order.daily_id + 1
except Order.DoesNotExist:
# If no order has been registered in declare_time date.
return 1
The problem is that when two different users are registering orders in the same category at the same time, it is highly likely that the orders have the repetitive daily_id values.
I have tried #transaction.atomic decorator for post method of DRF APIView and it didn't work!
You must use an auto increment and add a view that computes your semantic order like :
SELECT *, ROW_NUMBER() OVER(PARTITION BY MyDayDate ORDER BY id_autoinc) AS daily_id
I want to create a pre_save signal which will update the already created model instance whenever the sender is updated. I want to do it in pre_save signal.
The previous instance of the model will be either deleted and new instance will be created or the previous instance will be updated.
My models:
class Sales(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,null=True,blank=True)
company = models.ForeignKey(Company,on_delete=models.CASCADE,null=True,blank=True)
party_ac = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='partyledgersales')
sales = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='saleledger')
date = models.DateField(default=datetime.date.today,blank=False, null=True)
sub_total = models.DecimalField(max_digits=10,decimal_places=2,blank=True, null=True)
class Journal(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,null=True,blank=True)
company = models.ForeignKey(Company,on_delete=models.CASCADE,null=True,blank=True,related_name='Companyname')
voucher_id = models.PositiveIntegerField(blank=True,null=True)
date = models.DateField(default=datetime.date.today)
by = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='Debitledgers')
to = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='Creditledgers')
debit = models.DecimalField(max_digits=10,decimal_places=2,null=True)
credit = models.DecimalField(max_digits=10,decimal_places=2,null=True)
My pre_save signal for creation:
#receiver(pre_save, sender=Sales)
def user_created_sales(sender,instance,*args,**kwargs):
if instance.sub_total != None:
Journal.objects.update_or_create(user=instance.user,company=instance.company,date=instance.date,voucher_id=instance.id,by=instance.party_ac,to=instance.sales,debit=instance.sub_total,credit=instance.sub_total)
I want to create a signal which will update the Journal instance whenever the sender model or Sales model is update or delete the previous instance or create a new one.
Any idea how to perform this?
Thank you
update_or_create takes two sets of parameters:
kwargs which are the parameters that uniquely identify the row to fetch from the database
defaults which are the parameters that should be updated
Right now, you're never updating existing instances of Journal because you haven't specified defaults. You're looking for instances that match all the parameters, if one exists, you don't do anything, if it doesn't exist you create it.
You haven't told us what makes a Journal entry unique (and how it relates to a Sales entry, since there is no ForeignKey relationship between them).
update: with voucher_id, you now have way of looking up the corresponding Journal entries.
But something like:
Journal.objects.update_or_create(
user=instance.user,
company=instance.company,
voucher_id=instance.id,
defaults={
'date': instance.date,
'debit': instance.sub_total,
'credit': instance.sub_total,
'by': instance.party_ac,
'to': instance.sales}
)
would look for existing instance with the same user, company, and voucher_id and update the date, by, to, credit and debit.
Not sure that it's (a) doable and (b) if I formulate the task correctly. Perhaps the right way is refactoring the db design, but I would appreciate any opinion on that.
I have a model in django app, where I track the times a user enters and exits a certain page (via either form submission or just closing the broswer window). I do tracking using django channels, but it does not matter in this case.
The model looks like:
class TimeStamp(models.Model):
class Meta:
get_latest_by = 'enter_time'
page_name = models.CharField(max_length=1000)
participant = models.ForeignKey(to=Participant, related_name='timestamps')
timestamp = models.DateTimeField()
enter_exit_type = models.CharField(max_length=1000, choices=ENTEREXITTYPES,)
What I need to do is to calculate how much time a user spends on this page. So I need to loop through all records of Timestamp for the specific user, and calculate time difference between records of 'enter' and 'exit' types records.
So the db data may look like:
id timestamp enter_exit_type
1 20:12:12 enter
2 20:12:13 exit
3 20:18:12 enter
4 20:21:12 exit
5 20:41:12 enter
so what is the right way to produce a resulting queryset that look like:
id time_spent_sec
1 0:01
2 3:00
The last 'enter' record is ignored because there is no corresponding 'exit' record.
The record 1 in resulting queryset is difference between timestamps in ids 2 and 1. The record 2 in resulting queryset is difference between timestamps in ids 4 and 3.
I can just loop through the records, looking for the nearest 'exit' record and calculate it but I was thinking if there is a simpler solution?
It's possible:
1) Use the approach here to group by user if you want to get answer for all users in one query.
2) filter out the last unclosed entry with enter_exit_type == 'enter'.
3) .annotate(timestamp_with_sign=Case(When(enter_exit_type='exit', then=F('timestamp') * -1), default=F('timestamp'), )
4) Sum() by the timestamp_with_sign field.
I'm not sure, that F('timestamp') would work, you may need to search for the way to convert it to unix time.
This model structure may not be sufficient for your requirement. So I would suggest to change your model as,
class TimeStamp(models.Model):
class Meta:
get_latest_by = 'enter_time'
page_name = models.CharField(max_length=1000)
participant = models.ForeignKey(Musician, related_name='timestamps')
enter = models.DateTimeField()
exit = models.DateTimeField(null=True, blank=True)
Then you will get the data as,
from django.db.models import F, Sum, ExpressionWrapper, DurationField
TimeStamp.objects.values(
'participant').annotate(
sum_time_diff=Sum(
ExpressionWrapper(F('exit') - F('enter'), output_field=DurationField())
)
)
The response be like,
<QuerySet [{'participant': 1, 'sum_time_diff': datetime.timedelta(0, 7)}, {'participant': 2, 'sum_time_diff': datetime.timedelta(0, 2)}]>
I have 2 date fields and I want to update the date automatically.
The code won't work until I update the updated field by myself.
How can I make it update itself (updated fields) automatically?
STATUS_CHOICES = (
('P', 'Paid'),
('U', 'UNPAID'),
)
status = models.CharField(
max_length=1, choices=STATUS_CHOICES)
updated = models.DateTimeField(default=datetime.now() )
expiry = models.DateTimeField(default=datetime.now() + timedelta(days=30) )
def save(self):
if(self.expiry >= self.updated):
self.status = default = "P"
else:
self.status = default = "U"
self.expiry = default=self.updated+timedelta(days=1)
super(Users, self).save()
The DateTimeField have a auto_now property, that will set the field to the current date every time the object is saved.
The main question is what event should trigger the save action. For example you can improve your view, so that every time someone visit the page, your model would update as well as desired DateTimeField. On the other hand you may want this happen on the schedule basis, so you should use something like Cron, Celery or Huey.
In your case you have two options.
Make some code that will be executed periodically that will update the status based on current date.
Do not store status in the database at all. If it can depend only from expiry field it can be a computed property
P.S.
It's not related to what you are asking but I have a suggestion for you. Never ever use the direct result from datetime.now() as default value for DateTimeField. It's misleading for you and it's not the same as what you want to achieve. datetime.now will be executed at import time (when the server starts) and will stay the same until next restart.
If you want the default value to be the exact time when the record was created then default value need to be a function (which will be executed every time) and not the result of the function.
This means that updated need to be DateTimeFiled(default=datetime.now) (without the brackets).
This logic is more like for a field called created_at or date_created and not updated but this is your logic.
I'm working on a Ticket/Issue-tracker in django where I need to log the status of each ticket. This is a simplification of my models.
class Ticket(models.Model):
assigned_to = ForeignKey(User)
comment = models.TextField(_('comment'), blank=True)
created = models.DateTimeField(_("created at"), auto_now_add=True)
class TicketStatus(models.Model):
STATUS_CHOICES = (
(10, _('Open'),),
(20, _('Other'),),
(30, _('Closed'),),
)
ticket = models.ForeignKey(Ticket, verbose_name=_('ticket'))
user = models.ForeignKey(User, verbose_name=_('user'))
status = models.IntegerField(_('status'), choices=STATUS_CHOICES)
date = models.DateTimeField(_("created at"), auto_now_add=True)
Now, getting the status of a ticket is easy sorting by date and retrieving the first column like this.
ticket = Ticket.objects.get(pk=1)
ticket.ticketstatus_set.order_by('-date')[0].get_status_display()
But then I also want to be able to filter on status in the Admin, and those have to get the status trough a Ticket-queryset, which makes it suddenly more complex. How would I get a queryset with all Tickets with a certain status?
I guess you are trying to avoid a cycle (asking for each ticket status) to filter manually the queryset. As far as I know you cannot avoid that cycle. Here are ideas:
# select_related avoids a lot of hits in the database when enter the cycle
t_status = TicketStatus.objects.select_related('Ticket').filter(status = ID_STATUS)
# this is an array with the result
ticket_array = [ts.ticket for ts in tickets_status]
Or, since you mention you were looking for a QuerySet, this might be what you are looking for
# select_related avoids a lot of hits in the database when enter the cycle
t_status = TicketStatus.objects.select_related('Ticket').filter(status = ID_STATUS)
# this is a QuerySet with the result
tickets = Tickets.objects.filter(pk__in = [ts.ticket.pk for ts in t_status])
However, the problem might be in the way you are modeling the data. What you called TickedStatus is more like TicketStatusLog because you want to keep track of the user and date who change the status.
Therefore, the reasonable approach is to add a field 'current_status' to the Ticket model that is updated each time a new TicketStatus is created. In this way (1) you don't have to order a table each time you ask for a ticket and (2) you would simply do something like Ticket.objects.filter(current_status = ID_STATUS) for what I think you are asking.