簡體   English   中英

在 Django CreateView 中,使用類方法生成要在 get_context_data() 和 form_valid() 中使用的數據

[英]In Django CreateView use a class method to generate data to use in both get_context_data() and form_valid()

我實際上正在研究一個學生項目,我嘗試使用 Python Django 在網絡上創建一個 roguelike 游戲。

我實際上對我的問題感到困惑,為了解釋我需要做的是在受所選角色類影響的角色創建中生成隨機特征。

我想在用戶開始游戲之前將這些特征發送給用戶。 並使用我在 form_valid() 中發送給他的特征將字符保存在 db 中。

我知道我可以使用 get_context_data() 將一些信息發送到我的模板,但我不知道是否可以使用 get_context_data() 發送到 form_valid() 中的模板的數據。

實際上,我使用 CreateView 成功地通過選擇的字符類保存了具有隨機特征的字符,請參閱下面的代碼。

模型.py

class CharacterClass(models.Model):
    name = models.CharField(max_length=20,
                            blank=True,
                            null=True)
    minHpMax = models.PositiveIntegerField(default=10,
                                           validators=[MinValueValidator(10)],
                                           blank=False,
                                           null=False)
    minStrength = models.IntegerField(default=1,
                                      validators=[MinValueValidator(0)],
                                      blank=False,
                                      null=False)
    minAgility = models.IntegerField(default=1,
                                     validators=[MinValueValidator(0)],
                                     blank=False,
                                     null=False)
    minInt = models.IntegerField(default=1,
                                 validators=[MinValueValidator(0)],
                                 blank=False,
                                 null=False)
    minPhysResis = models.IntegerField(default=0,
                                       validators=[MinValueValidator(0)],
                                       blank=False,
                                       null=False)
    minMagRes = models.IntegerField(default=0,
                                    validators=[MinValueValidator(0)],
                                    blank=False,
                                    null=False)

    def __str__(self):
        return f'{self.id}: {self.name}'

    def generateHpMax(self):
        return random.randint(self.minHpMax, self.minHpMax + 10)

    def generateStrength(self):
        return random.randint(self.minStrength, self.minStrength + 10)

    def generateAgility(self):
        return random.randint(self.minAgility, self.minAgility + 10)

    def generateIntelligence(self):
        return random.randint(self.minInt, self.minInt + 10)

    def generatePR(self):
        return random.randint(self.minPhysResis, self.minPhysResis + 10)

    def generateMR(self):
        return random.randint(self.minMagRes, self.minMagRes + 10)


class Character(models.Model):
    name = models.CharField(max_length=20,
                            default='Jon Doe',
                            blank=False,
                            null=False)
    characterClass = models.ForeignKey(CharacterClass,
                                       on_delete=models.CASCADE,
                                       related_name='characterClass')
    level = models.PositiveIntegerField(default=1,
                                        validators=[MinValueValidator(1)],
                                        blank=False,
                                        null=False)
    hpMax = models.PositiveIntegerField(default=10,
                                        validators=[MinValueValidator(0)],
                                        blank=False,
                                        null=False)
    hp = models.PositiveIntegerField(default=10,
                                     validators=[MinValueValidator(0)],
                                     blank=False,
                                     null=False)
    strength = models.IntegerField(default=1,
                                   validators=[MinValueValidator(0)],
                                   blank=False,
                                   null=False)
    agility = models.IntegerField(default=1,
                                  validators=[MinValueValidator(0)],
                                  blank=False,
                                  null=False)
    intelligence = models.IntegerField(default=1,
                                       validators=[MinValueValidator(0)],
                                       blank=False,
                                       null=False)
    physicalResistance = models.IntegerField(default=0,
                                             validators=[
                                                 MinValueValidator(0)],
                                             blank=False,
                                             null=False)
    magicalResistance = models.IntegerField(default=0,
                                            validators=[
                                                MinValueValidator(0)],
                                            blank=False,
                                            null=False)
    inventory = models.OneToOneField('Inventory',
                                     on_delete=models.PROTECT)

    def __str__(self):
        return f'{self.id}: {self.name} ' \
               f'[Lvl: {self.level}' \
               f'|Class: {self.characterClass}' \
               f'|HpM: {self.hpMax}' \
               f'|hp: {self.hp}' \
               f'|Str: {self.strength}' \
               f'|Ag: {self.agility}' \
               f'|Int: {self.intelligence}' \
               f'|Pr: {self.physicalResistance}' \
               f'|Mr: {self.magicalResistance}]'

    def get_absolute_url(self):
        return reverse('characterDetail', kwargs={'pk': self.pk})

