繁体   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