flask wtforms QuerySelectFeld form.populate_obj fields not populated and if filled in error translate raised

偶尔善良 提交于 2021-01-29 11:41:52

问题


I am struggling with two problems,

1/ QuerySelectField not populated

2/ Translate error if field is filled in

I have an add function and an edit function, I am using "from wtforms_alchemy.fields import QuerySelectField" to allow a choice from one data base model to be available in a drop down list. In the "addboilercircuit" function this works, in the form a drop down list is displayed and I can submit the form. in the "editboilercircuit" function I am using formpopulate_obj all the fields are populated accept the QuerySelectField, a drop down list is visible but it does not display the saved choice, if I select one of the choices and then submit I get a translate error message. Here is my code:

form.py

def boiler_ID():
    return Boilers.query

class AddBoilerCircuitForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired()])
    boiler_ID = QuerySelectField('Boiler_ID',
                    query_factory=boiler_ID,
                    get_label='id')
    submit = SubmitField('Register')

models.py

class Boilers(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    state = db.Column(db.String(9))

    def __repr__(self):
        return '<Boilers {}>'.format(self.id)

class Boilercircuit(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    boiler_ID = db.Column(db.String(30))

    def __repr__(self):
        return '<Boilercircuit {}>'.format(self.id)

boilers.py

@bp.route('/boilers/editboilercircuit/<int:id>', methods=('GET', 'POST')) 
@login_required
def editboilercircuit(id):
    obj = Boilercircuit.query.get(id) or Boilers()
    form = AddBoilerCircuitForm(request.form, obj=obj)
    if form.validate_on_submit():
        form.populate_obj(obj)
        db.session.add(obj)
        db.session.commit()
        flash('Congratulations, you are have updated a Boiler Circuit!')
        return redirect(url_for('boilers.boilercircuits'))
    return render_template('boilers/editboilercircuit.html', title= 'edit boilercircuit',
                          form=form, obj=obj)

and the html editboilercircuit.html

  <h2>Edit Boiler Circuit</h2>
      <form action="" method="post">
      {{ form.hidden_tag() }}
          <div>{{ form.name.label }} {{ form.name(class="input") }}</div>
          <div>{{ form.boiler_ID.label }} {{ form.boiler_ID(class="input") }}</div>
          <div>{{ form.submit(class="submit") }}</div>
     <form>

the error message is

AttributeError: 'Boilers' object has no attribute 'translate'

on the "addboilercircuit" function this works fine, accept in my view function I have to add str to each QuerySelectField to avoid a "translate error" here is my code

def addboilercircuit():
    form = AddBoilerCircuitForm()
    if form.validate_on_submit():
        boilercircuit = Boilercircuit(name=form.name.data,
                boiler_ID=str(form.boiler_ID.data), #here I have added "str"

I have searched all the forums for a similar problem but most relate to an add function, this has helped me clean upmy code (Thanks @sean) and many others. I hope my question is clear Thanks in advance

Paul


回答1:


The key thing to take in here is that the ORM backed fields actually deal in ORM objects, not scalar values for the value of the processed form fields. The evidence of that is in the query callable that you pass to the QuerySelectField constructor:

def boiler_ID():
    return Boilers.query

That is a query that returns Boilers instances, not integer ID values.

To sort it, add a relationship field on to your model called boiler and associate your form field to that. We also need to add a foreign key on boilercircuit.boiler_ID so the relationship can establish a join path to the boilers table.

# adds a `ForeignKey` constraint to `boiler_ID` and a `boiler` 
# relationship to your `BoilerCircuit` object.

class Boilercircuit(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    boiler_ID = db.Column(db.String(30), db.ForeignKey("boilers.id"))

    boiler = db.relationship("Boilers")

    def __repr__(self):
        return '<Boilercircuit {}>'.format(self.id)

Then modify the form:

# renames the `boiler_ID` field to `boiler` and also the field's label.
class AddBoilerCircuitForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired()])
    boiler = QuerySelectField('boiler',
                    query_factory=boiler_ID,
                    get_label='id')
    submit = SubmitField('Register')

You'll also need to change any references that you made to AddBoilerCircuitForm.boiler_ID throughout your views and templates as that field no longer exists on the form.



来源:https://stackoverflow.com/questions/58383945/flask-wtforms-queryselectfeld-form-populate-obj-fields-not-populated-and-if-fill

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!