Django 多数据库使用中出现“无法适应类型”错误 (Postgresql 8.4 和 sqlite3)
简短描述
我在本地使用sqlite3数据库时,可以保存和提取信息,但在我的生产服务器上(另一台机器上的postgresql 8.4),Django却报了一个“无法适应类型”的错误。有没有人能帮我指点一下,应该从哪里开始调试这个问题?
背景
这个Python项目使用Django 1.3来处理多个数据库(生产和调试)。在所有情况下,多个数据库连接都能正常工作,只有这个例外。在搜索StackOverflow和谷歌时,发现大多数类似的错误通过重新运行syncdb解决了。我在我的生产和调试服务器上都做过这个操作,但仍然遇到同样的错误。查看模型、访问器和修改器后,我无法看出这个函数有什么不同。我已经包含了可疑的函数、我的模型和错误信息。任何帮助都将非常感激。如果需要其他非敏感信息,我很乐意提供。
系统信息
* Postgresql 8.4 - Ubuntu服务器
* Django项目(客户端/用户)- Windows XP(如图所示)、Mac OSX、Windows 7(64位)
* Python 2.7.1
* Psycopg2
* Django 1.3
Models.py
from django.db import models
# Create your models here.
class Card_Test(models.Model):
name = models.TextField(max_length=100)
description = models.TextField(max_length=200)
units = models.TextField(max_length=500)
result_tags = models.TextField(max_length=500)
def __unicode__(self):
return self.name
class Status_Type(models.Model):
status = models.CharField(max_length=25)
def __unicode__(self):
return self.status
class Card_Test_List(models.Model):
card_id = models.ForeignKey('Card')
card_test_id = models.ForeignKey('Card_Test')
card_test_sub_id = models.PositiveIntegerField()
status = models.ForeignKey('Status_Type')
result = models.TextField()
ran_on = models.DateField()
ran_by = models.CharField(max_length=50)
run_number = models.PositiveIntegerField()
def __unicode__(self):
return self.card_test_id.__unicode__()
class Card_Type(models.Model):
card_type = models.CharField(max_length=25)
def __unicode__(self):
return self.card_type
class Card(models.Model):
serial_number = models.CharField(max_length=25)
card_type = models.ForeignKey('Card_Type')
status = models.ForeignKey('Status_Type')
card_tests = models.ManyToManyField('Card_Test', through='Card_Test_List')
def __unicode__(self):
return self.serial_number
def print_all_cards(self):
print Card.objects.all()
class System_Test_Type(models.Model):
test_type = models.CharField(max_length=25)
def __unicode__(self):
return self.test_type
class System_Test(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=100)
units = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class System_Test_List(models.Model):
chassis_id = models.ForeignKey('Chassis')
system_test_id = models.ForeignKey('System_Test')
result = models.CharField(max_length=25)
ran_on = models.DateField()
ran_by = models.CharField(max_length=50)
test_type = models.ForeignKey('System_Test_Type')
def __unicode__(self):
return self.system_test_id.__unicode__()
class Chassis(models.Model):
serial_number = models.CharField(max_length=25)
slot_311 = models.ForeignKey(Card, related_name='slot1_card')
slot_175 = models.ForeignKey(Card, related_name='slot2_card')
slot_345 = models.ForeignKey(Card, related_name='slot3_card')
slot_346 = models.ForeignKey(Card, related_name='slot4_card')
slot_344 = models.ForeignKey(Card, related_name='slot5_card')
slot_178 = models.ForeignKey(Card, related_name='slot6_card')
backplane_serial = models.TextField(max_length=25)
site_location = models.TextField(max_length=25)
status_env_70c = models.ForeignKey('Status_Type', related_name='70C')
status_env_10c = models.ForeignKey('Status_Type', related_name='10C')
status_assembly = models.ForeignKey('Status_Type', related_name='assembly')
status_final = models.ForeignKey('Status_Type', related_name='final')
system_test = models.ManyToManyField(System_Test, through='System_Test_List')
def __unicode__(self):
return self.serial_number
Settings.py 摘录
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'production', # Or path to database file if using sqlite3.
'USER': 'tester', # Not used with sqlite3.
'PASSWORD': 'xxxxxx', # Not used with sqlite3.
'HOST': '10.10.100.30', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
},
'debug': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': curdir + '/mux_db',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
访问器 / 修改器
在调试和生产数据库上都能正常工作
def get_chassis_by_sn(chassis_id):
try:
return Chassis.objects.using(get_database()).filter(serial_number__iexact=chassis_id)
except Chassis.DoesNotExist:
return []
仅在调试数据库上能正常工作。请查看失败行的内联注释
def modify_chassis_sn(current, new):
#chassis = Chassis.objects.using(get_database()).filter(serial_number__iexact=current)
try:
chassis = Chassis.objects.using(get_database()).filter(serial_number__iexact=current)
except Chassis.DoesNotExist:
err.Handle_MUX_Error('Unknown Chassis / Serial Number')
return False
chassis = chassis[0] # <--- Fails here
# Update the serial number
chassis.serial_number = new
chassis.save(using=get_database())
return True
def modify_chassis_record(sn, slots=None, bp_sn=None, site_loc=None ):
#chassis = Chassis.objects.using(get_database()).filter(serial_number__iexact=sn)
try:
c = Chassis.objects.using(get_database()).filter(serial_number__iexact=sn)
print len(c)
except Chassis.DoesNotExist:
err.Handle_MUX_Error('Unknown Chassis / Serial Number')
return False
chassis = c[0] # <--- Fails here
# Update the List of Cards (if provided)
if slots != None:
if len(slots) != 6:
err.Handle_MUX_Error('You must enter 6 serial numbers!')
return False
index = 0
db_slots = [None]*6
for slot in slots:
s = get_card_by_sn(slot)
if len(s) == 0:
err.Handle_MUX_Error('Slot ' + str(index) + ' serial number does not exist!')
return False
db_slots[index] = s[0]
index +=1
chassis.slot_311 = db_slots[0]
chassis.slot_175 = db_slots[1]
chassis.slot_345 = db_slots[2]
chassis.slot_346 = db_slots[3]
chassis.slot_344 = db_slots[4]
chassis.slot_178 = db_slots[5]
# Update the Backplane Serial Number (if provided)
if bp_sn != None:
chassis.backplane_serial = bp_sn
# Update the site Location (if provided)
if site_loc != None:
chassis.site_location = site_loc
# Save all changes to the chassis
print chassis
chassis.save(using=get_database())
return True
错误信息
Traceback (most recent call last):
File "C:\Documents and Settings\User\Desktop\Python\exe\wx_gui\Assembly_Panel.py", line 276, in SaveChassis
mux_api.modify_chassis.run(active_chassis, new_chassis_id, bp_sn=backplane_sn)
File "C:\Documents and Settings\User\Desktop\Python\exe\api_rehabilitation_suite\modify_chassis.py", line 10, in run
modify_status = db.modify_chassis_record(sn, slots=slots, bp_sn=bp_sn, site_loc=site_loc )
File "C:\Documents and Settings\User\Desktop\Python\mux_test_data\db_driver.py", line 136, in modify_chassis_record
print len(c)
File "C:\Python27\lib\site-packages\django\db\models\query.py", line 82, in __len__
self._result_cache = list(self.iterator())
File "C:\Python27\lib\site-packages\django\db\models\query.py", line 273, in iterator
for row in compiler.results_iter():
File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py", line 680, in results_iter
for rows in self.execute_sql(MULTI):
File "C:\Python27\lib\site-packages\django\db\models\sql\compiler.py", line 735, in execute_sql
cursor.execute(sql, params)
File "C:\Python27\lib\site-packages\django\db\backends\util.py", line 34, in execute
return self.cursor.execute(sql, params)
File "C:\Python27\lib\site-packages\django\db\backends\postgresql_psycopg2\base.py", line 44, in execute
return self.cursor.execute(query, args)
django.db.utils.DatabaseError: can't adapt type 'Chassis'
1 个回答
6
原来在使用Django的过滤器时,sqlite3会忽略某些值,或者试图把这些值转换成字符串。我在图形界面中传入的是实际的底盘对象,而不是序列号。Postgresql在尝试把一个底盘对象当作序列号使用时会报错,而sqlite3则忽略了这个问题,把它当作字符串处理(我在Django中把它定义为序列号)。
我希望这个发现能帮助到其他人在调试类似错误时。
感谢所有关注这个问题的人。