使用ForeignKey和ManyToMany的Django模型设计

时间:2014-01-15 22:31:58

标签: django django-models

我被困住了,需要对我的模型设计有一些新的认识。我似乎无法理解如何最好地设计它。

REQS:

  • 每个项目可以同时激活多个服务层,其他服务设置为关闭。没有互相排斥
  • 所有项目的层次相同。
  • 我需要跟踪特定项目中活动的层级。
  • 我需要能够将项目的收费日期与活动层相关联。请参阅下文,了解收费日期。
  • 项目和层级“活动”字段无关。
  • 有关我的要求的更多想法,请参阅编辑。

以下是模型:

class Project(models.Model):
    name = models.CharField('project name', max_length=128)
    company = models.ForeignKey('Company', related_name='projects')
    # A project could have more than one instance
    instances = models.ManyToManyField(Instance, related_name='projects') 
    type = models.CharField(max_length=128, blank=True)
    start_date = models.DateField(null=True, auto_now=False, auto_now_add=False)
    end_date = models.DateField(null=True, auto_now=False, auto_now_add=False)
    active = models.BooleanField()

class Tier(models.Model):
    TIERS = (('TI1', 'tier1'),
            ('TI2', 'tier2'),
            ('TI3', 'tier3'),
            ('TI4', 'tier4'),
            ('TI5', 'tier5'))

    name = models.CharField(max_length=3, choices=TIERS)
    active = models.BooleanField()

class TierHistory(models.Model):

    project = models.ForeignKey(Project, related_name='tier_history') 
    tiers = models.ManyToManyField(Tier)
    charge_date = models.DateField(null=True, auto_now=False, auto_now_add=True)
    contact = models.ForeignKey(Contact)

清理事项的编辑:

我遇到的问题是,鉴于目前的设计,我不觉得我正在跟踪层级,以及它们是否以最佳方式运行。这是所有这一切的主要目标;了解项目中哪些层是活动的,相反能够看到哪些项目曾经活跃过任何特定层。

鉴于我目前的设计,我不能在项目1上设置第2层活动而在项目2上设置不活动。

  • 项目可以同时激活多个层。
  • 收费日期将针对每一层。我意识到我读错了我的规格。
  • 我需要能够报告,“项目1已使用第1层3个月,第2层持续6个月且从未使用过第5层”
  • 我需要能够报告,“项目1和项目2现在有1级活动,项目1有4个活动1个月,项目3是目前使用5级的唯一项目”

2 个答案:

答案 0 :(得分:0)

我需要跟踪特定项目中哪些层级处于活动状态

为此,请将ManyToManyField添加到项目模型中。通过这样做,因为您一次只能选择一个选项,那么当您调用Project对象和该对象的层时,您将获得当前活动层:

class Project(models.Model):
  tier = models.ManyToManyField(Tier)
  # other fields in your Project Model

我需要能够将项目的收费日期与活动层相关联。

这需要是一个单独的事务表。所以你需要一个包含这些字段的表:

Charge Date, ProjectID (PK of your Project Model - unique identifier), Active Tier at the time.  

当收费发生时,写入此表以记录交易。

<强>更新

我建议然后将每个Tier设为布尔字段。这样他们就可以随意打开和关闭。并且您可以一次打开多个层。

要知道何时更改了哪个层,您可以将其放在事先建议的事务表中。在Project下创建一个类方法来为您处理此问题。或者只是查询数据库中的数据。

答案 1 :(得分:0)

根据您想问的问题,听起来您需要保留对给定层状态的所有更改的完整历史记录。有很多方法可以做到这一点,这是一个简单的方法。基本思想是,每次更改层的状态时,都会创建一个新的TierState

(请注意,这并未完全规范化,因为current隐含了change_time。它使查找更容易,状态更改稍微更难。)

class Project(models.Model):
    # as before

class TierState(models.Model):
    TIERS = (('TI1', 'tier1'),
             ('TI2', 'tier2'),
             ('TI3', 'tier3'),
             ('TI4', 'tier4'),
             ('TI5', 'tier5'))

    project = models.ForeignKey(Project, related_name='tiers') 
    name = models.CharField(max_length=3, choices=TIERS)
    active = models.BooleanField()
    change_time = models.DateTimeField(auto_now_add=True)
    current = models.BooleanField()

第1层是否在项目1上有效?

project1.tiers.filter(name='TI1', active=True, current=True).exists()

在项目2中将第3层设置为活动。

# For simplicity, assume a current state exists. Also, wrap this in a transaction.
current_t3 = project2.tiers.get(name='TI3', current=True)
current_t3.current = False
current_t3.save()
project2.tiers.create(name='TI3', active=True, current=True)

项目1是否曾使用过第5层?

project1.tiers.filter(name='TI5', active=True).exists()

项目2使用第4层的时间有多长?

# For simplicity we'll just assume it's active
datetime.now() - project2.tiers.get(name='TI4, current=True).change_time

目前有哪些项目使用第3层?

Project.objects.filter(tiers__name='TI3', tiers__active=True, tiers__current=True)