我一直在尝试找出基于单独但相同的模型自动创建多个SQL表的最佳方法,所有这些都基于相同的基类。我基本上是创建具有不同组的伪留言板或墙,我希望每个组都有自己的Post_db_table,每个Post包含用户ID,时间戳等。
我的第一个想法是拥有一个基类的帖子,并且只包括一个用于组名的字段,但我认为这将是不好的做法。我的理由是,包含所有组的每个帖子的一个表会变得非常大(理论上无论如何)并且减慢过滤速度,并且从长远来看,组名的额外字段在我可以分开时会浪费内存每组表格并跳过此字段。
我也考虑过使用具有多对一关系的ForeignKey,但据我所知,这有着同样的缺点。我认为错了吗?或者这些尺寸问题不是真正的问题吗?
所以我的下一个想法是使Posts成为一个抽象类,然后根据每个Group创建子类。这最终是我所做的。但是,我发现自己不得不一遍又一遍地复制和粘贴代码,每次都要更改类名。这让我觉得非常不善。它类似于:
class Posts(models.Model):
timestamp = models.DateTimeField(auto_now_add=True, unique=False)
user_id = ...
#etc.
#
class Meta:
abstract = True
class GroupA(Posts):
class Meta(Posts.Meta):
db_table = 'groupa_board'
class GroupB(Posts):
class Meta(Posts.Meta):
db_table = 'groupb_board'
class GroupC...etc.
我真正想要的是为我这样做的工厂功能。我试过这种事:
def makeBoard(group):
class Board(Posts):
class Meta(Posts.Meta):
db_table = group
return board #note I tried with and without this line
然后我使用一个组列表运行一个简单的for循环。
for group in groups:
makeBoard(group)
我发现自己遇到了RuntimeError:应用程序中的冲突模型,我可能应该得到它。那么我认为我需要的是:
def makeBoard(group):
class group(Posts): #***group here being a variable, not the class name
class Meta(Posts.Meta):
db_table = '%s' % group #maybe issues here too, but the table
return group #name is not that important if the class
#name works
但我无法弄清楚如何使这项工作!有没有办法将列表中的变量传递给类名?
无论如何,如果你还在我身边,我很感激。我整天都在使用stackoverflow,虽然我已经找到了创建抽象基类和子类来解决类似问题的指南,但我没有看到为我创建函数的方法。我最终在这里进行了抨击,并且手动为每个组创建了一个子类。如果有办法自动化这个过程,我很乐意听到它。
另外,如果我因为不只是使用包含每个帖子的一个db表而感到愚蠢,我也想知道这一点,以及为什么!或者,如果有更好的方法来完全实现这种系统。如果之前已经回答过,我很抱歉,我真的找不到它。
谢谢!
答案 0 :(得分:2)
使用单个表不是不好的做法。在现代系统上,额外的内存是最小的,这应该不是问题。您也不应该担心性能,过早优化(不包括实际的系统设计)被认为是不好的做法,但如果遇到性能问题,您可以随时在group
列上指定索引:
group = models.CharField(max_length=100, db_index=True)
这并不是说它是最好的选择,或者说你的方法不好。此外,完全可以使用type()
内置函数动态创建模型。动态创建模型和创建其他类的唯一区别是您必须专门传递__module__
属性。您可以通过以下方式为Posts
创建子类:
def fabric(names, baseclass=Posts):
for name in names:
class Meta:
db_table = '%s_table' % name.lower()
attrs = {'__module__': baseclass.__module__, 'Meta': Meta}
# specify any other class attributes here. E.g. you can specify extra fields:
attrs.update({'my_field': models.CharField(max_length=100)})
newclass = type(str(name), (baseclass,), attrs)
globals()[name] = newclass
fabric(['GroupA', 'GroupB', 'GroupC', etc...])
在models.py
课程之后将该代码放入Posts
,并为您创建所有课程。它们可以以任何方式使用普通类:Django甚至不知道你动态创建了这个类。虽然您的Meta
课程不会继承Posts.Meta
,但您的元设置仍应保留。
使用Django 1.4进行测试。
答案 1 :(得分:0)
像这样尝试smth
import app.models as group_models
from django.db.models.base import ModelBase
def fabric(group):
for item in dir(group_models):
c = getattr(group_models, item)
if type(c) is ModelBase:
if c._meta.db_table == '%s_table' % group:
return c
return None