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

jk9hmnmh  于 2023-01-05  发布在  Shell
关注(0)|答案(3)|浏览(126)

这一定很简单,但我就是想不明白。我想给一个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'
    • 为什么保存属性时无法识别或出现任何错误消息?**
lvjbypge

lvjbypge1#

我相信Bibhas有大部分正确的答案。事实上,你总是通过一个QuerySet引用数据,Profile.objects.all()是最大的部分。再加上Django处理切片的方式(像列表索引,但QuerySet不是真正的列表),以及数据库不必考虑记录的顺序,这是一个令人困惑和沮丧的奇妙来源。
序列

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

将生成类似于以下内容的SQL:

SELECT * FROM user_profile LIMIT 1 OFFSET 1;

才能从表中得到一个值。这里有几个重要的东西:
1.只提取一条记录。这样做是为了提高效率,因为您只请求了一条记录,所以没有必要再检索任何记录。这也意味着

  1. Django不会填充QuerySet的缓存,这意味着下次你请求一个[1]时,它会再次命中数据库。
    1.此查询没有指定顺序。数据库可以按最有效的顺序返回行,并且该顺序甚至可以在查询之间更改。
    我知道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'
dfty9e19

dfty9e192#

你看看这个-

>>> 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文档中可以看出-
QuerySet是懒惰的--创建QuerySet的行为不涉及任何数据库活动。您可以整天将过滤器堆叠在一起,Django在计算QuerySet之前不会真正运行查询。
一般来说,QuerySet的结果只有在你“请求”它们的时候才会从数据库中获取,当你请求的时候,QuerySet会通过访问数据库来计算。
你可以在这里读到更多的内容。所以members[1]上的save()方法不接触数据库或从那里读回。而Member对象上的更改被提交到数据库并立即读回。

p8ekf7hl

p8ekf7hl3#

PROFILE_STATUS[0]将返回('C', 'Claimed')和它的一个元组,你需要PROFILE_STATUS[0][0]

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

相关问题