視圖.py

    class GenerateCharacterView(CreateView):
    model = Character
    form_class = CharacterForm
    template_name = 'characterForm.html'

    def form_valid(self, form):
        # Creation of Character without db saving
        self.object = form.save(commit=False)

        # creation of empty inventory unique for the Character
        inventory = Inventory()
        inventory.save()
        self.object.inventory = inventory

        pkCharacterClass= form['characterClass'].value()
        currentCharacterClass = get_object_or_404(CharacterClass,
                                                  pk=pkCharacterClass)

        # for a CharacterClass found, get random characteristics for the Character in creation
        generatedHpMax = currentCharacterClass.generateHpMax()
        self.object.hpMax = generatedHpMax
        self.object.hp = generatedHpMax

        generatedStrength = currentCharacterClass.generateStrength()
        self.object.strength = generatedStrength

        generatedAgility = currentCharacterClass.generateAgility()
        self.object.agility = generatedAgility

        generatedIntelligence = currentCharacterClass.generateIntelligence()
        self.object.intelligence = generatedIntelligence

        generatedPhysicalResistance = currentCharacterClass.generatePR()
        self.object.physicalResistance = generatedPhysicalResistance

        generatedMagicalResistance = currentCharacterClass.generateMR()
        self.object.magicalResistance = generatedMagicalResistance

        # Enregistrement en BDD de l'objet et appel du super form valid pour
        # renvoie de la succes url défini en Model
        self.object.save()
        return super().form_valid(form)

表格.py

    class CharacterForm(forms.ModelForm):
    class Meta:
        model = Character
        # exclude = []
        fields = ['name', 'characterClass']

    name = forms.CharField(max_length=20, widget=widgets.TextInput(
        attrs={'placeholder': 'Enter Your Name'}
    ))

網址.py

    urlpatterns = [
    path('admin/', admin.site.urls),
    path('', IndexView.as_view(), name='home'),
    path('generateCharacter',
         GenerateCharacterView.as_view(),
         name='generateCharacter'),
    path('characterDetail/<int:pk>', CharacterDetailView.as_view(),
         name='characterDetail'),
]

這種用法你已經成功了嗎? 你知道它是否有效嗎? 如何 ? 你對我有什么提示或建議嗎? 我現在正在研究它 2 天,我快瘋了。


您好,很抱歉這張票,我可能在其中顯示的內容有誤。

現在我使用我在票證中顯示的代碼來解決我的問題。

此時我可以通過選擇一個 CharacterClass 和一個角色名稱來生成一個具有隨機特征的角色。

但是我想要做的是當我進入表單頁面時生成隨機特征。

因此,我嘗試在頁面上放置一個按鈕,該按鈕調用路徑“createCharacter/1”,其中“1”是我的角色類的 pk。

並且我此時嘗試生成隨機特性以在提交表單之前向用戶顯示特性。

並且在表格中只詢問了人物姓名。

所以這是我之前使用的代碼

網址.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', IndexView.as_view(), name='home'),
    path('createCharacter/<int:characterClass>',
         CreateCharacterView.as_view(),
         name='createCharacter'),
    path('characterDetail/<int:pk>', CharacterDetailView.as_view(),
         name='characterDetail'),
]

視圖.py

