Complex relationships with filtering - django

I'm stuggling to get to grips with relationships in ORM.
I want to get a distinct CostItem queryset related to a particular event.
Normally I'd filter CostFixedList for the particular event I'm interested and get a the Cost_Rate id's. From that I could then get the CostItem id's.
I could do this easily in SQL, but can't understand how to start with ORM. Can anyone point me in the right direction?
class Event(models.Model):
event_type = models.ForeignKey(EventType)
retailer = models.ForeignKey(Retailer)
....
class CostItem(models.Model):
name = models.CharField("Name", max_length=50, unique=True)
cost_type = models.ForeignKey(CostType, verbose_name="Type")
active = models.BooleanField("Active", default=True)
class CostRate(models.Model):
cost_item = models.ForeignKey(CostItem, verbose_name="Item")
valid_from = models.DateField("From")
valid_till = models.DateField("Till")
unit_amount = models.DecimalField("Price Per Unit", max_digits=5, decimal_places=2)
class CostFixedList(models.Model):
event = models.ForeignKey(Event)
cost_rate = models.ForeignKey(CostRate)
units = models.IntegerField()
appointment = models.ForeignKey(Appointment, null=True, blank=True)

I think this should do it (where myevent is the event for which you wish to obtain the CostItem queryset):
qs = CostItem.objects.filter(costrate__costfixedlist__event=myevent)

Related

Group By Django queryset by a foreignkey related field

I have a model Allotment
class Kit(models.Model):
kit_types = (('FLC', 'FLC'), ('FSC', 'FSC'), ('Crate', 'Crate'), ('PP Box', 'PP Box'))
kit_name = models.CharField(max_length=500, default=0)
kit_type = models.CharField(max_length=50, default=0, choices=kit_types, blank=True, null=True)
class AllotmentFlow(models.Model):
flow = models.ForeignKey(Flow, on_delete=models.CASCADE)
kit = models.ForeignKey(Kit, on_delete=models.CASCADE)
asked_quantity = models.IntegerField(default=0)
alloted_quantity = models.IntegerField(default=0)
class Allotment(models.Model):
transaction_no = models.IntegerField(default=0)
dispatch_date = models.DateTimeField(default=datetime.now)
send_from_warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
flows = models.ManyToManyField(AllotmentFlow)
For a stacked graph I am trying to get the data of different kit_type alloted in different months.
For that I have tried annotate but it isn't getting the desired results
dataset = Allotment.objects.all().annotate(
month=TruncMonth('dispatch_date')).values(
'month').annotate(dcount=Count('flows__kit__kit_type')).values('month', 'dcount')
Expected Output:
[{'month':xyz, 'kit_type':foo, count:123},...]
I am getting the month and count of kit type from above but how do I segregate it by kit_type?
having a field that represents your choice field names in this query is difficult
instead how about use the Count filter argument and annotate to get what you want
dataset = Allotment.objects.all().annotate(month=TruncMonth('dispatch_date')).values('month').annotate(
FLC_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="FLC")),
FSC_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="FSC")),
Crate_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="Crate")),
PP_Box_count=Count('flows__kit__kit_type', filter=Q(flows__kit__kit_type="PP_Box")),
).values('month', 'FLC_count', 'FSC_count', 'Crate_count', 'PP_Box_count')

how to filter data in different models in django?

my models
class Player(TimeStampedModel):
name = models.CharField(max_length=200)
email = models.CharField(max_length=200)
email_verified = models.BooleanField(default=False, blank=True)
phone = models.CharField(max_length=200)
phone_verified = models.BooleanField(default=False, blank=True)
company_id = models.ImageField(upload_to=get_file_path_id_card, null=True,
max_length=255)
company_id_verified = models.BooleanField(default=False, blank=True)
team = models.ForeignKey(Team, related_name='player', on_delete=models.DO_NOTHING)
def __str__(self):
return self.name
this is my model , how to filter data in multiple model?
You can use a Queryset to filter by modal object's field.
You can use this to also filter relationships on models.
In your example, you can do a filter of all the Player entries that have a Character that have Weapon with strength > 10
Player.objects.filter(character__weapon__strength__gt=10)
You can also separate them out into 3 variables for readability purposes.
player_q = Player.objects.filter(character__isnull=False)
ch_q = player_q.filter(weapon__isnull=False)
wpn_dmg = ch_q.filter(strength__gt=10)
Please note that filters are lazy and thus don't return actual model instances untill they're evaluated. I think in this case gt returns an instance.
This documentation goes over all the fieldset lookups you can do with QuerySet object methods filter(), get(), and exclude()

Archive records and re-inserting new records in Django?

I've got a Stock table and a StockArchive table.
My Stock table consists of roughly that 10000 stocks that I update daily. The reason I have a StockArchive table is because I still wanna some historic data and not just update existing records. My question is, is this a proper way of doing it?
First, my models:
class Stock(models.Model):
objects = BulkUpdateOrCreateQuerySet.as_manager()
stock = models.CharField(max_length=200)
ticker = models.CharField(max_length=200)
exchange = models.ForeignKey(Exchange, on_delete=models.DO_NOTHING)
eod_price = models.DecimalField(max_digits=12, decimal_places=4)
currency = models.CharField(max_length=20, blank=True, null=True)
last_modified = models.DateTimeField(blank=True, null=True)
class Meta:
db_table = "stock"
class StockArchive(models.Model):
objects = BulkUpdateOrCreateQuerySet.as_manager()
stock = models.ForeignKey(Stock, on_delete=models.DO_NOTHING)
eod_price = models.DecimalField(max_digits=12, decimal_places=4)
archive_date = models.DateField()
class Meta:
db_table = "stock_archive"
I proceed on doing the following:
#transaction.atomic
def my_func():
archive_stocks = []
batch_size = 100
old_stocks = Stock.objects.all()
for stock in old_stocks:
archive_stocks.append(
StockArchive(
stock=stock.stock,
eod_price = stock.eod_price,
archive_date = date.today(),
)
)
# insert into stock archive table
StockArchive.objects.bulk_create(archive_stocks, batch_size)
# delete stock table
Stock.objects.all().delete()
# proceed to bulk_insert new stocks
I also wrapped the function with a #transaction.atomic to make sure that everything is committed and not just one of the transactions.
Is my thought process correct, or should I do something differently? Perhaps more efficient?

