filter from an object and more object that related in django? - django

This Is my models.py
class Customer(models.Model):
def __unicode__(self):
return self.name
name = models.CharField(max_length=200)
type = models.ForeignKey(Customer_Type)
active = models.BooleanField(default=True)
class Sale(models.Model):
def __unicode__(self):
return "Sale %s (%i)" % (self.type, self.id)
customer = models.ForeignKey(Customer)
total = models.DecimalField(max_digits=15, decimal_places=3)
class Unitary_Sale(models.Model):
book = models.ForeignKey(Book)
quantity = models.IntegerField()
unit_price = models.DecimalField(max_digits=15, decimal_places=3)
sale = models.ForeignKey(Sale)
Views.py
def get_filter_result(self, customer_type='' volume_sale=''):
qdict = {}
if customer_type != '':
qdict['type__name'] = customer_type
qdict['active']=True
#WHAT I AM GOING TO DO NEXT
*** if volume_sale != '':
pass # This point I am asking :)
#IT RETURN CUSTOMERS BASE ON PARAMS.
queryset = Customer.objects.filter(**qdict)
***The volume_sale is:
units=Unitary_Sale.objects.all()
>>> units=Unitary_Sale.objects.all()
>>> for unit in units:
... print unit.sale.customer
... print unit.book,unit.sale.total
...
Sok nara
Khmer Empire (H001) 38.4
Sok nara
killing field (H001) 16
San ta
khmer krom (H001) 20
San ta
Khmer Empire (H001) 20
>>>
{<Customer: Sok nara>: Decimal("56.4"), <Customer: san ta>: Decimal("40")}
Decimal("56.4") , Decimal("40") this is the volume_sale
I could not find the ways to make the filter from difference object as in my case.
It will be great if everyone here help in this stuck? Thanks.

Cool, this actually pretty easy to implement. I used the django annotation feature documented here and here:
from django.db.models import Sum
query = Customer.objects.all().annotate(volume_sale = Sum('Sale__total'))
query.filter(volume_sale < 12.0) #return all customers that have purchased less than 12.0
query[0].volume_sale #you can even get it on the Customer objects given back
Django will take care of the database joins for you. It will put this extra field into each instance of the model that you can filter, order_by and access in templates or views.

Related

query to django model to compare daily sale over previous day (compare two row of database model)

