这里有很多关于SO的问题,其标题听起来与我将要描述的类似,但据我从几个小时的研究中可以看出,这个问题是独一无二的。所以这里去了!
我正在编写我的第一个Flask应用程序。我正在使用SQLAlchemy作为模型层,使用WTForms来处理表单。该应用程序将成为一个轻量级的个人财务经理,我可能不会真正用于严肃的商业。我有一个表用于所有交易的列表,另一个表用于所有费用类别(杂货,服装等)。事务表有一个列(“类别”),它引用了Category表。在视图中,我表示带有元素的类别列表。
我的问题是,在编辑事务时,我无法弄清楚如何告诉WTForms将元素设置为特定的预定义值。 (是的,我知道您可以在定义表单时设置默认值,这不是我要求的。)
模型看起来像这样(删除了不相关的字段):
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False, unique=True)
# ...
class Trans(db.Model):
# ...
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
category = db.relationship('Category',
backref=db.backref('trans', lazy='dynamic'))
# ...
forms.py:
def category_choices():
return [('0', '')] + [(c.id, c.name) for c in Category.query.all()]
class TransactionForm(Form):
# ...
category = SelectField('Category', coerce=int, validators=[InputRequired()])
# ...
路线(POST尚未实施):
@app.route('/transactions/edit/<trans_id>', methods=['GET', 'POST'])
def trans_edit(trans_id):
transaction = Trans.query.get(trans_id)
form = forms.TransactionForm(obj=transaction)
form.category.choices = forms.category_choices()
form.category.default = str(transaction.category.id)
#raise Exception # for debugging
return render_template('trans.html',
title='Edit Transaction',
form=form)
最后,模板(Jinja2):
{{ form.category(class='trans-category input-medium') }}
正如您在路径中看到的,我从transaction.category.id设置了form.category.default,但这不起作用。我认为我的问题是我在创建表单后设置了“默认”。因为模型来自SQLAlchemy的数据库,所以我不得不这样做。根本原因似乎是form.category是一个对象(由于关系),WTForms似乎无法轻易处理。我不可能是第一个遇到这个问题的人......我是否需要重新设计模型以使WTForms更兼容?我有什么选择?
谢谢!
答案 0 :(得分:1)
我在评论中提到了这一点。听起来您可能会从使用WTForm的SQLAlchemy扩展中受益。这将为您的转换表单中的类别创建一个下拉列表。
我的示例用例略有不同。我将博客文章与主题联系起来。也就是说,许多帖子共享一个主题。在你的情况下我想象,许多交易共享一个类别。
<强>表格强>
from wtforms.ext.sqlalchemy.fields import QuerySelectField #import the ext.
def enabled_topics(): # query the topics (a.k.a categories)
return Topic.query.all()
class PostForm(Form): # create your form
title = StringField(u'title', validators=[DataRequired()])
body = StringField(u'Text', widget=TextArea())
topic = QuerySelectField(query_factory=enabled_topics, allow_blank=True)
<强>模型强> 这里的重要部分是a)确保正确定义了关系,并且b。)将主题添加到init,因为您使用它来创建新条目。
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80))
body = db.Column(db.Text)
# one-to-many with Topic
topic = db.relationship('Topic', backref=db.backref('post', lazy='dynamic'))
def __init__(self, title, body, topic):
self.title = title
self.body = body
self.topic = topic
class Topic(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
def __init__(self, name):
self.name = name
查看强> 这里没什么特别的。只是一个生成表单并处理提交结果的常规视图。
@app.route('/create', methods=['GET', 'POST'])
@login_required
def create_post():
form = PostForm()
if form.validate_on_submit():
post = Post(title=form.title.data, body=form.body.data,
topic=form.topic.data)
db.session.add(post)
db.session.commit()
Topic.update_counts()
flash('Your post has been published.')
return redirect(url_for('display_post', url=url))
posts = Post.query.all()
return render_template('create_post.html', form=form, posts=posts)
<强>模板强> 这里没什么好看的。只需确保在模板中渲染字段,就像在基本字段中一样。由于WTForms Sqlalchemy扩展功能可以满足您的需求,因此无需花哨的循环。
{% extends "base.html" %}
{% block title %}Create/Edit New Post{% endblock %}
{% block content %}
<H3>Create/Edit Post</H3>
<form action="" method=post>
{{form.hidden_tag()}}
<dl>
<dt>Title:
<dd>{{ form.title }}
<dt>Post:
<dd>{{ form.body(cols="35", rows="20") }}
<dt>Topic:
<dd>{{ form.topic }}
</dl>
<p>
<input type=submit value="Publish">
</form>
{% endblock %}
那就是它!现在我的帖子表单有一个主题下拉列表。要使用您的术语,在加载事务时,该事务的默认类别将在下拉列表中突出显示。说明这一点的正确方法是通过trans模型中定义的关系加载与事务关联的类别。
另请注意,如果一个事务有多个默认值,那么还有一个多选SQLAlchemy扩展名。类别。
现在,我的问题是如何处理多对多关系....我试图将存储在多对多表中的一串标记传递给TextArea字段。没有SQLAlchemy扩展!
我发布了这个问题here