Django ORM: cache e manipulação de objectos ForeignKey

votos
7

Considere o seguinte esqueleto de um models.py para um jogo espaço conquista:

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

Eu tenho muitos modelos tais dados para um projeto que estou trabalhando, e eu mudar o estado do jogo com base em interações pouco complicadas entre vários objetos de dados. Eu quero evitar muitas chamadas desnecessárias para o banco de dados, de modo que uma vez por turno, eu fazer algo assim

  1. Consultar todas as frotas, planetas e outros objetos do banco de dados e cache-los como objetos python
  2. Processar os objetos do jogo, resolvendo o estado do jogo
  3. Salvá-los de volta no banco de dados

Este modelo parece quebrar totalmente para baixo quando usando objetos ForeignKey. Por exemplo, quando uma nova frota se afasta um planeta, eu tenho uma linha que é algo como isto:

fleet.home.ships -= fleet.ships

Após esta linha funciona, eu tenho outro código que altera o número de navios em cada um dos planetas, incluindo o fleet.home planeta. Infelizmente, as mudanças feitas na linha acima não são refletidas na QuerySet de planetas que eu obtidos anteriormente, de modo que quando eu salvar todos os planetas no final do turno, as alterações para os navios de fleet.home obter substituído.

Existe alguma maneira melhor de lidar com esta situação? Ou isso é apenas como todos os ORMs são?

Publicado 25/03/2009 em 06:24
fonte usuário
Em outras línguas...                            


2 respostas

votos
20

ORM do Django não implementa um mapa de identidade (é no ticket tracker , mas não está claro se ou quando ele será implementado; pelo menos um núcleo Django committer tem manifestado oposição a ele ). Isto significa que se você chegar no mesmo objeto de banco de dados através de dois caminhos de consulta diferentes, você está trabalhando com diferentes objetos Python em memória.

Isso significa que seu projeto (carregar tudo na memória de uma só vez, modificar um monte de coisas, em seguida, guardar tudo de volta no final) é impraticável usando o Django ORM. Em primeiro lugar, porque muitas vezes vai perder muita carga de memória em cópias duplicadas do mesmo objeto, e segundo por causa de "substituindo" questões como o que você está correndo em.

Você nem precisa de refazer o seu projeto para evitar esses problemas (ou ter o cuidado de trabalhar com apenas um QuerySet de cada vez, salvar nada modificado antes de fazer outra consulta, ou se você carregar várias consultas, procurar todas as relações manualmente, não ForeignKeys sempre transversais usando os atributos convenientes para eles), ou usar um ORM Python alternativa que implementa mapa identidade. SQLAlchemy é uma opção.

Note que isso não significa ORM do Django é "mau". Ele é otimizado para o caso de aplicações web, onde esses tipos de problemas são raros (eu fiz desenvolvimento web com Django durante anos e nunca tive esse problema em um projeto real). Se o seu caso de uso é diferente, você pode querer escolher um ORM diferente.

Respondeu 25/03/2009 em 16:16
fonte usuário

votos
1

Este é talvez o que você está procurando:

http://simonwillison.net/2009/May/7/mmalones/

Respondeu 22/05/2009 em 15:34
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more