3

In my Django project I need to calculate a date range for a trip to see if the trip is currently on its way.

class TourTemplate(models.Model):
    length = models.IntegerField()
    description = models.TextField(max_length=1000)
...

class Trip(models.Model):
    tourtemplate = models.ForeignKey(TourTemplate)
    start = models.DateField()
...

I added this to my Trip model:

def end(self):
    length = self.tourtemplate.length
    start = self.start
    a = start + timedelta(days=length)
    return a

In the shell it works and returns the end date for single objects. But how can I filter my queryset so that I only get objects between start and the calculated end date?

ncopiy
  • 1,515
  • 14
  • 30
yabd
  • 31
  • 2
  • 3
  • Have you tried anything to "filter my queryset so that I only get objects between start and the calculated end date?" you should show that Part, that is that art people can help with more-so – Gary Evans Jul 05 '16 at 20:43
  • I tried annotating the end dates: `Trip.objects.all().annotate(end=Trip.end())` This gives me "end() missing 1 required positional argument: 'self'" – yabd Jul 05 '16 at 21:10
  • You want to find objects within two *given* dates using the start date and calculated end date of the objects? – Moses Koledoye Jul 05 '16 at 21:42
  • 1
    Have a look at [this](http://stackoverflow.com/questions/4668619/django-database-query-how-to-filter-objects-by-date-range). should help – isstiaung Jul 05 '16 at 22:12

2 Answers2

2
# First, define a manager subclass
class TripManager(models.Manager):
    def get_queryset(self):
        length= self.tourtemplate.length
        start= self.start
        end=start+ timedelta(days=length)
        return super(TripManager, self).get_queryset().filter(date__range=[start, end])

class Trip(models.Model):

    objects = models.Manager() # The default manager.
    current_trip = TripManager() # New manager

Now, you can call:

Trip.current_trip.all()

Two take aways from this:

  1. Functions that you have defined inside your model, is callable only on the instance of that model (where the function resides).
  2. And because of point 1, custom model manager is required in your case. Read about them from this link. Your default manager is called by Model.objects.all() and if you want to change or modify the queryset that your defualt manager returns, defining a custom manager comes handy.

Try the above solution. Hope it helps :)

Shubhanshu
  • 975
  • 1
  • 8
  • 21
  • Thanks so much Shubhanshu, for the solution and the explanation. This looks exactly like what I was looking for :) Will try it out when I get home and report back. – yabd Jul 06 '16 at 08:34
  • Unfortunately calling `Trip.current_trip.all()` returns `AttributeError: 'TripManager' object has no attribute 'tourtemplate'`. In all examples I've seen, model managers are used only for filtering. Can we actually use it the way you described it? – yabd Jul 06 '16 at 22:02
  • Why don't you try inserting use_for_related_fields = True above get_queryset method in your custom manager. Have a look at this link: http://stackoverflow.com/questions/7489635/how-to-use-custom-manager-with-related-objects and this link: https://docs.djangoproject.com/en/dev/topics/db/managers/#manager-types – Shubhanshu Jul 07 '16 at 09:22
  • Where is date__range=[start, end] comming from?? – Soerendip Dec 10 '19 at 13:27
0

Couldn't figure out how to insert my calculated values into a queryset. My solution was adding another datefield for the end date (editable=False) and calculate and save the end date when creating a new trip:

# Calculate end date on save
def save(self, *args, **kwargs):
    self.end = self.start+ timedelta(days=self.tourtemplate.length)
    super(Trip, self).save(*args, **kwargs)
yabd
  • 31
  • 2
  • 3