Создание экземпляров записей Django с помощью сквозной модели

Допустим, у вас есть концепция битвы, и в этой битве есть игроки и враги. Игроки - это простое ManyToMany, но Враги требуют сквозной модели, потому что если в БД есть запись "Гоблин", игрокам нужно сражаться с ИНСТАНЦИЕЙ модели Гоблина. Игроки могут сражаться со многими гоблинами, и каждому из них нужно свое здоровье/статус в любой момент времени.

На данный момент у меня есть модель Django следующего вида (я упрощаю код для удобства чтения и чтобы сосредоточиться на основной проблеме)

class Battle(models.Model):
    players = ManyToMany(Player)
    enemies = ManyToMany(Enemy, through=EnemyThroughModel)

После внесения соответствующих изменений в admin.py и т.п. это работает: я могу присоединить к битве несколько врагов и видеть их в отдельном списке в админке, НО все они привязаны к одному и тому же основному врагу, и если я изменю одного из них (скажем, он получит урон), то у ВСЕХ привязанных к этому врагу ссылок теперь уменьшится здоровье.

Есть ли изящный способ использовать модели для создания нового экземпляра врагов, чтобы они имели независимое здоровье/ману/etc?

Вам нужно установить здоровье/ману врага в пределах сквозной модели:

class Player(models.Model):
    pass

class EnemyType(models.Model):
    pass

class EnemyInstance(models.Model):
    enemy_type = models.ForeignKey(EnemyType, on_delete=models.CASCADE)
    battle = models.ForeignKey('myapp.Battle', on_delete=models.CASCADE)
    mana = models.IntegerField()
    health = models.IntegerField()

class Battle(models.Model):
    players = models.ManyToManyField(Player)
    enemies = models.ManyToManyField(EnemyType, through=EnemyInstance)

При этом реляционные БД не предназначены для такого использования. Вам нужно будет считывать статистику здоровья/маны игроков и врагов в реальном времени, во время игры. Лучше хранить эти данные в памяти, используя объект python или другую структуру данных (xml, json и т. д.). Смотрите Как выбрать способ хранения данных? для хорошей отправной точки.

Вернуться на верх