1

I'm working on a page that autofills an html dropdown with data from a Django model, then on submit, sends that data to another page that will do things with it. I have the html dropdown populated, but am having issues POSTing to another page. I keep getting

"AttributeError at /battleSim/ 'tuple' object has no attribute 'get'

as my error despite similar code working in my characterCreator template. I get this error as soon as I attempt to navigate to battleSim.html on the development server, despite the fact it shouldn't be trying that until a POST method runs. (I think?) Below is the relevant code:

views.py:


class CharacterCreatorView(TemplateView):
    template_name = "characterCreator.html"

    # this solution courtesy of Eliakin Costa on StackOverflow: https://stackoverflow.com/a/59112612/12352379
    def post(self, request, *args, **kwargs):
        userID = 'testUser'
        addCharacter(
            userID,
            str(request.POST.get('characterName')),
            str(request.POST.get('race')),
            str(request.POST.get('class')),
            str(request.POST.get('strength')),
            str(request.POST.get('dexterity')),
            str(request.POST.get('constitution')),
            str(request.POST.get('intelligence')),
            str(request.POST.get('wisdom')),
            str(request.POST.get('charisma'))
        )

        return render(request, self.template_name, {})

class battleSimView(TemplateView):
    template_name = "battleSim.html"


    def get(self, request, *args, **kwargs):
       character  = characterTable.objects.all() # use filter() when you have sth to filter ;)
       monster = monsterTable.objects.all()
       return render(request, self.template_name, {'characters':character, 'monsters':monster},)

    def post(self, request, *args, **kwargs):
        if(request.method == "POST"):
            characterID = str(request.POST.get('character_id'))
            monsterID = str(request.POST.get('monster_id'))
            return(render(request, template_name ="battle.html"), {'characterID': characterID, 'monsterID': monsterID},)

battleSim.html form:

  <div class="container-fluid">

    <form method="POST">

      <select name="character_id" id = "character_id">
        {% for entry in characters %}
            <option value="playerName">{{ entry.playerName }}</option>
        {% endfor %}
      </select>

      <br><br>
      <p> VS </p>
      </br>

      <select name="monster_id" id = "monster_id">
        {% for entry in monsters %}
            <option value="monsterName">{{ entry.monsterName }}</option>
        {% endfor %} <!-- MAKE THIS A GET REQUEST YOU MORON -->
      </select>
      {% csrf_token %}
      <br>
      <input type="submit" class="btn" value="Click" name="mybtn">


    </form>


  </div>

characterCreator.html form:

      <div id = "formArea">
        <form name = "characterForm" id = "characterForm" method = "POST">
          {% csrf_token %}
          Character Name:<br>
          <input type="text" name="characterName" id ="characterName">
          <br>

          Race:<br>
          <select name = "race" id = "race">
            <option value = "human"> Human </option>
            <option value = "elf"> Elf </option>
            <option value = "dwarf"> Dwarf </option>
            <option value = "gnome"> Gnome </option>
            <option value = "halfling"> Halfling </option>
            <option value = "halfElf"> Half-Elf </option>
            <option value = "halfOrc"> Half-Orc </option>
          </select>
          <br>

          Class:<br>
          <select name = "class" id = "class" onchange="changePic()">
            <option value = "fighter"> Fighter </option>
            <option value = "rogue"> Rogue </option>
            <option value = "wizard"> Wizard </option>
          </select>
          <br>

          Strength:<br>
          <input type = "number" name = "strength">
          <br>

          Dexterity:<br>
          <input type = "number" name = "dexterity">
          <br>

          Constitution:<br>
          <input type = "number" name = "constitution">
          <br>

          Intelligence:<br>
          <input type = "number" name = "intelligence">
          <br>

          Wisdom:<br>
          <input type = "number" name = "wisdom">
          <br>

          Charisma:<br>
          <input type = "number" name = "charisma">
          <br>

          <br><br>
          <input type="submit" class="btn" value="Click" name="mybtn">

          <br><br>
        </form>


      </div>

models.py

from django.db import models
from django.forms import ModelForm


class characterTable(models.Model):
    userID = models.CharField(max_length = 32)
    playerName = models.CharField(max_length = 32)
    race = models.CharField(max_length = 32)
    playerClass = models.CharField(max_length = 32)
    strength = models.CharField(max_length = 2)
    dexterity = models.CharField(max_length = 2)
    constitution = models.CharField(max_length = 2)
    intelligence = models.CharField(max_length = 2)
    wisdom = models.CharField(max_length = 2)
    charisma = models.CharField(max_length = 2)

    def __str__(self):
        return (self.userID + ": " + self.playerName )


class monsterTable(models.Model):
    monsterName = models.CharField(max_length = 32)
    hp = models.CharField(max_length = 3)
    ac = models.CharField(max_length = 3)
    special = models.CharField(max_length = 32)

    def __str__(self):
        return(self.monsterName)
# Create your models here.

Ideally, on page load of battleSim, it runs the "get" function in battleSimView, populates the dropdowns with data from the database, which is working now, and then on clicking "submit", POSTS the data so that Django can render the next HTML page that will use the data submitted. I'm not sure why I'm getting this error when trying to POST out of battleSim.html but not characterCreator.html

I know using a Django form is the proper way to do things, but with how far into making it work with an HTML form I am, I would like to just keep doing it this way if possible, as this will be the last form to be submitted, and is the only one I'm having an issue with

EDIT: my updated function producing a syntax error


    def post(self, request, *args, **kwargs):
       characterID = str(request.POST.get('character_id'))
       monsterID = str(request.POST.get('monster_id'))
       return render(request, template_name ='battle.html',{'characterID':characterID, 'monsterID':monsterID})

nunzio
  • 51
  • 1
  • 2
  • 7

1 Answers1

2

Your post functions returns a 2-tuple, and does not pass the context to the render function. It should be:

return render(
    request,
    'battle.html',
    {'characterID': characterID, 'monsterID': monsterID}
)

Not:

return (render(
        request,
        template_name ='battle.html'
    ),
    {'characterID': characterID, 'monsterID': monsterID}
)

You use a lot of brackets. In Python one normally does not use brackets for simple if statements, etc. So although not wrong, it is more idiomatic to write if request.method == 'POST', than if (request.method == 'POST'):.

Note that you need to implement an else case as well, since the post method should always return a response. Here however the request.method == 'POST' check is not necessary, since Django's class-based views should do proper routing to post and get.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555