在 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)
