2016-11-20 3 views
1

私はいくつかのリソースオブジェクトに対してM2M関係のStoryモデルを持っています。 Resourceオブジェクトの中には名前がないものがあるので、Storyのタイトルを割り当てられたResourceオブジェクトにコピーしたい。私は百万のオブジェクトを扱っていますので、私はページネータを使用する必要がDjangoはランダムに振る舞いを保存します

from collector import models 
from django.core.paginator import Paginator 

paginator = Paginator(models.Story.objects.all(), 1000) 

def fix_issues(): 
    for page in range(1, paginator.num_pages + 1): 
     for story in paginator.page(page).object_list: 
      name_story = story.title 
      for r in story.resources.select_subclasses(): 
       if r.name != name_story: 
        r.name = name_story 
        r.save() 
        if len(r.name) == 0: 
         print("Something went wrong: " + name_story) 
     print("done processing page %s out of %s" % (page, paginator.num_pages)) 

fix_issues() 

は、ここに私のコードです。変わった部分は、名前のない私のリソースの半分についてfix_issues()を呼び出した後、正しい名前を持ち、残りの半分にはまだ名前がないということです。 fix_issues()を何度も繰り返し呼び出すことができます。これは本当に私にとっては奇妙なようですが、なぜオブジェクトは初めて更新されないのですか?

追加情報:

  • "何かが間違っていた:" メッセージが印刷さ決してです。
  • 私はdjango-model-utilsのselect_subclassesを使用して、すべてのリソース(すべてのタイプ)を繰り返し処理しています。
  • story.titleはではありません。は空です。
  • これらのコマンドを実行すると、エラーメッセージは表示されません。
  • リソースモデルの保存メソッド(Storyモデルのsaveメソッドのみ)をオーバーライドしませんでした。
  • 私は@ transaction.atomicを使用しようとしましたが、結果は同じでした。

マイモデル:select_subclassesため

class Resource(models.Model): 
    name = models.CharField(max_length=200) 
    # Important for retrieving the correct subtype. 
    objects = InheritanceManager() 

    def __str__(self): 
     return str(self.name) 


class CustomResource(Resource): 
    homepage = models.CharField(max_length=3000, default="", blank=True, null=True) 


class Story(models.Model): 
    url = models.URLField(max_length=3000) 
    resources = models.ManyToManyField(Resource) 
    popularity = models.FloatField() 

    def _update_popularity(self): 
     self.popularity = 3 

    def save(self, *args, **kwargs): 
     super(Story, self).save(*args, **kwargs) 
     self._update_popularity() 
     super(Story, self).save(*args, **kwargs) 

ドキュメントhttp://django-model-utils.readthedocs.io/en/latest/managers.html#inheritancemanager

さらなる調査: を私は多分select_subclassesは、すべてのオブジェクトを返さなかったことを考えました。現在、すべてのストーリーには正確に1つのリソースがあります。したがって、select_subclassesが常に1つの項目を返すことを確認するだけで十分でした。これは私が使用した関数です:

def find_issues(): 
    for page in range(1, paginator.num_pages + 1): 
     for story in paginator.page(page).object_list: 
      assert(len(story.resources.select_subclasses()) == 1) 
     print("done processing page %s out of %s" % (page, paginator.num_pages)) 

これはやはり問題なく実行されます。だから私はselect_subclassesが責任を負うことではない。 paginator.num_pagesが正しいかどうかを確認しました。私が1000で割った場合(ページあたりのアイテム)、私は自分のデータベースにある物語の数を正確に取得します。

+0

モデルの詳細を表示する必要があります。ストーリーには既定の順序が定義されていますか? 'select_subclasses'は何をしますか?とにかく、ページネーターは本当に適切なツールではありません。 queryset ['iterator()'](https://docs.djangoproject.com/ja/1.10/ref/models/querysets/#iterator)メソッドを調べたいと思うかもしれません。それとは別に、おそらく 'update()'を使ってこれを行うもっと効率的な方法があります。 –

+0

私は使用しているライブラリへのコードとリンクを追加しました。回避策を見つけることは私にとってはそれほど重要ではないが、私はむしろこのアプローチが失敗する理由を理解するだろう。しかし、ヒントのおかげで、()更新時に読んでください。 – user667804

+0

私はこれが問題(または問題)100%だと言っているわけではありませんが、あなたのコードから飛び跳ねるものは、オーバーライドされたsaveメソッドで 'super()。save()'を2回呼び出しています。あなたは同じargsとkwargsでそれをやっているので、最初の 'save()'がそれらからsthをポップしたら、新しいparamsでsaveを再度呼び出します。どちらかといえば、どちらかと言えば、人気の更新前でも更新後でも1回だけ呼び出すことをお勧めします。また、あなたがそれに精通していない場合、M2Mリレーションは 'save()'メソッド内に保存されませんが、別の方法があります.Djangoドキュメントでそれを探します。 – makaveli

答えて

0

私は何が起こっているか知っていると思う:

ページネータは、クエリセットをロードし、私の最初のn個のアイテムを提供します。私はこれらを処理し、いくつかの値を更新します。しかし、次の反復では、クエリセット内のアイテムの順序が変更されます(その一部を更新し、順序を定義しなかったため)。だから私は最初のページにあるアイテムをスキップしています。注文を指定することでそれを避けることができます(たとえばpk)。

私が間違っていると思われる場合は、教えてください。さもなければ、私はこれを正しい答えとして受け入れます。ありがとうございました。