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
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')
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()
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?
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.
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()