I have a django model that is "DailyReport" of the companies sale I want to find out company sale change over the previous day.
the model that i define is like that:
class DailyReport(models.Model):
company = models.CharField(max_length=50)
sale = models.IntegerField()
date = models.DateField()
How can i figure out this issue to add new column for every report that represent change rate over the previous day
Use the Lag window function to annotate each row with the previous sale amount for that company.
Then use another annotation to calculate the difference between the current and previous sale
from django.db.models import Window, F
from django.db.models.functions import Lag
DailyReport.objects.annotate(
prev_val=Window(
expression=Lag('sale', default=0),
partition_by=['company'],
order_by=F('date').asc(),
)
).annotate(
diff=F('sale') - F('prev_val')
)
Assuming you can have only one record of a company for each day, you can create a model property:
#property
def previous_day_sale(self):
date = self.date
dr = DailyReport.objects.filter(company=self.company, date=date-timedelta(days=1)
if dr:
return dr.first().sale - self.sale
You may need to override the save method, but you will have to cover all edge cases.
class DailyReport(models.Model):
company = models.CharField(max_length=50)
sale = models.IntegerField()
date = models.DateField()
sale_over_previous_day = models.IntegerField()
def save(self, *args, **kwargs):
previous_day_sale_object = DailyReport.objects.filter(company=self.company, date=date-timedelta(days=1))
if previous_day_sale_object:
previous_day_sale = previous_day_sale_object[0].sale
else:
previous_day_sale = 0
self.sale_over_previous_day = self.sale - previous_day_sale
super(DailyReport, self).save(*args, **kwargs)

How to display database data to your website?

This is a very simple question that got me stuck. I have 2 tables that are connected: Dealershiplistings, Dealerships. On my website I need to display the Model, Make and year of the car (Which are all stored in the DealershipListing, so i have no problem wiht this part) but I also need to print the address that is stored in the Dealerships table. Can anyone help me with this?
this is what i have for my views.py
def store(request):
dealer_list = Dealer.objects.all()
car_list = DealershipListing.objects.all()
context = {'dealer_list': dealer_list, 'car_list': car_list}
return render(request, 'store/store.html', context)
i tried doing
{{%for car in car_list%}}
<h6>{{car.year}} {{car.make}} {{car.model}}</h6>
{% endfor %}
which works perfectly displaying those. But now how do i display the address of the dealership that is selling the car?
models.py
class Dealer(models.Model):
dealersName = models.TextField(('DealersName'))
zipcode = models.CharField(("zipcodex"), max_length = 15)
zipcode_2 = models.CharField(("zipCode"), max_length = 15)
state = models.CharField(("state"), max_length=5)
address = models.TextField(("Address"))
dealerId = models.IntegerField(("ids"), primary_key=True)
def __str__(self):
return self.dealersName
class DealershipListing(models.Model):
carID = models.IntegerField(("CarID"), primary_key=True)
price = models.IntegerField(('price'))
msrp = models.IntegerField(('msrp'))
mileage = models.IntegerField(('mileage'))
is_new = models.BooleanField(('isNew'))
model = models.CharField(("Models"), max_length= 255)
make = models.CharField(("Make"), max_length=255)
year = models.CharField(("Year"),max_length=4)
dealerID = models.ForeignKey(Dealer, models.CASCADE)
def __str__(self):
return self.year + " " + self.make + " " + self.model
So then it looks like your question is really How do I access data from a foreign key in a template?
The answer is refreshingly simple!
{{car.dealerID.address}}
On a side note, you might want to rename dealerID to dealer, django will handle the db column names how it sees fit, so while you might access the data with .dealer the db column would be named dealer_id by django automatically. Renaming the field also makes it more obvious that accessing it will give you a dealer and not its id.
calling with the model name is what I prefer to use
{{obj.related_table.field_name}}
I think this pattern may help you solve problem related to getting related field value

Django sum objects filtering another model

I have this 3 models:
class Provider(models.Model):
name = models.CharField("Provider",max_length=200)
def __str__(self):
return self.name
class Contract(models.Model):
active = models.BooleanField(default=False, verbose_name="Active?")
provider = models.ForeignKey(Provider, on_delete=models.CASCADE,verbose_name="Provider")
total_to_spent = models.IntegerField(blank=True, null=True, verbose_name="Total to spend")
def __str__(self,):
return str(self.id) + '- ' + str(self.provider)
class Invoice(models.Model):
contract = models.ForeignKey(Contract, on_delete=models.CASCADE,verbose_name="Contract",related_name='ContractObject',)
value = models.IntegerField(verbose_name="Value")
def __str__(self,):
return str(self.contract)
total_to_spent in Contract.model is the amount of money i can spent in that contract
value in Invoice.model is the money related to that invoice that is then associated with the contract
My view
def ServicoView(request):
contracts = Contract.objects.all()
contract_active = Contract.objects.filter(active=True)
contratos_finish = Contract.objects.filter(active=False)
//i was trying something like this
for i in contracts:
invoices= Invoice.objects.filter(contract=contract['id']).values().aggregate(total=Sum('value '))
context = {
'contract_active': contract_active,
'contratos_finish':contratos_finish,
}
return render(request, 'dashboard_servico.html', context)
In my view i want to do the SUM of all invoices (value) related to one Contract for later compare to the total_to_spent to see if it passes the value or not
In my view i want to do the SUM of all invoices (value) related to one Contract for later compare to the total_to_spent to see if it passes the value or not
You could do use the below query to get the sum of value of all the invoices belonging to a particular contract with id as contract_id
Invoice.objects.filter(contract_id=contract_id).values('value').annotate(total=Sum(value))
A similar question is answered in this link where you can find more detailed information

how to get the latest in django model

In this model:
class Rank(models.Model):
User = models.ForeignKey(User)
Rank = models.ForeignKey(RankStructure)
date_promoted = models.DateField()
def __str__(self):
return self.Rank.Name.order_by('promotion__date_promoted').latest()
I'm getting the error:
Exception Value:
'str' object has no attribute 'order_by'
I want the latest Rank as default. How do I set this?
Thanks.
Update #1
Added Rank Structure
class RankStructure(models.Model):
RankID = models.CharField(max_length=4)
SName = models.CharField(max_length=5)
Name = models.CharField(max_length=125)
LongName = models.CharField(max_length=512)
GENRE_CHOICES = (
('TOS', 'The Original Series'),
('TMP', 'The Motion Picture'),
('TNG', 'The Next Generation'),
('DS9', 'Deep Space Nine'),
('VOY', 'VOYAGER'),
('FUT', 'FUTURE'),
('KTM', 'KELVIN TIMELINE')
)
Genre = models.CharField(max_length=3, choices=GENRE_CHOICES)
SPECIALTY_OPTIONS = (
('CMD', 'Command'),
('OPS', 'Operations'),
('SCI', 'Science'),
('MED', 'Medical'),
('ENG', 'Engineering'),
('MAR', 'Marine'),
('FLT', 'Flight Officer'),
)
Specialty = models.CharField(max_length=25, choices=SPECIALTY_OPTIONS)
image = models.FileField(upload_to=image_upload_handler, blank=True)
This is the Rank_structure referenced by Rank in Class Rank.
THe User Foreign key goes to the standard User table.
The reason that you’re getting an error is because self.Rank.Name is not a ModelManager on which you can call order_by. You’ll need an objects in there somewhere if you want to call order_by. We can’t help you with the django formatting for the query you want unless you also post the model definitions as requested by several commenters. That said, I suspect that what you want is something like:
def __str__(self):
return self.objects.filter(Rank_id=self.Rank_id).order_by('date_promoted').latest().User.Name

Sorting products after dateinterval and weight

What I want is to be able to get this weeks/this months/this years etc. hotest products. So I have a model named ProductStatistics that will log each hit and each purchase on a day-to-day basis. This is the models I have got to work with:
class Product(models.Model):
name = models.CharField(_("Name"), max_length=200)
slug = models.SlugField()
description = models.TextField(_("Description"))
picture = models.ImageField(upload_to=product_upload_path, blank=True)
category = models.ForeignKey(ProductCategory)
prices = models.ManyToManyField(Store, through='Pricing')
objects = ProductManager()
class Meta:
ordering = ('name', )
def __unicode__(self):
return self.name
class ProductStatistic(models.Model):
# There is only 1 `date` each day. `date` is
# set by datetime.today().date()
date = models.DateTimeField(default=datetime.now)
hits = models.PositiveIntegerField(default=0)
purchases = models.PositiveIntegerField(default=0)
product = models.ForeignKey(Product)
class Meta:
ordering = ('product', 'date', 'purchases', 'hits', )
def __unicode__(self):
return u'%s: %s - %s hits, %s purchases' % (self.product.name, str(self.date).split(' ')[0], self.hits, self.purchases)
How would you go about sorting the Products after say (hits+(purchases*2)) the latest week?
This structure isn't set in stone either, so if you would structure the models in any other way, please tell!
first idea:
in the view you could query for today's ProductStatistic, than loop over the the queryset and add a variable ranking to every object and add that object to a list. Then just sort after ranking and pass the list to ur template.
second idea:
create a filed ranking (hidden for admin) and write the solution of ur formula each time the object is saved to the database by using a pre_save-signal. Now you can do ProductStatistic.objects.filter(date=today()).order_by('ranking')
Both ideas have pros&cons, but I like second idea more
edit as response to the comment
Use Idea 2
Write a view, where you filter like this: ProductStatistic.objects.filter(product= aProductObject, date__gte=startdate, date__lte=enddate)
loop over the queryset and do somthing like aProductObject.ranking+= qs_obj.ranking
pass a sorted list of the queryset to the template
Basically a combination of both ideas
edit to your own answer
Your solution isn't far away from what I suggested — but in sql-space.
But another solution:
Make a Hit-Model:
class Hit(models.Model):
date = models.DateTimeFiles(auto_now=True)
product = models.ForeignKey(Product)
purchased= models.BooleanField(default=False)
session = models.CharField(max_length=40)
in your view for displaying a product you check, if there is a Hit-object with the session, and object. if not, you save it
Hit(product=product,
date=datetime.datetime.now(),
session=request.session.session_key).save()
in your purchase view you get the Hit-object and set purchased=True
Now in your templates/DB-Tools you can do real statistics.
Of course it can generate a lot of DB-Objects over the time, so you should think about a good deletion-strategy (like sum the data after 3 month into another model MonthlyHitArchive)
If you think, that displaying this statistics would generate to much DB-Traffic, you should consider using some caching.
I solved this the way I didn't want to solve it. I added week_rank, month_rank and overall_rank to Product and then I just added the following to my ProductStatistic model.
def calculate_rank(self, days_ago=7, overall=False):
if overall:
return self._default_manager.all().extra(
select = {'rank': 'SUM(hits + (clicks * 2))'}
).values()[0]['rank']
else:
return self._default_manager.filter(
date__gte = datetime.today()-timedelta(days_ago),
date__lte = datetime.today()
).extra(
select = {'rank': 'SUM(hits + (clicks * 2))'}
).values()[0]['rank']
def save(self, *args, **kwargs):
super(ProductStatistic, self).save(*args, **kwargs)
t = Product.objects.get(pk=self.product.id)
t.week_rank = self.calculate_rank()
t.month_rank = self.calculate_rank(30)
t.overall_rank = self.calculate_rank(overall=True)
t.save()
I'll leave it unsolved if there is a better solution.