2016-11-20 5 views
1

Ich habe ein Story-Modell mit einer M2M-Beziehung zu einigen Ressourcen-Objekten. Bei einigen Ressourcenobjekten fehlt ein Name, daher möchte ich den Titel der Story in die zugewiesenen Ressourcenobjekte kopieren.Django speichern Verhalten nach dem Zufallsprinzip

Hier ist mein Code:

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() 

Ich brauche eine paginator zu verwenden, weil ich mit einer Million Objekten zu tun habe. Der komische Teil ist, dass nach dem Aufruf von fix_issues() etwa die Hälfte meiner Ressourcen, die keinen Namen hatten, nun den richtigen Namen haben, während die andere Hälfte noch keinen Namen hat. Ich kann fix_issues() immer wieder aufrufen und jedes Mal erhalten mehr Objekte einen Namen. Das erscheint mir wirklich komisch, warum sollte ein Objekt nicht beim ersten Mal aktualisiert werden, sondern nur beim zweiten Mal?

Zusätzliche Informationen:

  • Das "ging etwas schief:" Nachricht ist nie gedruckt.
  • Ich benutze select_subclasses von django-model-utils, um über alle Ressourcen (jeden Typ) zu iterieren.
  • Der story.title ist nie leer.
  • Keine Fehlermeldung wird gedruckt, wenn ich diese Befehle ausführen.
  • Ich habe die Speichermethode des Ressourcenmodells nicht überschrieben (nur die Speichermethode des Story-Modells).
  • Ich versuchte, @ transaction.atomic zu verwenden, aber das Ergebnis war das gleiche.

My Model:

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) 

Dokumentation für die select_subclasses: http://django-model-utils.readthedocs.io/en/latest/managers.html#inheritancemanager

Weitere Untersuchungen: Ich dachte, dass vielleicht select_subclasses nicht alle Objekte haben zurückzukehren. Im Moment hat jede Geschichte genau eine Ressource. Es war also einfach genug zu überprüfen, dass select_subclasses immer ein Element zurückgibt. Dies ist die Funktion, die ich verwendet:

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)) 

Aber auch dies führt ohne Probleme. Also ich ding nicht die select_subclasses ist schuld. Ich habe auch überprüft, ob paginator.num_pages richtig ist und es ist. Wenn ich durch 1000 dividiere (Elemente pro Seite), bekomme ich genau die Anzahl der Geschichten, die ich in meiner Datenbank habe.

+0

Sie müssen mehr Details Ihrer Modelle anzeigen. Hat Story eine Standardreihenfolge definiert? Was macht 'select_subclasses'? Paginatoren sind hier sowieso nicht das richtige Werkzeug; Vielleicht möchten Sie die Methode queryset ['iterator()'] (https://docs.djangoproject.com/en/1.10/ref/models/querysets/#iterator) untersuchen. Und, abgesehen von allem anderen, gibt es wahrscheinlich einen viel effizienteren Weg, dies zu tun, zB über 'update()'. –

+0

Ich habe mehr Code und einen Link zu der Bibliothek hinzugefügt, die ich verwende. Die Suche nach einem Workaround ist für mich nicht so wichtig, ich würde lieber verstehen, warum dieser Ansatz fehlschlägt. Aber danke für den Hinweis, lesen Sie update(). – user667804

+0

Ich sage nicht, dass dies das Problem (oder ein Problem) 100% ist, aber eine Sache, die von Ihrem Code aufspringt, ruft 'super(). Save()' zweimal in der überschriebenen Speichermethode auf. Du machst es mit den gleichen Argumenten und Kwargs, wenn also das erste 'save()' aus diesen herausspringt, dann rufst du erneut mit neuen Parametern auf. Schlechte Taktiken wie auch immer, ich schlage vor, du nennst es nur einmal - entweder vor oder nach dem Aktualisieren der Popularität. Auch wenn Sie nicht damit vertraut sind, dann werden M2M Relationen nicht innerhalb der 'save()' Methode gespeichert, aber es gibt eine andere separate Methode dafür, suchen Sie in den Django Dokumenten. – makaveli

Antwort

0

Ich glaube, ich weiß, was passiert:

Der Paginator ein Queryset lädt und gibt mir die ersten n Elemente. Ich verarbeite diese und aktualisiere einige der Werte. Aber für die nächste Iteration ändert sich die Reihenfolge der Elemente im Abfrage-Set (weil ich einige von ihnen aktualisiert habe und keine Reihenfolge definiert habe). Also überspringe ich Gegenstände, die jetzt auf der ersten Seite sind. Ich kann es vermeiden, indem ich eine Reihenfolge (pk zum Beispiel) festlege.

Wenn Sie denken, dass ich falsch liege, lass es mich wissen. Ansonsten werde ich das als die richtige Antwort akzeptieren. Vielen Dank.

Verwandte Themen