Django filter using two conditions - python

I am developing a web app using django. Among with other tables, I have a table called GeneralContract, which has issueDate and Expiration Date as date fields.
I want to find out the profit of an insurance agent in my case would get from these contracts between a period. For example, if the date range is 15 January 2015 - 25 February 2015 I would like to filter all GeneralContract objects who are issued ANY year between this period.
(i.e. issueDate__month = Date1.month AND IssueDate.day_gte= Date1.day) AND (IssueDate__month = Date2.month AND IssueDate.day_lte = Date2.day) ??
I tried the following but it is not giving me the results I wanted and I am not sure if I am writing this in the correct syntax or if my logic is wrong.
criterion1 = Q(issuedate__month=date1.month)
criterion2 = Q(issuedate__day__gte=date1.day)
criterion3 = Q(issuedate__month=date2.month)
criterion4 = Q(issuedate__day__lte=date2.day)
criterionA = criterion1 & criterion2
criterionB = criterion3 & criterion4
criterionC = criterionA & criterionB
currentGenProfits = GeneralContract.objects.filter(criterionC, cancelled=False)
Is this the right way of doing this filtering logic?

You can't do that because if date1.day = 5 and date2.day = 4 you will have no result, you must check the month and the date together, syntax is right but logic is wrong.
I may suggest to start by taking the biggest set and then apply filtering on it
Start with filtering between the two month and then remove from the queryset objects which are on the first month but before the min day and remove from the queryset objects which are on the last month but after the max day, i think that can do the job.

Related

Calculate Business Days in Django Annotate

I wanted to calculate business days in Django annotate. For example, if an event was generated 7 days back, and I wanted to know how many business days had passed. As per the example, 7 days includes [Monday - Sunday], and I only wanted to include [Monday - Friday], which means 5 business days. I've done this logic via some pythonic hack, but I wanted to do this in Django annotate() method. So I can filter the results based on business days.
Here is an example of what I've done so far:
table_values = Table.objects.all().annotate(issue_severity=datetime.utcnow() - F("event__created"))
for table in table_values:
date = datetime.now(timezone.utc) - table.issue_severity
dates = (date + timedelta(x + 1) for x in range(table.issue_severity.days))
table.business_days = sum(day.weekday() < 5 for day in dates)

Django: Why Filtering By Year Works, But Not Month and Day?

I have a simple datetime field named date. Stores dates and time like this: 2015-07-04 01:40:00+00:00.
When I run
today = datetime.datetime.now().today()
x = game.objects.filter(date__year=today.year)
It works, however if i run
today = datetime.datetime.now().today()
x = game.objects.filter(date__month=today.month)
I get an empty list.
Current month is July. If you filter by the year part of the date being equal to current month, then you search for records being in the year of 07 AD. I believe you do not have such records. You need to filter by month of the date if you want to filter by month.

Applying an arbitrary sort to Django ORM querysets

I have a database table containing sets of items representing yearly recurring events. The record sets are stored by month and day. I often need to retrieve the event records corresponding to a range of calendar dates. I'm using the Django ORM to work with the records, so at present I convert the dates to corresponding Q objects (e.g. Q(month=month, day=day) and OR them together in the call to MyModel.objects.filter().
The problem comes if my date range intersects the new year. If I want the events from Dec. 31, 2013 to Jan 1, 2014, I do something like:
MyModel.objects.filter(Q(month=12, day=31) | Q(month=1, day=1))
But I get my results in the order:
month = 1, day = 1
month = 12, day = 31
Instead, I would like to get my results in the order:
month = 12, day = 31
month = 1, day = 1
For reasons that would unnecessarily complicate the question, I can't simply partition the query into two queries, one for each year. I would like to make one query and get the results in the desired order. I can reformulate the query, if necessary.
I know that extra should be useful, but I don't quite see how to use it.
Update:
To head a little closer to the intended solution, to impose an absolute ordering I could somehow slip the Julian Day into the results as a "calculated" field, and order by that field. But how to do that?
I have tricky solution Using extra and SQL CASE statement:
start_month = 12
start_day = 31
end_month = 1
end_day = 1
query = (models.MyModel.objects.filter(Q(month=start_month, day=start_day) |
Q(month=end_month, day=end_day))
.extra(select={'order_me': '''CASE WHEN month*31+day < %s*31+%s
THEN (12+month)*31+day
ELSE (month)*31+day
END''' % (start_month, start_day)})
.extra(order_by=['order_me']))
As soon as I have added this order_me field (which is not nice) I think It should be used in predicate instead of Q(...)|Q(...) for date range
query = (models.MyModel.objects.all()
.extra(select={'order_me': """CASE WHEN month*31+day < %s*31+%s
THEN (12+month)*31+day
ELSE (month)*31+day
END""" % (start_month, start_day) })
.extra(order_by=['order_me'])
.extra(where=['order_me < (12 + %s) * 31 + %s' % (end_month,
end_day)]))

Django Group By Weekday?

I'm using Django 1.5.1, Python 3.3.x, and can't use raw queries for this.
Is there a way to get a QuerySet grouped by weekday, for a QuerySet that uses a date __range filter? I'm trying to group results by weekday, for a query that ranges between any two dates (could be as much as a year apart). I know how to get rows that match a weekday, but that would require pounding the DB with 7 queries just to find out the data for each weekday.
I've been trying to figure this out for a couple hours by trying different tweaks with the __week_day filter, but nothing's working. Even Googling doesn't help, which makes me wonder if this is even possible. Any Django guru's here know how, if it is possible to do?
Since extra is deprecated, here is a new way of grouping on the day of the week using ExtractDayOfWeek.
from django.db.models.functions import ExtractWeekDay
YourObjects.objects
.annotate(weekday=ExtractWeekDay('timestamp'))
.values('weekday')
.annotate(count=Count('id'))
.values('weekday', 'count')
This will return a result like:
[{'weekday': 1, 'count': 534}, {'weekday': 2, 'count': 574},.......}
It is also important to note that 1 = Sunday and Saturday = 7
Well man I did an algorithm this one brings you all the records since the beginning of the week (Monday) until today
for example if you have a model like this in your app:
from django.db import models
class x(models.Model):
date = models.DateField()
from datetime import datetime
from myapp.models import x
start_date = datetime.date(datetime.now())
week = start_date.isocalendar()[1]
day_week =start_date.isoweekday()
days_quited = 0
less_days = day_week
while less_days != 1:
days_quited += 1
less_days -= 1
week_begin = datetime.date(datetime(start_date.year,start_date.month,start_date.day-days_quited))
records = x.objects.filter(date__range=(week_begin, datetime.date(datetime.now())))
And if you add some records in the admin with a range between June 17 (Monday) and June 22 (today) you will see all those records, and if you add more records with the date of tomorrow for example or with the date of the next Monday you will not see those records.
If you want the records of other week unntil now you only have to put this:
start_date = datetime.date(datetime(year, month, day))
records = x.objects.filter(date__range=(week_begin, datetime.date(datetime.now())))
Hope this helps! :D
You need to add an extra weekday field to the selection, then group by that in the sum or average aggregation. Note that this becomes a database specific query, because the 'extra' notation becomes passed through to the DB select statement.
Given the model:
class x(models.Model):
date = models.DateField()
value = models.FloatField()
Then, for mysql, with a mapping of the ODBC weekday to the python datetime weekday:
x.objects.extra(select={'weekday':"MOD(dayofweek(date)+5,7)"}).values('weekday').annotate(weekday_value=Avg('value'), weekday_value_std=StdDev('value'))
Note that if you do not need to convert the MySql ODBC weekday (1 = Sunday, 2 = Monday...) to python weekday (Monday is 0 and Sunday is 6), then you do not need to do the modulo.
For model like this:
class A(models.Model):
date = models.DateField()
value = models.FloatField()
You can use query:
weekday = {"w": """strftime('%%w', date)"""}
qs = A.objects.extra(select=weekday).values('w').annotate(stat = Sum("value")).order_by()

Calculate the total value of the Widgets sold each month for a particular year

If I have a Django Model that defines a Widget like this:
class Widget(models.Model):
type = models.CharField()
sold = models.DateTimeField()
price = models.DecimalField()
.
.
How would I go about getting the total value of the Widgets sold per month for a particular year?
I'd like to end up with a list of 12 monthly totals, for example:
[1225, 197, 131, 125, ...
This would indicate the total value of the Widgets sold in January was $1225, February $197 etc.
I expect this can be done with a Django Query, but not quite sure how.
UPDATE
I'd prefer not to use anything database specific to make changing databases easier. I don't mind if it's not all done in a single query. Doing a query, then some manipulation using Python after is fine.
UPDATE
I think I can slightly change some code from an answer to another question I raised to get this:
queryset = Widget.objects.filter(sold__year=year)
totals = [0] * 12
for widget in queryset:
totals[widget.sold.month - 1] += widget.price
return totals
Please let me know if I've missed something or if there's a better way of doing it.
based on this answer you could do.
Widget.objects.extra(select={'year': "EXTRACT(year FROM sold)", 'month': "EXTRACT(month from sold)"}).values('year', 'month').annotate(Sum('price'))
would give you something like
[{'price__sum': 1111, 'year': 2010L, 'month': 6L}...]
Edit - without using EXTRACT
probably not very efficient but...
for date in Widget.objects.all().dates('sold','month'):
values["%s_%s" % (date.year,date.month)] = Widget.objects.filter(sold__month=date.month,sold__year=date.year).aggregate(Sum('price'))
Similar approach, but probably not very efficient either
month_totals = []
for month in range(1, 13):
month_total = Widget.objects. \
filter(sold__gte=datetime.date(the_year, month, 1),
sold__lte=datetime.date(the_year, month, 31)). \
aggregate(month_total=Sum('price')).month_total
month_totals.append(month_total)

Categories