Skip to main content
 首页 » 编程设计

Python:无法识别 Django 模型中的更改

2025年05月04日36luoye11

这一定很简单,但我无法理解它。 我想为 Django 模型实例分配一个简单的单字符值。我已经这样做了一百万次,但在这种情况下,它不起作用。

我的模型.py

class MetaInformation(models.Model): 
    # part of the class profile ... 
    PROFILE_STATUS = ( 
        ('C', 'Claimed'), 
        ('U', 'Unclaimed'),) 
    status = models.CharField(_('Profile'), max_length=1, 
        choices = PROFILE_STATUS,) 
 
class Profile(MetaInformation): 
    # additional attributes 
    ... 

现在我在 Django shell 中执行:

In [1]: a = Profile.objects.all() 
In [2]: a[1].status 
Out[2]: u'U' 
In [3]: a[1].status = Profile.PROFILE_STATUS[0] # equal to 'C' 
In [4]: a[1].save() 

我希望结果是

In [14]: a[1].status 
Out[14]: u'C' 

但是 Django 返回了

In [14]: a[1].status 
Out[14]: u'U' 

为什么无法识别属性的保存或提供任何错误消息?

请您参考如下方法:

我相信 Bibhas 的大部分答案都是正确的。事实上,您总是通过 QuerySet 引用数据,Profile.objects.all() 是其中最大的部分。再加上 Django 处理切片的方式(如列表索引,但 QuerySet 并不是真正的列表),以及数据库不必考虑有序记录的事实,你就有了困惑和沮丧的极好来源。

顺序

a = Profile.objects.all() 
a[1].status 

将产生类似这样的SQL:

SELECT * FROM user_profile LIMIT 1 OFFSET 1; 

为了从表中获取单个值。这里有几件重要的事情:

  1. 只获取了一条记录。这样做是为了提高效率,因为您只请求了一条记录,所以没有必要再检索了。这也意味着
  2. Django 不会填充 QuerySet 的缓存。这意味着下次您请求 a[1] 时,它将再次访问数据库。
  3. 此查询没有指定顺序。数据库可以自由地以最有效的顺序返回行,并且该顺序甚至可以在查询之间更改。

我知道 MySQL 通常会按照最近更新的顺序返回记录。因此,仅通过保存记录,它就不太可能处于与以前相同的位置。它可能会移动到结果集的开头或结尾,但不太可能保持在位置 1(返回的第二项)。

为避免这种情况,请不要将查询集视为列表。不要直接对使用切片语法检索到的项目执行操作。如果您需要这样做,则将它们存储在一个临时变量中,然后对该变量执行所有操作。

这个小修改可以避免所有的麻烦:

>>> a = Profile.objects.all() 
>>> b = a[1] 
>>> b.status 
'U' 
>>> b.status = 'C' 
>>> b.save() 
>>> b.status 
'C' 

或者,如果您需要将其视为列表,则将其设为一个。从 QuerySet 中创建一个列表将对其进行完整的计算,并将整个结果集存储在内存中,其中 a[1] 保证在您每次请求它时都是相同的对象。

>>> a = list(Profile.objects.all()) # Warning -- may be huge if the Profile table is large 
>>> a[1].status 
'U' 
>>> a[1].status = 'C' 
>>> a[1].save() 
>>> a[1].status 
'C'