class CreateCharacterView(CreateView):
    model = Character
    form_class = CharacterForm
    template_name = 'characterForm.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        classCharacter = get_object_or_404(CharacterClass ,self.kwargs['characterClass'])
        context['randomCarac'] = classCharacter.getRadomCarac()
        return context 

    def form_valid(self, form):
        self.object = form.save(commit=False)


        inventory = Inventory()
        inventory.save()
        self.object.inventory = inventory


        self.object.characterClass= context['characterClass']
        self.object.hpMax = context['hpMax ']
        self.object.hp = context['hpMax ']
        self.object.strength = context['strength ']
        self.object.agility = context['agility ']
        self.object.intelligence = context['intelligence  ']
        self.object.physicalResistance = context['physicalResistance ']
        self.object.magicalResistance = context['magicalResistance ']

        self.object.save()
        return super().form_valid(form)

模型.py

class CharacterClass(models.Model):
    name = models.CharField(max_length=20,
                            blank=True,
                            null=True)
    minHpMax = models.PositiveIntegerField(default=10,
                                           validators=[MinValueValidator(10)],
                                           blank=False,
                                           null=False)
    minStrength = models.IntegerField(default=1,
                                      validators=[MinValueValidator(0)],
                                      blank=False,
                                      null=False)
    minAgility = models.IntegerField(default=1,
                                     validators=[MinValueValidator(0)],
                                     blank=False,
                                     null=False)
    minInt = models.IntegerField(default=1,
                                 validators=[MinValueValidator(0)],
                                 blank=False,
                                 null=False)
    minPhysResis = models.IntegerField(default=0,
                                       validators=[MinValueValidator(0)],
                                       blank=False,
                                       null=False)
    minMagRes = models.IntegerField(default=0,
                                    validators=[MinValueValidator(0)],
                                    blank=False,
                                    null=False)

    def __str__(self):
        return f'{self.id}: {self.name}'

    def generateHpMax(self):
        return random.randint(self.minHpMax, self.minHpMax + 10)

    def generateStrength(self):
        return random.randint(self.minStrength, self.minStrength + 10)

    def generateAgility(self):
        return random.randint(self.minAgility, self.minAgility + 10)

    def generateIntelligence(self):
        return random.randint(self.minInt, self.minInt + 10)

    def generatePR(self):
        return random.randint(self.minPhysResis, self.minPhysResis + 10)

    def generateMR(self):
        return random.randint(self.minMagRes, self.minMagRes + 10)

    def getRadomCarac(self):
        return {'hpMax': self.generateHpMax(),
                'strength': self.generateStrength(),
                'agility': self.generateAgility(),
                'intelligence': self.generateIntelligence(),
                'physicalResistance': self.generatePR(),
                'magicalResistance': self.getRadomCarac()}


那行不通。 似乎我無法訪問 form_validation() 中的上下文 ['something']

所以我也試着

class CreateCharacterView(CreateView):
    model = Character
    form_class = CharacterForm
    template_name = 'characterForm.html'
    classCharacter = get_object_or_404(CharacterClass ,self.kwargs['characterClass'])
    randomCarac = classCharacter.getRadomCarac()

def form_valid(self, form):
        # Do things here with randomCarac['something']

要在視圖中使用值“全局”以在我需要時使用,get_object_or_404() 不起作用

好的,這是在我的項目中工作的最終代碼

網址.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', IndexView.as_view(), name='home'),
    path('generateCharacterByPk/<int:pk>', GenerateCharacterView2.as_view(),
         name='generateCharacterByPk'),
    path('generateCharacter', GenerateCharacterView.as_view(),
         name='generateCharacter'),
    path('characterDetail/<int:pk>', CharacterDetailView.as_view(),
         name='characterDetail'),
]

表格.py

class CharacterForm2(forms.ModelForm):
    class Meta:
        model = Character
        # exclude = []
        fields = ['name']

    name = forms.CharField(max_length=20, widget=widgets.TextInput(
        attrs={'placeholder': 'Enter Your Name'}
    ))

視圖.py

