【问题标题】:Django model for variable type of data用于可变数据类型的 Django 模型
【发布时间】:2014-07-29 06:05:58
【问题描述】:

我想做的是一个数据库来跟踪个人记录。 模型快完成了,但我在存储不同类型的记录时遇到了一些困难。

有时间记录、重量记录、重复/圈数记录、距离记录……所以,数据有不同类型:时间、小数、整数……

起初我为每种类型的数据创建了一个表(或 django 中的类)。一个表到时间,其他到重量(十进制)等等。

但我想知道是否有更好的解决方案来只为所有记录保留一张表。

我的分隔表/模型的代码(因此,我为每种类型设置一个类,总共 5 个模型):(这很好,但我必须预先选择适当的模型才能插入数据。)

class PRWeight(model.Models):  # there are PRDistance, PRLaps, PRHeight, PRTime
    user = FK(User)
    exercise = FK(Exercise)
    date = datefield()
    weight = decimalfield()  # integer, integer, decimal, time

    class Meta:
        unique_together = [user, exercise, date,]

或者我可以做这样的事情,如果它很好或者有更好的解决方案:

class PR(models.Model):
    user = FK(User)
    exercise = FK(Exercise)
    date = datefield()
    metric = FK(Metric)  # choose between time, weight, height...
                         # the aspect beeing mesured
    record =             # how can I call the right field type?

或者我可以用空白=True 替换其他五个字段的“记录”字段

class PR(models.Model):
    user = FK(User)
    exercise = FK(Exercise)
    date = datefield()
    metric = FK(Metric)  # choose between time, weight, height, distance...
                         # the aspect beeing mesured
                         # not necessary in this approach
    wheight = decimalfield(blank=True)
    height = decimalfield(blank=True)
    time = timefield(blank=True)
    distance = integerfield(blank=True)
    laps = integerfield(blank=True)

我正在寻找一个简单的解决方案。到目前为止,我倾向于选择最后一个示例,因为它是直截了当的,但是填写表单的用户可能会犯错误...

【问题讨论】:

  • 创建一个包含所有相似数据的抽象模型,然后将每个模型的特定数据分开。您可以使用抽象模型或表继承,这取决于您的应用程序逻辑来定义最佳方式。
  • 我不认为您应该担心表,除非您直接在数据库中工作。 Django 有一个非常好的 ORM,ORM 的主要方面是您不必查看数据库及其存储方式。只需创建一个漂亮的类层次结构来访问您的所有项目和模型,并让 ORM 决定它需要多少表来保存它们。

标签: python database django database-design model


【解决方案1】:

表包含使某些语句(由列名参数化)为真的行。一个表应该只包含列,只要您可以使用它们创建一个语句即可。

将许多但相关的列放在一起

如果 (user,exercise,date) 总是有体重和日期,则有一个表。

-- user [user] in exercise [exercise] on [date] weighed [weight] kg and was [height] m tall
PRstuff(user,exercise,date,weight,height)

但如果(用户、锻炼、日期)可能有重量但没有日期,则有单独的表格。

-- user [user] in exercise [exercise] on [date] lifted [weight] kg
PRlift(user,exercise,date,weight)
-- User [user] in exercise [exercise] on [date] jumped [height] m
PRjump(user,exercise,date,height)

条件列很复杂

可以有一个像你的第三个例子一样的语句/表:

--     user [user] did [exercise] on [date]
-- AND ( lifted != blank and they lifted [weight] kg OR lifted = blank and they didn't lift )
-- AND ( jumped != blank and they jumped [height] m OR jumped = blank and they didn't jump )
PR(user,exercise,date,weight,height)

但是您可以看到,作为表语句组合的查询语句和作为表组合的 SQL 表达式变得复杂。基本上,在查询时,无论如何您都必须不断地将这个表切割成单独的非条件表版本。

不要使用记录类型的列

有时我们可以有一个类型由固定部分组成的列。但是,如果您想使用 SQL 等逻辑条件查询零件,那么您应该将零件放入表格的列中。

-- user [user] in exercise [exercise] on [date] weighed [record.weight] kg and was [record.height] m tall
PRrecord(user,exercise,date,record)

SELECT * FROM PRrecord
WHERE PRrecord.record.weight = 100 -- really, record_dot(PRrecord.record,'weight')=100

这里第一个点是数据库表操作,第二个点是编程语言记录操作。 DBMS 无法优化您的查询,因为它优化的是表操作,而不是数据类型操作。基本上它必须得到一大堆不查看记录值的行然后调用记录运算符点然后调用字段相等然后丢弃很多行。

SELECT * FROM PR
WHERE PR.weight = 100

现在 DBMS 可以将字段相等性结合到优化获取行的方式中,因为您只使用了表版本的 dot。

不要使用容器类型的列

有时我们可以有一个列,其类型由相似部分的集合组成。但是,如果您想使用 SQL 中的逻辑条件查询这些部分,那么您应该创建一个新表。新表具有该特定集合的 PK 列,而旧表具有新 PK 的 FK 列。

-- user [user] in exercise [exercise] on [date] and their set of lifted weights in kg is [weights]
PRlifts(user,exercise,date,weights)

SELECT user FROM PRlifts l
WHERE l.name = 'Fred' AND set_has_member(l.weights,200)
AND ??? no two lifts were the same weight ???

不好。注意语句是多么复杂。 DBMS 也无法优化查询,因为 set_has_member 不是表操作。更糟糕的是你甚至不能查询某些条件,你必须编写非查询循环代码。

SELECT user FROM PRlift l
WHERE l.user = 'Fred' AND l.weight = 200
AND NOT EXISTS(
    SELECT weight
    FROM Prlift l1, PRlift l2
    WHERE l1.user = l.user AND l2.user = l.user AND l1.weight = l2.weight
)

现在 DBMS 可以优化并避免循环。

(请注意,如果这是

WHERE string_length(l1.name) = string_length(l2.name)

然后 DBMS 可以通过名称长度列进一步优化。但是通常 DBMS 对字符串和某些其他类型有特殊的了解,并且或多或少地进行优化,就好像某些列存在对应于某些运算符的值一样。事实上,DBMS 可以知道记录和集合类型,但你仍然不能有简单的语句和无循环的查询。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-27
    • 2018-04-09
    • 2023-04-05
    • 2012-04-05
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多