【问题标题】:Resubmitting form data with Flask and Jquery使用 Flask 和 Jquery 重新提交表单数据
【发布时间】:2021-08-01 05:55:12
【问题描述】:

我正在使用 Flask (https://astrodados.herokuapp.com/juego) 开发一个骰子应用程序,并且我想在不刷新页面的情况下使用相同的表单数据(如骰子数量)重新掷骰子。为此,我使用 Jquery 和 Ajax。我不明白为什么,但我无法获取数据,所以我收到错误“TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'”。 当我在 juego.html 中提交表单时,它会将我发送到 resjuego.html 并且一切正常。但是当我单击 resjuego.html 中的重新滚动按钮 ('#re_tirada') 时,Jinja 向我显示了错误。我看不出我做错了什么。我看过教程并尝试了很多不同的编码方式,但我无法获取数据。

我在 juego.html 中使用 Ajax 发送表单数据:

<script>
$(document).ready(function() {
    $('form').on('submit', function(event) {
        $.ajax({
            data : {
                signo : $('#signoInput').val(),
                pool : $('#poolInput').val(),
                magnitud : $('#magnitudInput').val() 
            },
            type : 'POST',
            url : '/back_retirada'
        })
        event.preventDefault();
    });
});
</script>
...
<form action=" {{(url_for('resjuego'))}}", method="post">
<div class='text-center'>
  <div class="form.row">
    <div class="col">
    <p class = "instrucciones">Ingresa tu ascendente: </p>
        <div id='signo'>
      {{ form.signo (class_="form-control form-control-lg")}}
  </div>
      <p class = "instrucciones">Elige la cantidad de dados:</p>
      <div id='pool'>
      {{form.pool (class_="form-control form-control-lg")}}
      </div>
      <p class = "instrucciones">
      Elige la magnitud de tu acción: </p>
      <div id='magnitud'>
      {{form.magnitud (class_="form-control form-control-lg")}}
      </p>
  </div>
      </div>
    <button type="submit">¡Tira los dados!</button>
</div>
</div>
</form>

这是我在 routes.py 中接收数据的视图:

@app.route('/back_retirada', methods=['GET', 'POST'])
def back_retirada():    
    signo = request.form['signo']
    pool =  request.form['pool']
    magnitud = request.form['magnitud']
    
    return jsonify ({'signo' : signo, 'pool': pool, 'magnitud': magnitud})

这是 /resjuego 的视图:

@app.route('/resjuego', methods=['GET','POST'])
def resjuego():
    form = CumuloForm()
    signo=request.form.get('signo')
    pool=request.form.get('pool', type = int)
    magnitud=request.form.get('magnitud', type = int)
    x = pool
    m = magnitud
    i=0
    roll=Dado.signar(x)
    res=roll
    y=rnd.randint(1,6)
    entropia=Dado.signar(y)
    thislist=[]
    thislist2=[]
    for i in range(x):
        thislist.append(Aspecto.aspectario(signo, res[0+i]))
        zumbi = thislist
    for i in range(y):
        thislist2.append(Aspecto.aspectario(signo, entropia[0+i]))
        zumbi2 = thislist2
    totalasp=zumbi+zumbi2
    conj = 2*(zumbi.count("conjunción"))
    semsex = 0*(zumbi.count("semisextil"))
    sext = 1*(zumbi.count("sextil"))
    cuad = -1*(zumbi.count("cuadratura"))
    trig = 1*(zumbi.count("trígono"))
    quinc = 0*(zumbi.count("quincuncio"))
    opos = -2*(zumbi.count("oposición"))

    conj2 = 2*(zumbi2.count("conjunción"))
    semsex2 = 0*(zumbi2.count("semisextil"))
    sext2 = 1*(zumbi2.count("sextil"))
    cuad2 = -1*(zumbi2.count("cuadratura"))
    trig2 = 1*(zumbi2.count("trígono"))
    quinc2 = 0*(zumbi2.count("quincuncio"))
    opos2 = -2*(zumbi2.count("oposición"))

    éxitos = conj + semsex + sext + cuad + trig + quinc + opos
    éxitosent= conj2 + semsex2 + sext2 + cuad2 + trig2 + quinc2 + opos2
    if éxitos + m <=0:
        rest="fallo"
    if éxitos >=0:
        rest="éxito"
    if éxitos <=0 and éxitos + m >=0:
        rest="adverso"
    des_exitos = descriptorc(rest)

    T1 = struli(zumbi)
    T2 = struli(zumbi2)
    res=struli(res)
    entropia=struli(entropia)

    return render_template('resjuego.html', title='Caosmos', lanzarcum=res, signo = signo, entropia=entropia, aspecto=T1, aspecto2=T2, éxitos=éxitos, éxitosent = éxitosent, des_exitos=des_exitos)

这是获取此数据的 jquery 代码,在 resjuego.html 中:

        <script type=text/javascript>
            $(function() {
                $("#re_tirada").click(function() {$.getJSON(
                    '/back_retirada')
                    }) })
                </script>
...

<div class='text-center'>
    <form>
        <span href=# id=re_tirada><button>¡Lanza otra vez!</button> </span>
    </form>
</div>

【问题讨论】:

  • 该错误是由于您使用函数int()但传递了一个值为None的事实引起的。不幸的是,您发布的部分代码并非如此。会不会是你求一个表单值,想把它转成整数?
  • 是的,这就是我想做的。我从表单(字符串中的数字)中获取“池”值,然后将其转换为整数。当我第一次提交数据时它可以工作,但当我尝试重新滚动时它不起作用。
  • 解释如下。 AJAX 是一种在后台传输数据而无需重新加载和渲染整个页面的方式。您还可以使用标准表格来实现您的目标。当您发送 GET 请求时,服务器端的表单对象为空,例如使用 getJSON。因此,如果端点允许这两种方法,您应该使用请求对象或 wtforms 来区分 GET 和 POST 请求。 Wtforms 为您提供验证条目的额外优势。
  • 我理解你的意图,但你的尝试是压倒性的。您的代码中使用了许多不同的技术。您应该将自己减少到最低限度,以便逐步实现目标。我删除了我的答案,因为它不再有用。请不要放弃,你会实现你的目标。很抱歉没能帮到你。

标签: javascript jquery user-interface flask frontend


【解决方案1】:

您可能根本不需要重新提交表单。
在本例中,表单数据被传输一次并保存在会话 cookie 中。从那时起,这些将在每次传输发生时发送到服务器。

from flask import Flask
from flask import redirect, render_template, request, session, jsonify, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField
from wtforms.validators import DataRequired, NumberRange
import random 

app = Flask(__name__)
app.secret_key = b'your secret here'

class ClusterForm(FlaskForm):
    sign = StringField(
        'Sign',
        validators=[DataRequired()],
        description='Enter your ascendant.'
    )
    pool = IntegerField(
        'Pool',
        validators=[NumberRange(min=1, max=6)],
        description='Choose the number of dice.'
    )
    magnitude = IntegerField(
        'Magnitude',
        validators=[NumberRange(min=1)],
        description='Choose the magnitude of your action.'
    )

@app.route('/')
@app.route('/game', methods=['GET', 'POST'])
def game():
    form = ClusterForm(request.form)
    if form.validate_on_submit():
        for k in ('sign', 'pool', 'magnitude'):
            session[k] = form[k].data
        return redirect(url_for('play'))
    return render_template('game.html', **locals())

@app.route('/play')
def play():
    if not all(k in session for k in ('sign', 'pool', 'magnitude')):
        return redirect(url_for('game'))
    return render_template('play.html')

@app.route('/turn')
def turn():
    sign = session.get('sign')
    pool = session.get('pool', 1)
    magnitude = session.get('magnitude', 1)

    print(sign, pool, magnitude)

    # Your calculation here!
    # A simplified example based on several dice rolls.
    throws = sum(random.randint(1,6) for _ in range(pool))
    result = ('misfortune', 'fortune')[throws >= 0.56*6*pool]

    return jsonify(prognosis=result)

这里是名为“game.html”的模板。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Game</title>
  </head>
  <body>
    <h1>Game</h1>
    <form action="{{ url_for('game') }}" method="post">
      {{ form.hidden_tag() }}
      <div>
        {{ form.sign.label }}
        {{ form.sign(class_='form-control' + ('', ' is-invalid')[form.sign.errors | count > 0]) }}
        {% if form.sign.errors: %}
        <div class="invalid-feedback">
            {{ form.sign.errors[0] }}
        </div>
        {% else %}
        <small class="form-text text-muted">
        {{ form.sign.description }}
        </small>
        {% endif %}
      </div>
      <div>
        {{ form.pool.label }}
        {{ form.pool(class_='form-control' + ('', ' is-invalid')[form.pool.errors | count  > 0]) }}
        {% if form.pool.errors: %}
        <div class="invalid-feedback">
            {{ form.pool.errors[0] }}
        </div>
        {% else %}
        <small class="form-text text-muted">
        {{ form.pool.description }}
        </small>
        {% endif %}
      </div>
      <div>
        {{ form.magnitude.label }}
        {{ form.magnitude(class_='form-control' + ('', ' is-invalid')[form.magnitude.errors | count  > 0]) }}
        {% if form.magnitude.errors: %}
        <div class="invalid-feedback">
            {{ form.magnitude.errors[0] }}
        </div>
        {% else %}
        <small class="form-text text-muted">
        {{ form.magnitude.description }}
        </small>
        {% endif %}
      </div>
      <input type="submit" />
    </form>
  </body>
</html>

这里是名为“play.html”的模板。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Play</title>
  </head>
  <body>
    <table>
      <tr>
        <th>Sign</th>
        <td>{{ session['sign'] }}</td>
      </tr>
      <tr>
        <th>Pool</th>
        <td>{{ session['pool'] }}</td>
      </tr>
      <tr>
        <th>Magnitude</th>
        <td>{{ session['magnitude'] }}</td>
      </tr>
    </table>

    <div id="main">
      <h2 id="prognosis">Loading</h2>
      <button id="roll">Roll</button>
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
    <script type="text/javascript">
    (function() {
      function roll() {
        $('#prognosis').html("Loading");
        $.getJSON('/turn')
          .done(data => {
            console.log(data);
            $('#prognosis').html(data.prognosis);
          });
      }
      $(document).ready(function() {
        $('#roll').click(roll);
        roll();
      });
    })();
    </script>
  </body>
</html>

【讨论】:

  • 感谢您的回答。我不知道那个类型转换器,它很有用,但是错误只是改变了这一行:pool 一直是 Nonetype,因为它没有内容。
  • 对不起逗号(太多 JS)。我编辑了代码以显示更多过程,并将 GET 方法添加到视图中。我试图像你展示的那样调用 ajax 方法,但它一直不起作用。 serialize 方法不起作用,因为我不需要打印这些数据,而是将其视为卷的变量。我该怎么做?
  • @ejeytijera 我已经再次处理了您的问题并更新了我的答案。我希望我的示例符合您的要求并帮助您实现目标。如果您有任何问题,请给我留言。
  • 谢谢!我已经尝试过你的代码,但遗憾的是我什么也没得到:现在,甚至第一卷都不可能。我直到现在才使用flask的会话对象;我读到它是不安全的,但如果数据用于掷骰子则无关紧要。我不会放弃,因为每一种寻求解决方案的方法都是新学到的东西。错误是一样的:它无法识别“pool”的值,因为它不存在(是 NoneType)。当我有时间时,我会重新排列我的代码以使其更具可读性。我意识到寻求帮助非常重要。
  • @ejeytijera 会话通常不是不安全的。正如您已经提到的,这取决于您在其中存储的内容,猜测应用程序密钥的难易程度等等。你可以利用它。代码对我来说运行完美,但我稍微改变了它。如果代码最终不起作用,请告诉我你会在终端和 web 开发者控制台中得到什么反馈。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2010-09-30
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多