我有一个这样的 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
在某些记录上运行 a会返回 a 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 版本的上限。
根据this 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,但SET TEXTSIZE 19456 SELECT [Notes].[note_id], [Notes].[note_content] FROM [Notes] WHERE [Notes].[note_id] = 1
直接在 Server Management Studio 中运行似乎可以正常工作并返回正确数量的字符。
另请注意,保存工作:
>>> 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)
>>>