2016-11-20 47 views
1

我有一個與某些資源對象具有M2M關係的故事模型。某些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是從來沒有空。
  • 當我運行這些命令時,不會打印錯誤消息。
  • 我沒有重寫資源模型的保存方法(只有故事模型的保存方法)。
  • 我試圖使用@ transaction.atomic,但結果是一樣的。

我的模型:

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) 

文檔爲select_subclasses: http://django-model-utils.readthedocs.io/en/latest/managers.html#inheritancemanager

進一步調查: 我想,也許select_subclasses沒有返回的所有對象。現在每個故事都有一個資源。所以很容易檢查select_subclasses總是返回一個項目。這是我使用的功能:

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

您需要顯示模型的更多細節。 Story是否定義了任何默認排序? 'select_subclasses'有什麼作用?無論如何,分頁器並不是真正的正確工具。你可能想調查queryset ['iterator()'](https://docs.djangoproject.com/en/1.10/ref/models/querysets/#iterator)方法。除了別的之外,可能有更高效的方式來做這件事,例如通過'update()'。 –

+0

我添加了更多的代碼和一個鏈接到我正在使用的庫。尋找解決方法對我來說並不重要,我寧願明白爲什麼這種方法會失敗。但感謝提示,將更新()。 – user667804

+0

我並不是說這是問題(或問題)的100%,但是從代碼中跳轉出來的一件事是在覆蓋保存方法中調用'super()。save()'兩次。你用同樣的參數和kwargs來做,所以如果第一個'save()'從那些彈出,那麼你再次用新的參數調用save。糟糕的策略無論哪種方式,我建議你只調用一次 - 在更新人氣之前或之後。另外,如果你不熟悉它,那麼M2M關係不會保存在'save()'方法中,但是另外一個單獨的方法可以在Django文檔中找到它。 – makaveli

回答

0

我想我知道發生了什麼事:

的分頁程序加載查詢集和給我的前n項。我處理這些並更新一些值。但是對於下一次迭代,查詢集中的項目順序會發生變化(因爲我更新了其中的一部分並且沒有定義順序)。所以我跳過了現在在第一頁上的項目。我可以通過指定一個訂單來避免它(例如pk)。

如果您認爲我錯了,請告訴我。否則,我會接受這是正確的答案。謝謝。