2013-03-06 44 views
2

我有一些複雜的業務邏輯,我放在一個自定義模型管理器中。管理器方法返回值的元組而不是查詢集。這被認爲是不好的做法?如果是的話,推薦的方法是什麼。我不想要View中的邏輯,而Django沒有服務層。另外,我的邏輯需要潛在地執行多個查詢。從Django Manager方法而不是查詢集返回元組是否是不好的做法?

邏輯需要選擇一個最接近當前時間的事件,再加上任何一方的3個事件。放置在模板中時,知道最接近的事件會很有幫助,因爲這是最初顯示在全屏滑塊中的事件。

當前呼叫如下:

closest_event, previous_events, next_events = Event.objects.closest() 

邏輯當前確實做工精細。我即將轉換我的應用程序。在模板中將事件數據呈現爲JSON,以便在頁面加載時引導backbone.js視圖。我打算使用TastyPie將資源服務器端渲染到模板中。在重構我的代碼之前,我很高興知道我目前的方法不被認爲是不好的做法。

這就是我的應用程序。當前工作:

views.py

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) 

models.py

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 < 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 < 0 else delta 
      if previous_delta and previous_delta <= 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 

回答

3

我不認爲這是不好的做法,返回一個元組。 ModelManager docs中的第一個示例返回一個列表。

這麼說,如果你想建立一個查詢集代替,那麼你可以做這樣的事情 -

def closest(self, **kwargs): 
    # get the events you want 
    return self.filter(pk__in=([event.id for event in events])) 
+0

有趣。我永遠不會想到這樣做。就我而言,我還需要再次order_by日期。自那以後,我改變了我的代碼來返回一個合併列表,但返回一個查詢集會更可取。 – Howie 2013-03-08 01:03:46

2

它的罰款,甚至Django自己get_or_create做的。只要確保它清楚誰使用函數,它是不可鏈接的(即不返回一個查詢集)。

+1

不錯的地方。那麼,那是非常明確的。與艾丹的答案只是因爲它提供了一個我沒有想到的選項。 – Howie 2013-03-08 01:03:21

相關問題