Aggregate/annotate project profit - django

I'm having a hard time aggregating project profit, so I can do more calculation with the result.
total_potential_profit = Project.objects.filter(created__year=year, created__month=month, client_sub_org__lead_contact__account_handler=user_id).aggregate(Sum('profit_aux'))
and this return None as a result, I'm not shure If I'm doing the right thing with aggregation, it seems that annotation is more appropriate in this filter, but that is also returning None as a result.
The model that I'm filtering on is
class Project(models.Model):
client_sub_org = models.ForeignKey(ClientSubOrganization)
profit_aux = models.DecimalField('profit aux', max_digits=20 decimal_places=2, default=0, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
and the user_id that I'm pulling out is from these models, client sub organization:
class ClientSubOrganization(models.Model):
lead_contact = models.OneToOneField(LeadContact, blank=True, null=True)
and Lead Contact
class LeadContact(models.Model):
account_handler = models.ForeignKey(User, blank=True, null=True, related_name='handling_leads', on_delete=models.SET_NULL)
What would be the proper way of doing this?

Related

How to use #property in Django models?

I want to add one subquery to my query. And I created a #property in Transaction. Found on the Internet that this is what I need. But I do not fully understand how they work. How to use it?
views.py(Query)
paymentsss = Transaction.objects.all().select_related('currency',
'payment_source__payment_type',
'deal__service__contractor',).
models.py
class PayerPaymentSource(models.Model):
id = models.BigIntegerField(blank=True, null=False, primary_key=True)
payer_id = models.BigIntegerField(blank=True, null=True)
payment_type = models.ForeignKey(PaymentType, max_length=64, blank=True, null=True, on_delete=models.CASCADE)
source_details = models.TextField(blank=True, null=True) # This field type is a guess.
class Meta:
managed = False
db_table = '"processing"."payer_payment_source"'
class Transaction(models.Model):
id = models.BigIntegerField(blank=True, null=False, primary_key=True)
currency = models.ForeignKey(Currency, null=True, on_delete=models.CASCADE)
deal = models.ForeignKey(Deal, null=True, on_delete=models.CASCADE)
# service_instance = models.ForeignKey(ServiceInstance, null=True, on_delete=models.CASCADE)
payment_source = models.ForeignKey(PayerPaymentSource, null=True, on_delete=models.CASCADE)
payment_date = models.DateTimeField(blank=True, null=True)
amount = models.IntegerField(blank=True, null=True)
status = models.CharField(max_length=255, blank=True, null=True)
context = models.TextField(blank=True, null=True)
#property
def bank_card_details(self):
return PayerPaymentSource.objects.filter(self.payment_source.source_details,
payment_type='bank_card_details')
class Meta:
managed = False
db_table = '"processing"."transaction"'
UPD: print(payment.bank_card_details) works, but it creates a lot of similar queries. How to fix it?
The #property decorator is just a convenient way to call the property() function, which is built in to Python. This function returns a special descriptor object which allows direct access to the method's computed value.
For example in your view
obj = Transaction.objects.get(pk=pk)
#now you can get the bank_card_details like this:
print(obj.bank_card_details)

How to order_by related field date with annotation?

i have this model :
class Node(MPTTModel):
parent = TreeForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='children')
name = models.TextField(blank=True, null=True)
which have this related model :
class Views(models.Model):
related_tree = models.ForeignKey(Node, on_delete=models.CASCADE, blank=True, null=True, related_name='related_views')
views_count = models.PositiveIntegerField(null=True, blank=True, default=0)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, blank=True, null=True)
view_date = models.DateTimeField(default=timezone.now)
What i am trying to do is to order a queryset of the first model by the view date of the second one, this is the view that i have tried :
last_viewed_trees = Node.objects.filter(tree_type='root').order_by('-related_views__view_date')
In that one the result is correct but i have a duplicate view_date of many users.
I have tried also this one without success :
last_viewed_trees = Node.objects.filter(tree_type='root').annotate(time_of_views= Min('related_views__views_count')
).order_by('-time_of_views')
last_viewed_trees = Node.objects.filter(tree_type='root').annotate(time_of_views= Max('related_views__views_count')
).order_by('-time_of_views')
Nothing have worked for me, there is something that i am missing, but i cannot identify it.

