这一定很简单,但我无法理解它。 我想为 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;
为了从表中获取单个值。这里有几件重要的事情:
- 只获取了一条记录。这样做是为了提高效率,因为您只请求了一条记录,所以没有必要再检索了。这也意味着
- Django 不会填充 QuerySet 的缓存。这意味着下次您请求 a[1] 时,它将再次访问数据库。
- 此查询没有指定顺序。数据库可以自由地以最有效的顺序返回行,并且该顺序甚至可以在查询之间更改。
我知道 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'