class GenerateCharacterView2(CreateView):
    model = Character
    form_class = CharacterForm2
    template_name = 'characterForm.html'

    def get_context_data(self, **kwargs):
        result = super().get_context_data(**kwargs)
        result['title'] = 'Create Character'
        return result

    def get(self, *args, **kwargs):
        currentCharacterClass = get_object_or_404(CharacterClass,
                                                  pk=self.kwargs['pk'])

        self.request.session['characterClass'] = self.kwargs['pk']
        self.request.session['HpMax'] = currentCharacterClass.generateHpMax()
        self.request.session['Strength'] = currentCharacterClass.generateStrength()
        self.request.session['Agility'] = currentCharacterClass.generateAgility()
        self.request.session['Intelligence'] = currentCharacterClass.generateIntelligence()
        self.request.session['PhysicalResistance'] = currentCharacterClass.generatePR()
        self.request.session['MagicalResistance'] = currentCharacterClass.generateMR()
        return super().get(self)

    def form_valid(self, form):
        # Création de l'objet sans enregistrement en base
        self.object = form.save(commit=False)

        # Création d'un inventaire vide unique au personnage avec affectation et récupéraction de la classe du personnage
        currentCharacterClass = get_object_or_404(CharacterClass,
                                                  pk=self.request.session['characterClass'])
        inventory = Inventory()
        inventory.save()

        # Constitution du personnage
        self.object.inventory = inventory
        self.object.characterClass = currentCharacterClass
        self.object.hpMax = self.request.session['HpMax']
        self.object.hp = self.request.session['HpMax']
        self.object.strength = self.request.session['Strength']
        self.object.agility = self.request.session['Agility']
        self.object.intelligence = self.request.session['Intelligence']
        self.object.physicalResistance = self.request.session['PhysicalResistance']
        self.object.magicalResistance = self.request.session['MagicalResistance']

        # Création en BDD du personnage
        self.object.save()
        return super().form_valid(form)

字符表.html

{% extends 'base.html' %}

{% block page-top %}


    <form method="POST">
        {% csrf_token %}
        {% for field in form %}
            <div class="h5 font-weight-bold text-primary text-uppercase mb-1">
                <label>
                    {{ field.label }}:
                </label>
                <nav>
                    {{ field }}
                </nav>
            </div>
        {% endfor %}

        {{ request.session.characterClass }}
        {{ request.session.HpMax }}
        {{ request.session.Strength }}
        {{ request.session.Intelligence }}
        {{ request.session.Agility }}
        {{ request.session.PhysicalResistance }}
        {{ request.session.MagicalResistance }}
        <button type="submit">Valider</button>
    </form>


{% endblock %}

謝謝@dirkgroten 的幫助,這真的很有幫助

如果您想在向用戶顯示表單時創建一個隨機字符在用戶提交表單時保存該隨機字符(字符的名稱),則需要以某種方式保留隨機字符。

你有幾個選擇:

  1. 在第一次使用 GET 請求(名稱為空)呈現表單時創建並保存該角色,並將該角色的 id 作為隱藏字段包含在表單中,以便在提交表單時使用名稱更新該角色. 您需要以某種方式檢查提交的id屬於“草稿”角色,以確保用戶不會竊取另一個已經存在的角色,因此您可能需要在Character模型中添加一個status字段。 您不會在此處使用CreateView ,但基於函數的視圖會更合適。

  2. 您可以在視圖的get()方法中為角色創建值,並將它們存儲在request.session (參見 此處)中,以便您可以在form_valid()方法中從會話中檢索所述值。 這種方法對我來說似乎更容易。 您仍然可以在此處使用CreateView 您可以直接使用{{ request.session.<somekey> }}將它們顯示在您的模板中,也可以通過在get_context_data()中以更容易在模板中呈現的格式將它們添加到您的上下文中。

通過隱藏的表單輸入字段提交隨機值不是一種選擇,因為任何人都可以篡改提交的值。

請注意,我不明白為什么您的Character模型沒有對User的引用( ForeignKeyOneToOneField )。 目前尚不清楚如何檢查角色是否屬於該用戶並避免用戶竊取其他人的角色。 如果你添加這個,那么在選項 1 中你甚至不需要檢查id因為request.user只能有一個“草稿” Character

可能會遺漏您的解決方案中的某些內容,我已經嘗試了解決方案 2,並且我編寫了以下代碼

