我有一个类似的Note模型(这是从传统的MS SQL Server数据库中提取的,因此大部分记录都不是由Django创建的):
class Note(models.Model):
id = models.AutoField(primary_key=True, db_column="note_id")
content = models.TextField(db_column="note_content", blank=True, null=True)
date_created = models.DateTimeField(db_column="date_created", auto_now_add=True)
date_modified = models.DateTimeField(db_column="date_modified", null=True, blank=True)
date_removed = models.DateTimeField(db_column="date_deleted", null=True, blank=True)
在某些记录上运行.get
,即使它们存在于数据库中,也会返回DoesNotExist
。
当MS SQL Server TEXT
(如,CREATE TABLE Foo ( content TEXT null)
)字段中的内容长度超过一定数量时,会发生这种情况;特别是19455个字符。
这是运作中的样子:
>>> note = Note.objects.get(pk=1)
>>> note.content = "x" * 19455
>>> note.save()
>>> note = Note.objects.get(pk=1)
>>> note.content = "x" * 19456
>>> note.save()
>>> note = Note.objects.get(pk=1)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/path/to/django/db/models/query.py", line 366, in get
% self.model._meta.object_name)
DoesNotExist: Note matching query does not exist.
我正在使用FreeTDS,文本大小设置为2147483647,其中出现是我正在使用的MS SQL Server版本的上限。
根据这个other question on truncation,你应该在前面加上SET TEXTSIZE n
指令,其中n是一个以字节为单位的值,这将解决数据被截断的问题。所以我想知道在我的情况下是否发生了这种情况,以及它是否会解决它。
所以,我继续编写了一些只使用游标和SET TEXTSIZE
命令的代码。
首先,我们来看看应该在记录中的内容:
print“长度:%d;最后40个字符:%s”%(len(note.content),note.content [-40:]) 长度:19456;最后40个字符:rVEF1cCJeRaTtcdkXMqqQUxEVLZapMGVGSxMfJ2T
现在我们循环了。每次我们增加TEXTSIZE设置并显示记录(如果有人喜欢)。我们还显示返回记录字段的长度和最后10个字符。
>>> for xx in xrange(19450, 19460):
... cursor = connection.cursor()
... try:
... qrys = 'SET TEXTSIZE %d SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1' % xx
... print qrys
... qry = cursor.execute(qrys)
... record = qry.fetchone()
... if record:
... record_id, record_content = record
... print record_id, len(record_content), record_content[-10:]
... else:
... print "No record found after TEXTSIZE set to %d" % xx
... break
... except Exception, inst:
... print "Error: %s (%s)" % (inst, type(inst))
... break
... finally:
... cursor.close()
...
SET TEXTSIZE 19450 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19450 VLZapMGVGS
SET TEXTSIZE 19451 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19451 LZapMGVGSx
SET TEXTSIZE 19452 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19452 ZapMGVGSxM
SET TEXTSIZE 19453 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19453 apMGVGSxMf
SET TEXTSIZE 19454 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19454 pMGVGSxMfJ
SET TEXTSIZE 19455 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
1 19455 MGVGSxMfJ2
SET TEXTSIZE 19456 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
No record found after TEXTSIZE set to 19456
>>>
因此,只要我们尝试检索TEXTSIZE设置为大于19456的数字的记录,就不会返回任何记录。而且你会注意到字符串的最后10个字符与减去上面的字符串匹配,因为它太短而错过了它们。例如,对于找到的最后一条记录,最后10个字符为MGVGSxMfJ2
。它缺少真实记录中的T
,因为19455的TEXTSIZE比所讨论的字段长度少一个。
所以现在我当然想知道,发生了什么?我是否可以做进一步的故障排除以确定这是django-pyodbc,pyodbc还是FreeTDS的问题?它可能也可能是SQL Server,但直接在Server Management Studio中运行SET TEXTSIZE 19456 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
似乎可以正常工作并返回正确数量的字符。
另请注意,保存有效:
>>> note.content = (note.content * 10)[:65536] # 65536 is max length allowed for TEXT, apparently
>>> len(note.content)
65536
>>> note.save()
>>> cursor = connection.cursor()
>>> qry = cursor.execute( 'SELECT [Notes].[note_id], DATALENGTH([Notes].[note_content]) FROM [Notes] WHERE [Notes].[note_id] = 1')
>>> record = qry.fetchone()
>>> record
(1, 65536)
>>>