Filter django for objects containing subsets of same many to many relationship

In my database I have user objects with two many to many fields (messages and following) on them that both contain a many to many field related to another object Topic.
class User():
messages = ManyToManyField('Message', related_name='users', blank=True, null=True)
following = ForeignKey('Following', related_name='users', blank=True, null=True)
class Message():
date = DateField(blank=True, null=True)
content = TextField(blank=True, null=True)
topics = ManyToManyField('Topic', related_name='messages', blank=True, null=True)
class Following():
name = CharField(max_length=255, blank=True, null=True)
description = CharField(max_length=255, blank=True, null=True)
topics = ManyToManyField('Topic', related_name='following', blank=True, null=True)
class Topic():
name = CharField(max_length=255, blank=True, null=True)
source = CharField(max_length=255, blank=True, null=True)
I want to filter for all "users" who have "messages" attached to them that do not contain all of the topics attached to the "following" objects on the user.
Right now I am using a loop to accomplish this:
users = set()
for user in User.objects.filter(messages__isnull=False, following__isnull=False).iterator():
if not set(user.following.values_list('topics', flat=True))
).issubset(set(user.messages.values_list('topics', flat=True)):
users.add(user.pk)
Is there a way to accomplish the same thing with a single query?
---- EDIT ----
What I have is this:
User.objects.filter(following__isnull=False
).annotate(following_count=Count('following__topics', distinct=True)
).filter(following__topics__exact=F('message__topics')
).annotate(missing_topics=ExpressionWrapper(
F('following_count') - Count('message__topics', distinct=True),
IntegerField())
).filter(missing_topics__gt=0)
If there is a better way to do this or there are reasons why I should most definitely not do it this way, what are they?
---- EDIT ----
This question helped me to understand and use HÃ¥ken Lid's answer
This is my new model and my new query:
class User():
messages = ManyToManyField('Message', related_name='users', blank=True, null=True)
following = ManyToManyField('Topic', through='Following', related_name='users', blank=True, null=True)
class Message():
date = DateField(blank=True, null=True)
content = TextField(blank=True, null=True)
topics = ManyToManyField('Topic', related_name='messages', blank=True, null=True)
class Following():
name = CharField(max_length=255, blank=True, null=True)
description = CharField(max_length=255, blank=True, null=True)
user = ForeignKey('User', related_name='following', blank=True, null=True)
topic = ForeignKey('Topic', related_name='following', blank=True, null=True)
class Topic():
name = CharField(max_length=255, blank=True, null=True)
source = CharField(max_length=255, blank=True, null=True)
User.objects.filter(~Q(messages__topics__in=F('following'))
).values('id').annotate(missing_topics=Count('following__topics', distinct=True))
This should be possible using a subquery.
First, make sure Following.topics uses a different related name than Messages.topics.
class Following(models.Model):
topics = ManyToManyField('Topic', related_name='following')
Then it should be possible to create a subquery. Something like this:
from django.db.models import OuterRef, Subquery
user_following_topic = Topic.objects.filter(following__users=OuterRef('pk'))
User.objects.exclude(messages__topics__in=Subquery(user_following_topics.values('pk')))
This might not work and give you your expected output exactly as written, but I think the principle should work for your case as well.
On the other hand, I don't really understand your database structure. It seems you use m2m relations where foreign keys could be more appropriate and simpler. The more complicated your relations are, the harder it is to create this kind of advanced query. And queries with lots of database joins can be very slow, since they might have to process huge amounts of data, compared to simple queries.
For example, instead of using m2m realitions, Following would make more sense to me like so:
class Following():
topic = ForeignKey('Topic', on_delete=models.CASCADE)
user = ForeignKey('User', on_delete=models.CASCADE)
client = models.CharField(max_length=255, blank=True, null=True)
duration = fields.DateRangeField(blank=False, null=False)
So basically a "through" model, as explained in the django docs on model relationships where there's a similar example.

Django QuerySet, Filtering Data Based on The Latest Entry of Each Data's Column/Field equals to a particular Value

#models.py
class Orders(models.Model):
orderid = models.IntegerField(db_column='orderID', primary_key=True)
createdate = models.DateField(db_column='createDate', blank=True, null=True)
pickupdate = models.DateField(db_column='pickupDate', blank=True, null=True)
returndate = models.DateField(db_column='returnDate', blank=True, null=True)
pickupstore = models.ForeignKey(Branch, models.DO_NOTHING, db_column='pickupStore', blank=True, null=True,related_name = 'pickupstore')
returnstore = models.ForeignKey(Branch, models.DO_NOTHING, db_column='returnStore', blank=True, null=True,related_name = 'returnstore')
rentedvehicle = models.ForeignKey('Vehicles', models.DO_NOTHING, db_column='rentedVehicle', blank=True, null=True)
customer = models.ForeignKey(Customer, models.DO_NOTHING, db_column='customer', blank=True, null=True)
class Vehicles(models.Model):
vehicleid = models.IntegerField(db_column='vehicleID', primary_key=True)
make = models.CharField(max_length=45, blank=True, null=True)
model = models.CharField(max_length=45, blank=True, null=True)
series = models.CharField(max_length=45, blank=True, null=True)
Orders model have foreign key rentedvehicle which refers to Vehicles models
I have filtered the data based on the pickupstore state, e.g. The list of vehicles that are picked up from store in a particular state
Vehicles.objects.filter(orders__pickupstore__state = request.POST['state'])
I want to be able to filter the filtered data above so that I can get a list of vehicles that are picked up from store in a particular state WITH its latest entry in Orders models has returnstore__state == a particular state
So basically, I want to achieve this:
Vehicles.objects.filter(orders__pickupstore__state = request.POST['state']).filter(the latest entry returnstore state =request.POST['state'])
Many possible solutions. Optimal depends on your Django version (1.11 or higher?). Here's one possible solution:
from django.db.models import Max, F
Vehicles.objects.filter(orders__pickupstore__state = request.POST['state']).annotate(max_date=Max('orders__returndate')).filter(orders__return_date=F('max_date')).filter(orders__state = request.POST['state'])
What's happening here is that we're identifying the most recent return date, then filtering the orders to only include the most recent, then filtering the Vehicles on the state of that latest order.

Django - Multi Table Inheritance with django admin

I am trying to learn django by creating a blog on my own, and I've tried some real simple steps before, but now I want to make something slightly more complex. Currently, I am thinking of dividing the blogs' 'Stories' into 'Blocks'. My idea is to have two child classes 'TextBlock' and 'ImageBlock', and my current models look like this.
class Story(models.Model):
writer = models.CharField(max_length=189)
title = models.CharField(max_length=189)
class Block(models.Model):
story = models.ForeignKey(Story, related_name='+', on_delete=models.CASCADE)
block = EnumField(choices=[
('TXT', "text"),
('IMG', "image"),
])
serial = models.IntegerField(default=0)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
class TextBlock(Block):
type = models.CharField(max_length=128, blank=True, null=True, default='paragraph')
content = models.TextField(blank=True, null=True)
class ImageBlock(Block):
src = models.URLField()
type = models.CharField(max_length=128, blank=True, null=True, default='full')
title = models.CharField(max_length=189, blank=True, null=True)
photographer = models.CharField(max_length=128, blank=True, null=True)
What I'd like to do now is to create blog entries from the django admin interface. Is it possible to create both types from the main Block? Or do I need to go to both TextBlock and ImageBlock? Any ideas on how I should proceed from here? Thanks.