Django使用工厂函数从相同的基类创建多个表/模型类

时间:2014-05-04 18:40:03

标签: python mysql sql django

我一直在尝试找出基于单独但相同的模型自动创建多个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表而感到愚蠢,我也想知道这一点,以及为什么!或者,如果有更好的方法来完全实现这种系统。如果之前已经回答过,我很抱歉,我真的找不到它。

谢谢!

2 个答案:

答案 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