最佳实践:为每个用户创建一个新表是个好主意?

时间:2011-02-18 11:55:01

标签: django database-design

我正在编写一个小的django应用程序,以便对框架进行一些练习。该应用程序允许用户登录,写入条目并查看其条目列表。 我应该如何将条目分配给创建它们的用户?为每个新用户创建一个表并在那里保存条目是一个好主意,还是应该在条目模型中添加一个额外的字段(例如'created_by')并过滤要在列表中显示的项目?

需要考虑的一件事是,用户绝对不应该看到自己以外的条目(例如某些人使用应用程序写日记)。这是两种方式吗?

我以前更新用过数据库,所以我很感激为什么一种方法比另一种更好。

5 个答案:

答案 0 :(得分:8)

根据您的要求,为每个用户设置不同的数据库表会使事情变得更加困难,并且不值得权衡。作为一个示例:在“每个用户一个表”场景中,当您去检索用户的信息时,您必须弄清楚该用户的表的名称是什么。我甚至不确定你是怎么做的,因为关于用户的信息存储在表本身中。 (忽略会话存储。)

当您尝试将日记帐分录存储在自己的表中时,会出现更大的问题,并且您希望保持参照完整性。也就是说,您希望确保每个条目都属于实际存在的用户。对于每个用户来说,这几乎是不可能的。

很容易为用户使用一个表,为条目使用一个表,并将两个表连接起来,没有任何大的,有缺口的安全漏洞。你的“created_by”链接是要走的路。加载页面的视图功能可以轻松约束用户,因此他们只能看到自己的条目。这是一个观点:

@login_required
def my_entries(request):
    user = request.user
    entries = Entry.objects.filter(created_by=user)
    # return response here...

@login_required是一个装饰器,需要登录用户访问页面,而Entry模型上的.filter()调用只会加载由加载页面的用户创建的条目。

现在,此列表可能会链接到每个条目的“编辑”页面。每个页面的URL可能在URL中具有唯一标识符,通常是ID字段。因此,创建的第一个条目自动获得ID为1,下一个条目将获得ID为2,依此类推,因此标识每个条目的内容都是唯一的。所以URL可能看起来像'/ entry / 1 /','/ entry / 2 /'等。当页面加载时,它会检查URL中的ID。如果它为'1',则加载ID为'1'的条目供用户编辑。 (对不起,如果您已经知道该部分。)

但是,这意味着,一个更精明的用户可能会弄​​清楚URL是如何形成的,并开始加入自己的ID,作为侦察其他人的条目的手段。我可以开始输入带有随机ID值的URL,直到我找到一个加载:'/ entry / 8 /'。也许我不拥有ID为8的条目,但从理论上讲,如果设置正确,我可以加载它。

有一些非常简单的方法来阻止这一点。当您编写用于加载单个条目的视图时,不要只通过其ID加载Entry实例...按其ID加载它,并通过以下方式创建用户:

@login_required
def get_entry(request, entry_id):
    user = request.user
    entry = Entry.objects.get(id=entry_id, created_by=user)
    # return response here...

在上述情况下,如果我尝试为存在的条目加载此页面,但这不属于我,则会引发异常。 Django实际上有一个名为'get_object_or_404'的辅助方法可以帮助解决这个问题:

@login_required
def get_entry(request, entry_id):
    user = request.user
    entry = get_object_or_404(Entry, id=entry_id, created_by=user)
    # return response here...

现在,如果我尝试访问存在的Entry实例的页面,但不是我的,我只会看到Django提供的典型“找不到页面”错误,如果我试图访问一个页面不存在。

我知道您的问题是关于用户数据库表,但我希望这可以帮助您配置Django,以便您的用户不会读取/编辑彼此的数据。

答案 1 :(得分:3)

不,每个用户的表格与最佳做法完全相反。通过添加'created_by'列或类似列来规范化数据。

答案 2 :(得分:2)

为什么不为每个用户创建一个表? 绝对不建议每个用户创建一个db表。 你会如何为每个用户创建一个表?原始SQL语句?据我所知,你打破了Django的主要目的,它是ORM(对象关系映射器) - 它是SQL的简单接口,因为它不支持每个用户自动创建表/知道如何查询它。

当然,绝对要使用ForeignKey表到User表。 每个表都有一个主键字段,通常是一个数字。一个表可以通过该主键引用另一个表。

例如Entry 1 belongs to User ID 3

幸运的是,django抽象了SQL层,这是通过ForeignKey字段完成的。

http://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey


由于您是构建数据库查询的人,因此只显示特定用户编写的条目是非问题。您只需通过登录用户查询数据库中的条目。只要没有从程序外部输入原始SQL的漏洞,用户就无法访问其他数据。


要了解最佳实践/ ForeignKey /查询等,我建议在线学习本教程。我认为文档和教程是django最大的资产之一。

http://docs.djangoproject.com/en/dev/intro/tutorial01/

在第一个教程中,他们将介绍如何创建Poll应用,其中包含Choices模型,ForeignKeyPoll

您绝对可以将其应用于您的模型:)

答案 3 :(得分:1)

你必须在你的模型中有一个字段来保存用户ID。 (这意味着一张桌子。每人创建一张桌子不是个好主意。) 然后你必须申请一些权限,这样那个用户才能看到他写的东西,而其他人看不到他写的东西。

这些链接对于行级权限非常有用。

http://code.djangoproject.com/wiki/RowLevelPermissions

http://djangosnippets.org/snippets/1054/这是我用过的那个,非常有用。

http://code.djangoproject.com/wiki/RowLevelPermissionsDeveloper

答案 4 :(得分:1)

就像其他人所说的那样,即使尝试在django中为每个用户创建一个表也很困难。

通常在使用关系数据库时,如果每个用户尝试一个表,则只能尝试一次。 :)想象一下,如果你开始扩展到几百个用户,现在你需要获得所有条目的计数。你想为此做300个查询?也许是300 UNION ALL语句的大量查询?性能不仅会受到影响,而且您也会厌倦维护应用程序。

因为您没有多次使用数据库,所以您可能希望稍微阅读一下关系数据模型。你可以在它上面找到一本体面的书,Database Design For Mere Mortals或者在线教程,如:http://www.15seconds.com/issue/020522.htm。获得一些关于RDBMS设计的背景知识,然后回到django教程,这将是有意义的。