1

これは本当に単純なはずですが、頭がわかりません。単純な 1 文字の値を 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'

しかし、ジャンゴは戻ってきます

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

属性の保存が認識されない、またはエラー メッセージが表示されるのはなぜですか?

4

3 に答える 3

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. 1 つのレコードのみがフェッチされます。これは効率化のために行われます。単一のレコードのみを要求したため、それ以上取得しても意味がありません。これはまた、
  2. Django は QuerySet のキャッシュを作成しません。これは、次に a[1] を要求したときに、データベースに再度ヒットすることを意味します。
  3. このクエリには順序が指定されていません。データベースは、最も効率的な順序で行を自由に返すことができ、その順序はクエリ間で変わることさえあります。

具体的には、MySQL は最近更新された順にレコードを返すことが多いことを知っています。そのため、レコードを保存するだけで、以前と同じ位置にある可能性は低くなります。結果セットの先頭または末尾に移動する可能性はありますが、位置 1 (返される 2 番目の項目) にとどまる可能性はほとんどありません。

これを避けるには、クエリセットをリストのように扱わないでください。スライス構文を使用して取得したアイテムに対して直接操作を実行しないでください。それを行う必要がある場合は、それらを一時変数に格納し、その変数に対してすべての操作を実行します。

この小さな変更により、すべての問題を回避できたはずです。

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

または、リストのように扱う必要がある場合は、1 つにします。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'
于 2013-02-07T06:24:05.067 に答える
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 を返します。save()また、上記のクエリから、QuerySet 内のアイテムを実行すると、変更がデータベースにコミットされません。ただし、Memberオブジェクトに対して個別に実行すると機能します。そしてDjangoのドキュメントから -

QuerySet は怠惰です。QuerySet を作成する行為には、データベース アクティビティは含まれません。フィルターを 1 日中積み重ねることができ、Django は QuerySet が評価されるまで実際にクエリを実行しません。...

一般に、QuerySet の結果は、ユーザーが「要求」するまでデータベースから取得されません。そうすると、データベースにアクセスして QuerySet が評価されます。

詳しくはこちらをご覧ください。したがって、save()メソッド onmembers[1]はデータベースに触れたり、そこから読み返したりしません。オブジェクトの変更はMemberデータベースにコミットされ、すぐに読み戻されます。

于 2013-02-07T05:49:38.887 に答える
0

PROFILE_STATUS[0]('C', 'Claimed')とそのタプルを返します。必要なものPROFILE_STATUS[0][0]:

a[1].status = Profile.PROFILE_STATUS[0][0]
于 2013-02-06T20:36:59.433 に答える