DJango ORM double join with Sum

I searched for a similar case on SO and Google with no luck.
SHORT EXPLANATION
I have transactions that belong to an account, and an account belongs to an account aggrupation.
I want to get a list of accounts aggrupations, with their accounts, and I want to know the total balance of each account (an account balance is calculated by adding all its transactions amount).
LONG EXPLANATION
I have the following models (I include mixins for the sake of completeness):
class UniqueNameMixin(models.Model):
class Meta:
abstract = True
name = models.CharField(verbose_name=_('name'), max_length=100, unique=True)
def __str__(self):
return self.name
class PercentageMixin(UniqueNameMixin):
class Meta:
abstract = True
_validators = [MinValueValidator(0), MaxValueValidator(100)]
current_percentage = models.DecimalField(max_digits=5,
decimal_places=2,
validators=_validators,
null=True,
blank=True)
ideal_percentage = models.DecimalField(max_digits=5,
decimal_places=2,
validators=_validators,
null=True,
blank=True)
class AccountsAggrupation(PercentageMixin):
pass
class Account(PercentageMixin):
aggrupation = models.ForeignKey(AccountsAggrupation, models.PROTECT)
class Transaction(models.Model):
date = models.DateField()
concept = models.ForeignKey(Concept, models.PROTECT, blank=True, null=True)
amount = models.DecimalField(max_digits=10, decimal_places=2)
account = models.ForeignKey(Account, models.PROTECT)
detail = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return '{} - {} - {} - {}'.format(self.date, self.concept, self.amount, self.account)
I want to be able to do this in Django ORM:
select ca.*, ca2.*, sum(ct.amount)
from core_accountsaggrupation ca
join core_account ca2 on ca2.aggrupation_id = ca.id
join core_transaction ct on ct.account_id = ca2.id
group by ca2.name
order by ca.name;
It would appear that nesting navigation through sets is not possible:
Wrong: AccountsAggrupation.objects.prefetch_related('account_set__transaction_set')
(or any similar approach). The way to work with this is the way around: go from transaction to account and then to account_aggroupation.
But, as I needed to have a dict with account_aggroupation, pointing each key to its set of accounts (and the balance for each), I ended up doing this:
def get_accounts_aggrupations_data(self):
accounts_aggrupations_data = {}
accounts_balances = Account.objects.annotate(balance=Sum('transaction__amount'))
for aggrupation in self.queryset:
aggrupations_accounts = accounts_balances.filter(aggrupation__id=aggrupation.id)
aggrupation.balance = aggrupations_accounts.aggregate(Sum('balance'))['balance__sum']
accounts_aggrupations_data[aggrupation] = aggrupations_accounts
current_month = datetime.today().replace(day=1).date()
date = current_month.strftime('%B %Y')
total_balance = Transaction.objects.aggregate(Sum('amount'))['amount__sum']
return {'balances': accounts_aggrupations_data, 'date': date, 'total_balance': total_balance}
Note that since I'm iterating through the accounts_aggrupations, that query (self.queryset, which leads to AccountsAggrupation.objects.all()) is executed to the DB.
The rest of the queries I do, do not execute yet because I'm not iterating through them (until consuming the info at the template).
Also note that the dictionary accounts_aggrupations_data has an accounts_aggrupation object as key.

Posting in several tastypie resources simultaneously

Here's what I'm trying to do :
The user creates an Event in my application. Here's the model :
class Event(models.Model):
name = models.CharField(max_length=40)
organizer = models.ForeignKey(UserProfile)
description = models.TextField(null=True)
place = models.TextField(null=True)
confirmed = models.BigIntegerField(null=True)
organizer_part = models.BooleanField(default=True)
slug = models.SlugField()
Right after that, it posts the different people invited to this event, and the different dates that the user chose. Here are the models :
class EventDate(models.Model):
"""Correspondances date-event"""
event = models.ForeignKey(Event)
date = models.BigIntegerField()
class EventPeople(models.Model):
"""Correspondances personne-event"""
event = models.ForeignKey(Event)
phone_number = models.PositiveIntegerField()
name = models.CharField(max_length=32)
answer = models.BooleanField()
participation = models.NullBooleanField()
I'd like to fill those three models in only one request. So far I have to make three requests. I can't see how I could possibly do it.
Any idea would be highly appreciated.
Resource that should work with your models is:
class EventResource(ModelResource):
event_dates = fields.ToManyField(EventDateResource, 'event_dates')
event_peoples = field.ToManyField(EventPeopleResource, 'event_peoples')
class Meta:
queryset = Event.objects.all()
Also you have to create simple EventDateResource and EventPeopleResource.
One one more change in yout models, you need to add related_names:
class EventDate(models.Model):
"""Correspondances date-event"""
event = models.ForeignKey(Event, related_name='event_dates')
date = models.BigIntegerField()
class EventPeople(models.Model):
"""Correspondances personne-event"""
event = models.ForeignKey(Event, related_name='event_peoples')
phone_number = models.PositiveIntegerField()
name = models.CharField(max_length=32)
answer = models.BooleanField()
participation = models.NullBooleanField()