Python:Django模型的变化无法识别

时间:2013-02-06 20:30:38

标签: python django shell models choice

这一定非常简单,但我无法理解它。 我想为django模型实例分配一个简单的单字符值。我做了一百万次,但在这种情况下,它没有用。

my models.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'

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

3 个答案:

答案 0 :(得分:4)

我相信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的缓存。这意味着下次你要求[1]时,它会再次点击数据库。
  3. 此查询未指定任何顺序。数据库可以按任何最有效的顺序返回行,并且该顺序甚至可以在查询之间进行更改。
  4. 我知道MySQL,通常会按照最近更新的顺序返回记录。因此,只需保存记录,就不可能像以前一样处于同一位置。它可能会移动到结果集的开头或结尾,但不太可能保留在位置1(返回的第二个项目)。

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

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

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

    或者,如果您需要将其视为列表,则将其设为一个。从QuerySet中创建一个列表将完全评估它,并将整个结果集存储在内存中,每次请求时,[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'
    

答案 1 :(得分:3)

看看这个 -

>>> from apps.users.models import Member
>>> members = Member.objects.all()
>>> members[1].user_type
u'C'
>>> members[1].user_type = 'M'
>>> members[1].save()
>>> members[1].user_type
u'C'
>>> m = members[1]
>>> m.user_type
u'C'
>>> m.user_type = 'M'
>>> m.save()
>>> m.user_type
'M'

这是我认为正在发生的事情:all()方法返回一个QuerySet。从上面的查询中,当您对QuerySet中的项执行save()时,更改不会提交到数据库。但是如果你单独在Member对象上执行它,它确实有效。并从Django文档 -

  

QuerySets是懒惰的 - 创建QuerySet的行为不涉及   任何数据库活动。你可以整天堆叠过滤器,   在QuerySet之前,Django实际上不会运行查询   评估。 ......

     

通常,不从数据库中获取QuerySet的结果   直到你“问”他们。执行此操作时,将按以下方式评估QuerySet   访问数据库。

您可以阅读更多here。因此save()上的members[1]方法不会触及数据库或从那里读回。虽然Member对象的更改已提交到数据库并立即回读。

答案 2 :(得分:0)

PROFILE_STATUS[0]将返回('C', 'Claimed')及其元组。您需要PROFILE_STATUS[0][0]

a[1].status = Profile.PROFILE_STATUS[0][0]