Джанго несколько раз просматривает вызовы функций - PullRequest
0 голосов
/ 24 сентября 2019

Я создаю браузерную RPG, в которой боевая механика встроена в модель под названием «Битва».Он выполняет действия на моделях Hero, Monster и Item в соответствии с некоторыми формулами.Каждое действие добавляет сообщение в «журнал сражений».Игрок может начать бой против другого игрока или NPC в форме.Когда форма отправляется, она вызывает то же представление, создается объект Battle, персонажи составляются, и игровая механика запускается.

По какой-то причине старые объекты "Battle" по-прежнему "выбираются" междузапускает эти представления, пока они находятся в одном веб-сеансе.Поэтому, даже если я создаю новый объект, старый журнал сражений переносится на этот новый объект.Что я здесь не так делаю?

Обновлено с дополнительным контекстом

Поле боя в первом объекте является правильным.Поле fightlog во втором объекте - это данные первых объектов плюс новые данные.Третий список сражений - это первый плюс второй плюс третий и т. Д.

views.py

def battle_log(request):

    if request.session["last_battle"]:
        pk = request.session["last_battle"]
        b = Battletest.objects.get(pk=pk)
        battle_log = b.fightlog

        request.session["last_battle"] = ""
        context = { 'battle_log' : battle_log, }

        return render(request, 'battle.html', context)

    else:
        return redirect('/game/monster')

def fight_select_monster(request):
    form = SelectCharacter()
    if request.method=='POST':
        form = SelectCharacter(request.POST)
        if form.is_valid():
            b = Battletest.objects.create()
            b.draft(request.POST.get("character"))
            b.start_fight()
            b.round()
            b.eof()
            b.save()

            request.session["last_battle"] =  b.pk
            return redirect('/game/fight/')

    context = { 'form': form }
    request.session["last_battle"] = ""
    return render(request, 'fight.html', context)

models.py

class Battletest(models.Model):
    messages = []
    fightlog = models.TextField()
    opponent = ""

    def draft(self, opponent):
        CHARACTERS= (
            (0, 'Confident Hacker'),
            (1, 'Confused Coder'),
        )
        self.opponent = CHARACTERS[int(opponent)][1]

    def start_fight(self):
        self.messages.append([0, "You joined the battle."])
        self.messages.append([0, self.opponent + "has appeared"])

    def round(self):
        # have character objects do stuff to eachother until
        # some edge case is met.
        self.messages.append([1, "You smack " + self.opponent + " in the face"])
        self.messages.append([1, self.opponent + " decides to leave this stupid fight"])

    def eof(self):
        self.messages.append([2, "The fight is over and noone wins"])
        self.fightlog = self.messages

forms.py

class SelectCharacter(forms.Form):

    CONFIDENTHACKER = 0
    CONFUSEDCODER = 1
    CHARACTERS= (
        (CONFIDENTHACKER, 'Confident Hacker'),
        (CONFUSEDCODER, 'Confused Coder'),
    )
    character = forms.ChoiceField(choices=CHARACTERS)

1 Ответ

1 голос
/ 24 сентября 2019

Хорошо, ваша проблема здесь:

class Battletest(models.Model):
    messages = []
    opponent = ""

Это определяет messages и opponent как class атрибуты - атрибуты, которые принадлежат самому объекту класса и как таковыеделится между всеми экземплярами класса, превращая их практически в глобальные переменные (поскольку объекты класса являются синглетонами).

Здесь вы хотите сделать messages атрибутом экземпляра, определив int в инициализаторе (вот для чего он):

class Battletest(models.Model):
     fightlog = models.TextField()

     def __init__(self, *args, **kwargs):
         # let Model do it's own stuff !!!
         super(Battletest, self).__init__(*args, **kwargs) 

         # and add our ones:
         self.messages = []
         self.opponent = None

В качестве примечания: такие ошибки часто встречаютсяпризнак того, что кто-то вроде «запрыгнул» в Django без предварительного изучения основ Python и ошибочно полагает, что поскольку модели Django используют атрибут класса для определения полей БД, синтаксис класса Python такой же, как в Java или PHP, где вы определяете атрибуты на верхнем уровне класса,Но это не то, как работает Python , и я очень настоятельно рекомендую, чтобы на этом этапе вы все остановили и сделали весь официальный урок по Python - это сэкономит вам много времени и боли, действительно,

В качестве примечания второй стороны: в контексте веб-приложения на стороне сервера вы хотите избежать любого (1022) глобального (изменяемого) состояния в вашем коде.Каждый бит изменяемого глобального состояния должен существовать в некоторых базах данных, ваших моделях, сеансах, независимо от того, является ли он внешним по отношению к вашему коду и может совместно использоваться многими процессами - потому что в типичной производственной настройке ваше приложение будет обслуживаться многими различными процессами (дадаже если у вас есть один единственный передний HTTP-сервер, он, как правило, будет управлять пулом процессов django, и запросы будут произвольно отправлены любому из этих процессов.

Теперь у вас есть еще одна проблема:

def eof(self):
    # ...
    self.fightlog = self.messages

Вы определили fightlog как текстовое поле, но вы назначаете ему список списков.То, что будет сохранено, будет текстовым представлением списка, что не очень удобно.

Теоретически, то, что у вас здесь есть, это отношение один ко многим (в Battletest есть много Посланий), поэтому правильным реляционным дизайном будет использование отдельной модели Message с ForeignKey на Battletest- как показано в учебнике (вы сделали учебник, не так ли?).

Теперь, если вы действительно настаиваете на денормализации этого, лучшее (не менее худшее) решение - это сериализовать messages до json в save() время и десериализовать его обратно в Python в инициализаторе.Это можно сделать вручную:

import json

class Battletest(models.Model):
     fightlog = models.TextField()

     def __init__(self, *args, **kwargs):
         # let Model do it's own stuff !!!
         super(Battletest, self).__init__(*args, **kwargs) 

         # and add our ones:
         if self.fightlog:
             self.messages = json.loads(self.fightlog)
         else:
             self.messages = []
         self.opponent = None

    # ...

    def save(self, *args, **kwargs):
        self.fightlog = json.dumps(self.messages)
        super(Battletest, self).save(*args, **kwargs)

или с помощью JSONField (который более или менее автоматически позаботится об этом), если ваша СУБД поддерживает это.Поиск в Google для «django JSONField» должен дать некоторые подсказки ...

О, да ... Вы дублировали код здесь:

class Battletest(models.Model):

    # ...

    def draft(self, opponent):
        CHARACTERS= (
            (0, 'Confident Hacker'),
            (1, 'Confused Coder'),
        )
        self.opponent = CHARACTERS[int(opponent)][1]

и здесь:

class SelectCharacter(forms.Form):

    CONFIDENTHACKER = 0
    CONFUSEDCODER = 1
    CHARACTERS= (
        (CONFIDENTHACKER, 'Confident Hacker'),
        (CONFUSEDCODER, 'Confused Coder'),
    )
    character = forms.ChoiceField(choices=CHARACTERS)

Вы хотите вычленить это, чтобы у вас была единственная точка истины:

class Battletest(models.Model):

        CONFIDENTHACKER = 0
        CONFUSEDCODER = 1
        CHARACTERS= [
            (CONFIDENTHACKER, 'Confident Hacker'),
            (CONFUSEDCODER, 'Confused Coder'),
        ]


    def draft(self, opponent):
        self.opponent = self.CHARACTERS[int(opponent)][1]

и в ваших формах.py:

from . models import Battletest

class SelectCharacter(forms.Form):
    character = forms.ChoiceField(choices=Battltest.CHARACTERS)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...