Skip to main content
 首页 » 编程设计

python之为 Django 中的字段设置数据库级默认值

2025年05月04日29jillzhang

在 django 中使用什么方法设置数据库级默认值?

我知道这是一个 django wontfix 的决定,但是如果为特定的后端 (postgres) 编写的话,必须有一些关于实现它的方法的想法。

我想通过 python 来支持它,所以我不想使用 /sql/.sql 文件。

我想我可以在现有字段上设置属性,例如:

foo = models.CharField(max_length=256, blank=True) 
foo.db_default = '' 

然后过滤字段并构造一个ALTER COLUMN SET DEFAULT 查询。

不过我会把它放在哪里?文档说不要更改 post_syncdb Hook 中的数据库。

有什么想法可以把这个 Action 放在哪里吗?我也在想我可以动态生成 sql/.sql 文件。管理命令总比没有好。自动的会很棒。嗯,我想知道 post_syncdb 是否可以及时生成要执行的 sql 文件?将测试。

请您参考如下方法:

我尝试执行 post_syncdb 但为时已晚,无法使用 .sql 文件。连接到 class_prepared 及时为 syncdb 工作,但我意识到我把事情复杂化了。我还不如在模型实例化时运行一些代码。

我最终得到了一个直接的解决方案,当我需要再次摆弄它时,可以在 6 个月内轻松理解。

def db_default(field, db_default): 
    """ 
    Set attribute __db_default for signal to set default values with. 
    """ 
    field.__db_default = db_default 
    return field 
 
class OrderShipLog(models.Model): 
    date = db_default(models.DateTimeField(), 'now()') 
 
def generate_default_sql(model): 
    """ 
    Generate SQL for postgresql_psycopg2 default values because the shipping 
    database post doesn't guarantee posting certain fields but id like them all to be strings. 
    """ 
    db_fields = filter(lambda x: hasattr(x, '__db_default'), model._meta.fields) 
    db_table = model._meta.db_table 
    modelname = model._meta.object_name 
 
    sql_dir = os.path.join(os.path.dirname(__file__), 'sql/') 
    sql_filename = os.path.join(sql_dir, '{modelname}.postgresql_psycopg2.sql'.format( 
        modelname=modelname.lower())) 
 
    from django.db import connection 
    if not db_table in connection.introspection.table_names(): 
        print >> sys.stderr, "{0} not in introspected table list; creating db default sql file : {1}".format(db_table, sql_filename) 
        try: 
            if not os.path.exists(sql_dir): 
                os.makedirs(sql_dir) 
 
            with open(sql_filename, 'w+') as f: 
                for field in db_fields: 
                    attname, db_column = field.get_attname_column() 
                    if not field.__db_default: 
                        raise Exception("Must enter value for field {modelname}.{field}.__db_default".format( 
                            modelname=modelname, 
                            field=attname)) 
                    f.write('ALTER TABLE {db_table} ALTER COLUMN {db_column} SET DEFAULT {default};\n'.format( 
                        db_table=db_table, 
                        db_column=db_column, 
                        default=field.__db_default, 
                        )) 
        except Exception, e: 
            print >> sys.stderr, "Could not generate SQL file. Manually set the defaults! {0}\n".format(e) * 10 
 
generate_default_sql(OrderShipLog)