虽然已经很老了,已回答并接受了问题,但我补充了我的理解,我添加了它,因为我没有使用自定义类型,它是 Django Evolution 错误(但不是 syncdb)evolve --hint --execute
。我认为这可能对将来的某人有所帮助。.
我的 Python 水平一般,对 Django 很陌生。当我向现有项目添加一些新功能时,我也遇到了同样的问题。要添加新功能,我必须添加一些新的models.CharField()
类型字段,如下所示。
included_domains = models.CharField(
"set of comma(,) seprated list of domains in target emails",
default="",
max_length=it_len.EMAIL_LEN*5)
excluded_domains = models.CharField(
"set of comma(,) seprated list of domains NOT in target emails",
default="",
max_length=it_len.EMAIL_LEN*5)
我使用的 Django 版本是 1.3.1:
$ python -c "import django; print django.get_version()"
1.3.1 <--------# version
$python manage.py syncdb
Project signature has changed - an evolution is required
Django Evolution: Django Evolution 是 Django 的扩展,它允许您跟踪模型随时间的变化,并更新数据库以反映这些变化。
$ python manage.py evolve --hint
#----- Evolution for messagingframework
from django_evolution.mutations import AddField
from django.db import models
MUTATIONS = [
AddField('MessageConfiguration', 'excluded_domains', models.CharField, initial=u'', max_length=300),
AddField('MessageConfiguration', 'included_domains', models.CharField, initial=u'', max_length=300)
]
#----------------------
Trial evolution successful.
Run './manage.py evolve --hint --execute' to apply evolution.
试验很混乱,当我尝试在 DB 中应用更改时
$ python manage.py evolve --hint --execute
Traceback (most recent call last):
File "manage.py", line 25, in <module>
execute_manager(settings)
File "/var/www/sites/www.taxspanner.com/django/core/management/__init__.py", line 362, in execute_manager
utility.execute()
File "/var/www/sites/www.taxspanner.com/django/core/management/__init__.py", line 303, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/var/www/sites/www.taxspanner.com/django/core/management/base.py", line 195, in run_from_argv
self.execute(*args, **options.__dict__)
File "/var/www/sites/www.taxspanner.com/django/core/management/base.py", line 222, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python2.7/dist-packages/django_evolution-0.6.9.dev_r225-py2.7.egg/django_evolution/management/commands/evolve.py", line 60, in handle
self.evolve(*app_labels, **options)
File "/usr/local/lib/python2.7/dist-packages/django_evolution-0.6.9.dev_r225-py2.7.egg/django_evolution/management/commands/evolve.py", line 140, in evolve
database))
File "/usr/local/lib/python2.7/dist-packages/django_evolution-0.6.9.dev_r225-py2.7.egg/django_evolution/mutations.py", line 426, in mutate
return self.add_column(app_label, proj_sig, database)
File "/usr/local/lib/python2.7/dist-packages/django_evolution-0.6.9.dev_r225-py2.7.egg/django_evolution/mutations.py", line 438, in add_column
sql_statements = evolver.add_column(model, field, self.initial)
File "/usr/local/lib/python2.7/dist-packages/django_evolution-0.6.9.dev_r225-py2.7.egg/django_evolution/db/common.py", line 142, in add_column
f.db_type(connection=self.connection), # <=== here f is field class object
TypeError: db_type() got an unexpected keyword argument 'connection'
为了理解这个异常,我检查了这个异常是否类似于:
>>> def f(a):
... print a
...
>>> f('b', b='a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() got an unexpected keyword argument 'b'
>>>
所以函数签名已经改变。
因为我没有添加任何新的自定义或枚举字段,但大多数数据库(我正在使用 PostgreSQL)只支持模型和字符类型字段中已经存在的两个类似字段,即使我收到了这个错误!
然后我从@阅读:Russell Keith-Magee-4 回复。
您在这里遇到的是不支持多个数据库的代码的弃用周期的结束。
在 Django 1.2 中,我们引入了多数据库支持;为了支持这一点,对原型进行了get_db_preb_lookup()
更改
get_db_prep_value()
。
为了向后兼容,我们添加了一个 shim,如果开发人员尚未修复这些方法,它将透明地“修复”这些方法。
在 Django 1.2 中,这些 shim 的使用引发了 PendingDeprecationWarning。在 Django 1.3 中,他们提出了 DeprecationWarning。
在 Django 1.4 下,shim 代码已被删除——因此任何未更新的代码现在都会引发与您描述的错误类似的错误。
但是由于 Django Evolution 的较新版本,我没有收到任何 DeprecationWarning 警告。
但是从上面的引用中我可以理解,为了支持多个数据库,添加了函数签名,并且需要一个额外的参数connection
。我还检查了db_type()
我安装的 Django 中的签名,如下所示:
/django$ grep --exclude-dir=".svn" -n 'def db_type(' * -R
contrib/localflavor/us/models.py:8: def db_type(self):
contrib/localflavor/us/models.py:24: def db_type(self):
:
:
我也参考了 Django 文档
返回Field 的数据库列数据类型,同时考虑到连接对象以及与之关联的设置。
然后我可以理解,要解决这个问题,我必须继承models.filed
类并覆盖def db_type()
函数。而且因为我使用PostgreSQL 在其中创建 300 个字符类型的字段,所以我需要返回'char(300)'
. 在我的 models.py 中,我添加了:
class CharMaxlengthN(models.Field):
def db_type(self, connection):
return 'char(%d)' % self.max_length # because I am using postgresql
如果您遇到类似的问题,请查看您的下划线数据库手册,了解您需要创建哪种类型的列并返回一个字符串。
并更改了新字段的定义(我需要添加)阅读评论:
included_domains = CharMaxlengthN( # <--Notice change
"set of comma(,) seprated list of domains in target emails",
default="",
max_length=it_len.EMAIL_LEN*5)
excluded_domains = CharMaxlengthN( # <-- Notice change
"set of comma(,) seprated list of domains NOT in target emails",
default="",
max_length=it_len.EMAIL_LEN*5)
然后我执行了之前失败的相同命令:
t$ python manage.py evolve --hint --execute
You have requested a database evolution. This will alter tables
and data currently in the None database, and may result in
IRREVERSABLE DATA LOSS. Evolutions should be *thoroughly* reviewed
prior to execution.
Are you sure you want to execute the evolutions?
Type 'yes' to continue, or 'no' to cancel: yes
Evolution successful.
我还检查了我的数据库并测试了我的新增功能它现在运行良好,没有数据库问题。
如果要创建 ENUM 字段,请阅读Specifying a mySQL ENUM in a Django model
.
编辑:我意识到models.Field
我应该继承更具体的子类而不是子类,即models.CharField
.
同样,我需要创建十进制数据库字段,所以我在模型中添加了以下类:
class DecimalField(models.DecimalField):
def db_type(self, connection):
d = {
'max_digits': self.max_digits,
'decimal_places': self.decimal_places,
}
return 'numeric(%(max_digits)s, %(decimal_places)s)' % d