2011-12-29 65 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