Frage

Sie sich das folgende Skelett eines models.py für einen Raum Eroberung Spiel:

class Fleet(models.Model):
    game = models.ForeignKey(Game, related_name='planet_set')
    owner = models.ForeignKey(User, related_name='planet_set', null=True, blank=True)
    home = models.ForeignKey(Planet, related_name='departing_fleet_set')
    dest = models.ForeignKey(Planet, related_name='arriving_fleet_set')
    ships = models.IntegerField()

class Planet(models.Model):
    game = models.ForeignKey(Game, related_name='planet_set')
    owner = models.ForeignKey(User, related_name='planet_set', null=True, blank=True)
    name = models.CharField(max_length=250)
    ships = models.IntegerField()

Ich habe viele solche Datenmodelle für ein Projekt arbeite ich, und ich den Zustand des Spiels zu ändern, basierend auf etwas komplizierten Wechselwirkungen zwischen verschiedenen Datenobjekten. Ich möchte viele unnötige Anrufe auf die Datenbank vermeiden, also einmal pro Zug, das tue ich so etwas wie

  1. Abfrage aller Flotten, Planeten und andere Objekte aus der Datenbank und als Python Objekte zwischenzuspeichern
  2. Prozess der Spielobjekte, die Lösung des Zustandes des Spiels
  3. Speichern Sie sie in der Datenbank
  4. zurück

Dieses Modell scheint völlig zusammenbrechen, wenn ForeignKey Objekte verwenden. Zum Beispiel, wenn eine neue Flotte eines Planeten fährt, habe ich eine Linie, die etwa wie folgt aussieht:

fleet.home.ships -= fleet.ships

Nachdem diese Linie läuft, habe ich einen anderen Code, der die Anzahl von Schiffen an jedem der Planeten verändert, einschließlich der Planeten fleet.home. Leider ist die in der obigen Zeile vorgenommenen Änderungen werden nicht in der QuerySet von Planeten reflektiert, die ich früher erhalten, so dass, wenn ich alle Planeten am Ende der Runde zu speichern, überschreiben die Änderungen an fleet.home Schiffen erhalten.

Gibt es eine bessere Möglichkeit, diese Situation zu handhaben? Oder ist dies nur, wie alle ORMs sind?

War es hilfreich?

Lösung

Django ORM hat eine Identitätskarte nicht umsetzen (es ist in der Ticket tracker , aber es ist nicht klar, ob oder wann sie umgesetzt werden, mindestens eine Django Committer Kern sprachen sich gegen sie ). Das bedeutet, dass, wenn Sie in dem gleichen Datenbankobjekt durch zwei verschiedene Abfragepfade ankommen, können Sie mit verschiedenen Python-Objekten im Speicher arbeiten.

Das bedeutet, dass Ihr Design (alles auf einmal in den Speicher laden, eine Menge Dinge ändern, speichern Sie sie dann alle am Ende zurück) ist nicht praktikabel, die Django ORM. Erstens, weil es oft vielen Speicher Laden in doppelten Kopien des gleichen Objekts verschwenden, und zweitens, weil die „Überschreiben“ Fragen wie die, die Sie in ausführen.

Sie müssen entweder Ihr Design zu überarbeiten, diese Probleme zu vermeiden (entweder vorsichtig sein, mit nur einem QuerySet zu einer Zeit zu arbeiten, etwas zu speichern geändert, bevor Sie eine weitere Abfrage machen, oder wenn Sie mehrere Abfragen laden, alle Beziehungen manuell nachschauen, nicht immer Traverse Foreign die praktischen Eigenschaften für sie), oder einen alternativen Python ORM verwenden, die Identität Karte implementiert. SQLAlchemy ist eine Option.

Beachten Sie, dass dies nicht bedeutet, Django ORM ist „schlecht“. Es ist für den Fall von Web-Anwendungen optimiert, in denen diese Art von Fragen sind selten (ich habe seit Jahren mit Django Web-Entwicklung gemacht und nicht ein einziges Mal dieses Problem auf einem realen Projekt hatte). Wenn Ihr Anwendungsfall unterschiedlich ist, möchten Sie vielleicht eine andere ORM wählen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top