索引.html

    <button>
        <a href="{% url 'generateCharacterByPk' 1 %}">Play2(pk=1)</a>
    </button>

    <button>
        <a href="{% url 'generateCharacterByPk' 2 %}">Play2(pk=2)</a>
    </button>

網址.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', IndexView.as_view(), name='home'),
    path('generateCharacterByPk/<int:pk>',
         GenerateCharacterView2.as_view(),
         name='generateCharacterByPk'),
    path('generateCharacter',
         GenerateCharacterView.as_view(),
         name='generateCharacter'),
    path('characterDetail/<int:pk>', CharacterDetailView.as_view(),
         name='characterDetail'),
]

表格.py

class CharacterForm2(forms.ModelForm):
    class Meta:
        model = Character
        # exclude = []
        fields = ['name']

    name = forms.CharField(max_length=20, widget=widgets.TextInput(
        attrs={'placeholder': 'Enter Your Name'}
    ))

視圖.py

class GenerateCharacterView2(CreateView):
    model = Character
    form_class = CharacterForm2
    template_name = 'characterForm.html'

    def get_context_data(self, **kwargs):
        result = super().get_context_data(**kwargs)
        result['title'] = 'Create Character'
        return result

    def get(self, request, *args, **kwargs):
        request.session.characterClass = self.kwargs['pk']
        currentCharacterClass = get_object_or_404(CharacterClass,
                                                  pk=self.kwargs['pk'])
        request.session.characterClass = currentCharacterClass
        request.session.HpMax = currentCharacterClass.generateHpMax()
        request.session.Strength = currentCharacterClass.generateStrength()
        request.session.Agility = currentCharacterClass.generateAgility()
        request.session.Intelligence = currentCharacterClass.generateIntelligence()
        request.session.PhysicalResistance = currentCharacterClass.generatePR()
        request.session.MagicalResistance = currentCharacterClass.generateMR()
        return render(request, 'characterForm.html')

    def form_valid(self, form):
        # Création de l'objet sans enregistrement en base
        self.object = form.save(commit=False)

        # Création d'un inventaire vide unique au personnage avec affectation
        inventory = Inventory()
        inventory.save()

        self.object.inventory = inventory
        self.object.hpMax = request.session.characterClass
        self.object.hpMax = request.session.HpMax
        self.object.hp = request.session.HpMax
        self.object.strength = request.session.Strength
        self.object.agility = request.session.Agility
        self.object.intelligence = request.session.Intelligence
        self.object.physicalResistance = request.session.PhysicalResistance
        self.object.magicalResistance = request.session.MagicalResistance

        self.object.save()
        return super().form_valid(form)

字符表.html

{% extends 'base.html' %}

{% block page-top %}


    <form method="POST">
        {% csrf_token %}
        {% for field in form %}
            <div class="h5 font-weight-bold text-primary text-uppercase mb-1">
                <label>
                    {{ field.label }}:
                </label>
                <nav>
                    {{ field }}
                </nav>
            </div>
        {% endfor %}

        {{ request.session.characterClass }}
        {{ request.session.HpMax }}
        {{ request.session.Strength }}
        {{ request.session.Intelligence }}
        {{ request.session.Agility }}
        {{ request.session.PhysicalResistance }}
        {{ request.session.MagicalResistance }}
        <button type="submit">Valider</button>
    </form>


{% endblock %}

當我訪問 generateCharacterByPk/1 或 generateCharacterByPk/2 時,我有一個奇怪的反應

首先,我使用提交按鈕在我的頁面上看到隨機生成的隨機特征。

當我點擊重新加載頁面時,我最終會看到我的表單和一個提交按鈕,但我在我的頁面上看不到這些功能了。

當我驗證表單時,我收到以下錯誤:

AttributeError at /generateCharacterByPk/1
module 'django.http.request' has no attribute 'session'.
Request Method: POST
Request URL: http://127.0.0.1:8000/generateCharacterByPk/1
Django Version: 3.0.2
Exception Type: AttributeError
Exception Value:    
module 'django.http.request' has no attribute 'session'.
Exception Location: C:\Users\u049298\Desktop\PYTHON_DJANGO\projetWebRPG\app\views.py in form_valid, line 130
```

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM