#model
class Promotion(models.Model):
name = models.CharField(max_length=200)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
#view
def promo_search(request):
...
results = Promotion.objects.filter(start_date__gte=start_date).filter(end_date__lte=end_date)
...
(The code above obviously isn't going to work I'm just using it to
help illustrate my problem.)
I want to show all active promotions between the start date and end
date.
So if a promotion starts on 01/01/09 and ends 30/01/09 and a person
searches from 01/12/08 to 01/02/09 it will still return a result. Also
if they search from inside the date range e.g. 02/01/09 - 03/01/09
they would get the same result.
Is there some magical django way of achieving this without looping
over each day?
You have four dates to consider: start_search, end_search, start_promo and end_promo. You are looking for promotions where start_promo <= end_search and end_promo >= start_search:
results = Promotion.objects.\
filter(start_date__lte=end_date).\
filter(end_date__gte=start_date)
Related
I have 2 models-
class POWStage(Content):
time_slot = models.OneToOneField(
TaskTime,
on_delete=models.CASCADE,
help_text='Link to time slot describing the stage timescale',
verbose_name='Time slot link',
null=True,
blank=True
class TaskTime(Content):
schedule_finish = models.DateTimeField(
help_text='Scheduled finish date',
verbose_name='Scheduled finish',
blank=True,
null=True,
I would like to get the latest end date for a list of POwStages.... e.g. If I have 8 POWStages will have 8 corresponding schedule finish dates.
I have tried the following with no success:
pow_stage_list = POWStage.objects.get_stage_by_pow(pow_detail)
task_time_list = TaskTime.objects.get_task_time_by_id(getattr(pow_stage_list,'time_slot'))
and also:
time_list = []
time_slot=[]
time_finish[]
for time_slot in pow_stage_list:
time_list.append(time_slot)
for entry in time_list:
time_entry.append(entry.id)
for finish_date in time_entry:
time_finish.append(TaskTime.objects.get_task_time_by_id(finish_date))
to try and at least get the values of the finish dates in order to process them further (neither of which are working)
Im thinking of getting the
POWStages - using a filter - no problems
2)FOr each of the POWStages - loop through them to get the id of TaskTime
I can do this ok -ish ( I manage to get the id which is returned as
UUID() object. which I
cannot then pass to get the TaskTime
For each of the TaskTime get the value of schedule finish
Iterate through the values to find the latest finish date.
Im thinking there must be a simpler way that I'm missing or at least something that works!!!
2 mins after posting - I managed to work it out:
pow_stage_list = POWStage.objects.get_stage_by_pow(pow_detail)
time_list = TaskTime.objects.filter(powstage__in=pow_stage_list, schedule_finish__isnull=False).latest('schedule_finish')
I am making a scheduler in Django and having issues filtering my events for the weekly calendar view. The calendar supports multi-day events, and my current filter doesn't work with this weekly view.
Here is my model:
class Event(models.Model):
title = models.CharField(max_length=40)
start = models.DateTimeField()
end = models.DateTimeField()
description = models.TextField()
all_day = models.BooleanField(default=False)
recuring = models.BooleanField(default=False)
recuring_end = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return '/cab/event/%i/' % self.id
and I'm trying to filter the events that occur during a given week. For single day events I do something like.
events = Event.objects.order_by('start').filter(Q(start__gte=monday) | Q(end__lte=sunday))
This works to retrieve all single day events that occur during the week. It also works for multi-day events that either start or stop during the given week. The issue is retrieving objects that start before and finish after the week, but do span the week.
My idea is to try and filter out any event spanning longer than 9 days (ie. would start Sunday of prior week and finish Monday of next week) since I know these are rare and wont completely destroy performance. I want to do this without specifying a date range as this is not dynamic.
To try and minimise the performance impact I was trying to use F expressions to evaluate the duration of the event with the start and end of the event. My first idea was to do something like:
my_events = Event.objects.order_by('start').filter(Q(start__gte=monday) | Q(end__lte=sunday) | Q( (F('end_day') - F('start_day')) >= 9 ) )
but I get error 'bool' object is not iterable
also tried:
my_events = Event.objects.order_by('start').filter(Q(start__gte=monday) | Q(end__lte=sunday) | Q( (F('end_day') - F('start_day')) >= datetime.timedelta(days=9) ) )
but get can't compare datetime.timedelta to ExpressionNode
Anyone have incite as how to do such a thing?
from datetime import timedelta
Event.objects.filter(end__gt=F('start') + timedelta(days=9))
Documentation has example.
UPDATE:
Events, that span more than 9 days AND (start later than Monday OR end sooner than Sunday), ordered by start.
(Event.objects
.filter(end__gt=F('start') + timedelta(days=9),
Q(start__gte=monday) | Q(end__lte=sunday))
.order_by('start'))
Just the warning to #https://stackoverflow.com/users/4907653/f43d65
's answer, that last query lookups with Q objects might be invalid.
Reference to docs
Lookup functions can mix the use of Q objects and keyword arguments. All arguments provided to a lookup function (be they keyword arguments or Q objects) are “AND”ed together. However, if a Q object is provided, it must precede the definition of any keyword arguments. For example:
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who',)
… would be a valid query, equivalent to the previous example; but:
# INVALID QUERY
Poll.objects.get(
question__startswith='Who',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
… would not be valid.
In a Django application I need to create an order number which looks like: yyyymmddnnnn in which yyyy=year, mm=month, dd=day and nnnn is a number between 1 and 9999.
I thought I could use a PostgreSQL sequence since the generated numbers are atomic, so I can be sure when the process gets a number that number is unique.
So I created a PostgreSQL sequence:
CREATE SEQUENCE order_number_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9999
START 1
CACHE 1
CYCLE;
This sequence can be accessed as a tables having one row. So in the file checkout.py I created a Django model to access this sequence.
class OrderNumberSeq(models.Model):
"""
This class maps to OrderNumberSeq which is a PostgreSQL sequence.
This sequence runs from 1 to 9999 after which it restarts (cycles) at 1.
A sequence is basically a special single row table.
"""
sequence_name = models.CharField(max_length=128, primary_key=True)
last_value = models.IntegerField()
increment_by = models.IntegerField()
max_value = models.IntegerField()
min_value = models.IntegerField()
cache_value = models.IntegerField()
log_cnt = models.IntegerField()
is_cycled = models.BooleanField()
is_called = models.BooleanField()
class Meta:
db_table = u'order_number_seq'
I set the sequence_name as primary key as Django insists on having a primary key in a table.
The I created a file get_order_number.py with the contents:
def get_new_order_number():
order_number = OrderNumberSeq.objects.raw("select sequence_name, nextval('order_number_seq') from order_number_seq")[0]
today = datetime.date.today()
year = u'%4s' % today.year
month = u'%02i' % today.month
day = u'%02i' % today.day
new_number = u'%04i' % order_number.nextval
return year+month+day+new_number
now when I call 'get_new_order_number()' from the django interactive shell it behaves as expected.
>>> checkout.order_number.get_new_order_number()
u'201007310047'
>>> checkout.order_number.get_new_order_number()
u'201007310048'
>>> checkout.order_number.get_new_order_number()
u'201007310049'
You see the numbers nicely incrementing by one every time the function is called. You can start multiple interactive django sessions and the numbers increment nicely with no identical numbers appearing in the different sessions.
Now I try to use call this function from a view as follows:
import get_order_number
order_number = get_order_number.get_new_order_number()
and it gives me a number. However next time I access the view, it increments the number by 2. I have no idea where the problem is.
The best solution I can come up with is: don't worry if your order numbers are sparse. It should not matter if an order number is missing: there is no way to ensure that order numbers are contiguous that will not be subject to a race condition at some point.
Your biggest problem is likely to be convincing the pointy-haired ones that having 'missing' order numbers is not a problem.
For more details, see the Psuedo-Key Neat Freak entry in SQL Antipatterns. (note, this is a link to a book, which the full text of is not available for free).
Take a look at this question/answer Custom auto-increment field in postgresql (Invoice/Order No.)
You can create stored procedures using RawSql migration.
I have a report model looking a bit like this:
class Report(models.Model):
date = models.DateField()
quantity = models.IntegerField()
product_name = models.TextField()
I know I can get the last entry for the last year for one product this way:
Report.objects.filter(date__year=2009, product_name="corn").order_by("-date")[0]
I know I can group entries by name this way:
Report.objects.values("product_name")
But how can I get the quantity for the last entry for each product ? I feel like I would do it this way in SQL (not sure, my SQL is rusty):
SELECT product_name, quantity FROM report WHERE YEAR(date) == 2009 GROUP_BY product_name HAVING date == Max(date)
My guess is to use the Max() object with annotate, but I have no idea how to.
For now, I do it by manually adding the last item of each query for each product_name I cant list with a distinct.
Not exactly a trivial query using either the Django ORM or SQL. My first take on it would be to pretty much what you are probably already doing; get the distinct product and date pairs and then perform individual queries for each of those.
year_products = Product.objects.filter(year=2009)
product_date_pairs = year_products.values('product').distinct('product'
).annotate(Max('date'))
[Report.objects.get(product=p['product'], date=p['date__max'])
for p in product_date_pairs]
But you can take it a step further with the Q operator and some fancy OR'ing to trim your query count down to 2 instead of N + 1.
import operator
qs = [Q(product=p['product'], date=p['date__max']) for p in product_date_pairs]
ored_qs = reduce(operator.or_, qs)
Report.objects.filter(ored_qs)
I need to create a cross-site template object which will check the current time and return either one string if it's within a time range specified in a model or another or blank in all other cases.
Seems simple, but I wonder what is the best approach here? Also, there are a few other considerations:
the string should be editable
the display time should not have an end time before the start time
we need to allow for multiple strings to be stored, but only one (or none) to be selected as 'live'
As a starting point, I'd use a model to define the string as well as the start and end time, like this:
from datetime import datetime
class dynamicString(models.Model):
start = models.TimeField()
end = models.TimeField()
name = models.CharField(max_length=50, help_text = 'Just for reference, won\'t be displayed on site.')
number = models.CharField(max_length=18, help_text = 'This is the string to be displayed within the above timeframe.')
active = models.BooleanField(help_text = 'Uncheck this to stop string from displaying entierly.')
def __unicode__(self):
return self.name
But where next to incorporate the logic rules?
Redesigned this using a simpler rule system: check for one number time range, if within range and if not blank, return the number, otherwise return a backup number (which may be blank).
Works a treat passed as a context process.