Complete many-to-one example using jar, WTForm, SQLAlchemy and Jinja2

Here is my HTML drop down menu. The value is the primary key of the child table.

<select id="category" name="category"> <option selected value="__None"></option> <option value="1">Category Number One</option> <option value="2">Category Number Two</option> </select> 

I need to update Post.category_id with integer 1 instead of "Category number one". Here is my code.

 # create new post @app.route('/admin/post', methods=['GET', 'POST']) @login_required # Required for Flask-Security def create_post(): form = PostForm() if form.validate_on_submit(): post = Post(title=form.title.data, body=form.body.data, pub_date=form.pub_date.data, cateogry_id=form.category.data) db.session.add(post) db.session.commit() flash('Your post has been published.') return redirect(url_for('admin')) posts = Post.query.all() return render_template('create_post.html', form=form, posts=posts) 

I tried to do ...

 cateogry_id=form.category.data cateogry_id=form.category.value 

Now that would be nice!

+8
python flask flask-wtforms flask-sqlalchemy wtforms
source share
1 answer

I get it! Here is my solution. Hope this post helps the closest guy.

The solution is to let the extension do the work for you! The following is a working example of a sqlalchemy WT Forms extension using Flask, WTForm, SQLAlchemy, and Jinja2. In short, you don’t have to worry about the child identifier, because the extension will take care of this automatically. this means that when you work with SQLAlchemy Parent and Child in a one-to-many relationship, you ONLY have to deal with PARENT.

MODEL

First, make sure your model and relationships are correct. Note in my example how relationships are defined and that in the init model there is only CATEGORY ... NOT CATEGORY_ID. My mistake was that I would fill in the CATEGORY_ID model field. Nope. The extension does this for you. In fact, if you try to do it manually, like me, it will not work at all.

 class Post(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(80)) url = db.Column(db.String(120)) body = db.Column(db.Text) create_date = db.Column(db.DateTime) pub_date = db.Column(db.DateTime) pub_status = db.Column(db.Text(80)) author_id = db.Column(db.Integer, db.ForeignKey('user.id')) author = db.relationship('User', backref=db.backref('posts', lazy='dynamic')) category_id = db.Column(db.Integer, db.ForeignKey('category.id')) category = db.relationship('Category', backref=db.backref('posts', lazy='dynamic')) def __init__(self, title, body, category, pub_date=None): self.title = title self.body = body if pub_date is None: pub_date = datetime.utcnow() self.category = category self.pub_date = pub_date def __repr__(self): return '<Post %r>' % self.title class Category(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50)) description = db.Column(db.String(250)) def __init__(self, name): self.name = name def __repr__(self): return self.name 

Secondly, check the form .... ATTENTION I am using wtfrom sqlalchmey QuerySelectedField and the Category_ID field is missing ...

THE FORM

 from sprucepress.models import Tag, Category from flask_wtf import Form from wtforms.fields import StringField, DateTimeField from wtforms.widgets import TextArea from wtforms.validators import DataRequired from wtforms.ext.sqlalchemy.orm import model_form from wtforms.ext.sqlalchemy.fields import QuerySelectField def enabled_categories(): return Category.query.all() class PostForm(Form): title = StringField(u'title', validators=[DataRequired()]) body = StringField(u'Text', widget=TextArea()) pub_date = DateTimeField(u'date create') category = QuerySelectField(query_factory=enabled_categories, allow_blank=True) 

Now the logic for routing and viewing FLASK ... Pay attention to the post NO category_id again! Only category !!!

GASKET / VIEW

 # create new post @app.route('/admin/post', methods=['GET', 'POST']) @login_required # required for Flask-Security def create_post(): form = PostForm() if form.validate_on_submit(): post = Post(title=form.title.data, pub_date=form.pub_date.data, body=form.body.data, category=form.category.data) db.session.add(post) db.session.commit() flash('Your post has been published.') return redirect(url_for('admin')) posts = Post.query.all() return render_template('create_post.html', form=form, posts=posts) 

Finally, the template. Guess what, we only generate the form.category field !!!

TEMPLATE

  <form action="" method=post> {{form.hidden_tag()}} <dl> <dt>Title: <dd>{{ form.title }} <dt>Post: <dd>{{ form.body(cols="35", rows="20") }} <dt>Category: <dd>{{ form.category }} </dl> <p> <input type=submit value="Publish"> </form> 

Result ... this solution correctly uses the category model as a lookup table and correctly binds Post columns by writing PK integers to the Posts Category_Id field. Yeeeehaww!

+7
source share

All Articles