Note that there are some explanatory texts on larger screens.

plurals
  1. POIs it bad practice to return a tuple from a Django Manager method rather than a queryset?
    text
    copied!<p>I have some complex business logic that I have placed in a custom ModelManager. The manager method returns a tuple of values rather than a queryset. Is this considered bad practice? if so, what is the recommended approach. I do not want the logic in the View, and Django has no Service tier. Plus, my logic needs to potentially perform multiple queries.</p> <p>The logic needs to select an Event closest to the current time, plus 3 events either side. When placed in the template, it is helpful to know the closest event as this is the event initially displayed in a full-screen slider.</p> <p>The current call is as follows:</p> <pre><code>closest_event, previous_events, next_events = Event.objects.closest() </code></pre> <p>The logic does currently work fine. I am about to convert my app. to render the Event data as JSON in the template so that I can bootstrap a backbone.js View on page load. I plan to use TastyPie to render a Resource server-side into the template. Before I refactor my code, it would be good to know my current approach is not considered bad practice.</p> <p>This is how my app. currently works:</p> <p>views.py</p> <pre><code>class ClosestEventsListView(TemplateView): template_name = 'events/event_list.html' def get(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) closest_event, previous_events, next_events = Event.objects.closest() context['closest_event'] = closest_event context['previous_events'] = previous_events context['next_events'] = next_events return self.render_to_response(context) </code></pre> <p>models.py</p> <pre><code>from datetime import timedelta from django.db import models from django.utils import timezone from model_utils.models import TimeStampedModel class ClosestEventsManager(models.Manager): def closest(self, **kwargs): """ We are looking for the closest event to now plus the 3 events either side. First select by date range until we have a count of 7 or greater Initial range is 1 day eithee side, then widening by another day, if required Then compare delta for each event data and determine the closest Return closest event plus events either side """ now = timezone.now() range_in_days = 1 size = 0 while size &lt; 7: start_time = now + timedelta(days=-range_in_days) end_time = now + timedelta(days=range_in_days) events = self.filter(date__gte=start_time, date__lte=end_time, **kwargs).select_related() size = events.count() range_in_days += 1 previous_delta = None closest_event = None previous_events = None next_events = None position = 0 for event in events: delta = (event.date - now).total_seconds() delta = delta * -1 if delta &lt; 0 else delta if previous_delta and previous_delta &lt;= delta: # we have found the closest event. Now, based on # position get events either size next_events = events[:position-1] previous_events = events[position:] break previous_delta = delta closest_event = event position += 1 return closest_event, previous_events, next_events class Event(TimeStampedModel): class Meta: ordering = ['-date'] topic = models.ForeignKey(Topic) event_type = models.ForeignKey(EventType) title = models.CharField(max_length=100) slug = models.SlugField() date = models.DateTimeField(db_index=True) end_time = models.TimeField() location = models.ForeignKey(Location) twitter_hashtag = models.CharField(null=True, blank=True, max_length=100) web_link = models.URLField(null=True, blank=True) objects = ClosestEventsManager() def __unicode__(self): return self.title </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload