2011-12-29 107 views
0

這可能是一個設計問題。Django複雜查詢比較2型號

問題是「什麼是最好的方式來找到需要有登錄用戶發送反饋的優惠」。在反饋網站有3個選項卡:「發送」,「收到」,「發送反饋」。 「發送反饋」選項卡中有一個與「提議ID」,「用戶名(買家/發件人」和「發送反饋」鏈接指向的反饋形式的表格。

下面的代碼應該有助於理解我的意思。

商情顯示,直到一些用戶購買它。 要約被關閉,新訂單(存儲訂單詳細信息)實例此優惠創建。

我想實現一個反饋應用程序,這裏兩側報價交易可以 發送關於交易的反饋意見。

讓我們跳過「結束」或「運行」報價問題。

class Offer(models.Model): 
    """Offer is displayed for 5 days, then it's being ended by run everyday cron script. 
     If someone buys the offer end_time is being set, and offer is treated as ended. 
     Both sides of transaction may send feedback. 
    """  
    whose = models.ForeignKey(User, verbose_name="User who has created the offer") 
    end_time = models.DateTimeField(blank=True, null=True, help_text="") 
    field =() 
    fields2 =() 
    order = models.ForeignKey(Order, balnk=True, null=True, help_text="Order details") 

class Order(models.Model): 
    """stores order details like user, date, ip etc.""" 
    order_1_field_details =() 
    who = models.ForeignKey(User, verbose_name="User who bought the offer") 
    offer_id = models.PositiveIntegerField("know it's unnecessary") 
    offer_data = models.TextField('offer data dict here') 

class Feedback(models.Model): 
    offer_id = models.PositiveIntegerField() 
    sent_by = models.ForeignKey(User, verbose_name="Offer sender") 
    received_by = models.ForeignKey(User, verbose_name="Offer receiver") 

    def get_offer(self): 
     try: 
      Offer.objects.get(id=self.offer_id) 
     except Offer.DoesNotExist: 
      return None # offer moved to archive 

在第一稿有一個報價= models.ForeignKey(優惠),而不是offer_id領域, 但我會從發售表中的一些舊的報價移動到另一個用於歸檔。 即使我'歸檔'報價,我也希望反饋能夠繼續。在反饋列表中會有一個「優惠ID」鏈接,如果優惠超過60天,用戶在點擊「詳細信息」時會看到「已移動到存檔」

我現在所能想到的是獲取優惠「T過期,但有一個買家。

結束()是經理回來self.filter(end_date__isnull=False)

offers_with_buyer = models.Q(Offer.objects.ended().filter(whose__exact=request.user, order__isnull=False) | models.Q(Offer.objects.ended().filter(order__who__exact=request.user) 

我如何檢查是否有對這些提議的反饋? 我知道我應該回報用戶,並提供從上面的queryset id,並檢查它們是否存在Feedback.offer_id和Feedback.sent_by ..或者我應該改變mod埃爾設計完全...

回答

1

首先,你如何處理結束日期是非常人爲的。如果要約端面5,5日子裏創建之後,那麼就設置自動:

from datetime import datetime, timedelta 

class Offer(models.Model): 
    ... 
    def save(self, *args, **kwargs): 
     self.end_date = datetime.now() + timedelta(days=5) 

     super(Offer, self).save(*args, **kwargs) 

然後,只需修改ended經理,而不是返回:self.filter(end_date__lte=datetime.now())

不過,我一般喜歡其他方法添加到我的默認經理應對各種方式的數據:

class OfferQuerySet(models.query.QuerySet): 
    def live(self): 
     return self.filter(end_date__gt=datetime.now()) 

    def ended(self): 
     return self.filter(end_date__lte=datetime.now()) 

class OfferManager(models.Manager): 
    use_for_related_fields = True 

    def get_query_set(self): 
     return OffersQuerySet(self.model) 

    def live(self, *args, **kwargs): 
     return self.get_query_set().live(*args, **kwargs) 

    def ended(self, *args, **kwargs): 
     return self.get_query_set().ended(*args, **kwargs) 

(定義自定義QuerySet,然後使用上Manager方法,只是代理到QuerySet是Django的核心團隊做的方式,並允許您鏈的任何地方使用的方法,而不只是前面。)

至於「歸檔」你Offers去,這是非常不好的做法,將類似數據分成兩個不同的模型/表格。它會以指數方式增加應用中複雜度的順序。如果您想「歸檔」報價。添加一個字段,如:

is_archived = models.BooleanField(default=False) 

然後,您可以創建一個在您ManagerQuerySet子類的另一種方法來篩選後進行存檔或實時報價:

def live(self): 
    return self.filter(is_archived=False, end_date__gt=datetime.now()) 

def archived(self): 
    return self.filter(is_archived=True) 

如果你真的需要另一個模型(如對於管理中的一個單獨的視圖只是歸檔優惠),您可以創建一個代理模型:

class ArchivedOfferManager(models.Manager): 
    def get_query_set(self): 
     return super(ArchivedOfferManager, self).get_query_set().filter(is_archived=True) 

    def create(self, **kwargs): 
     kwargs['is_archived'] = True 
     return super(ArchivedOfferManager, self).create(**kwargs) 

class ArchivedOffer(models.Model) 
    class Meta: 
     proxy = True 

    objects = ArchivedOfferManager() 

    def save(self, *args, **kwargs): 
     self.is_archived = True 
     super(ArchivedOffer, self).save(*args, **kwargs) 
+0

表已經有400000+的報價。那麼不會緩存要約表很困難?我可以在創建新商品時自動設置end_date + 5天(通過自定義save()),但我如何緩存商品表?優惠將在午夜結束,因此我可以使用end_date作爲DateField()並在午夜運行緩存清除。使用end_date作爲DateTimeField() - 目前是不必要的 - 我沒有看到緩存選項,因爲每分鐘/秒提供查詢集都會改變。這就是爲什麼我選擇通過cron腳本來結束供應商的原因。也許is_archived是要走的路。謝謝! – Robert 2011-12-29 17:23:11