12
votes

I am able to add a new entry to my database using WTForms and Flask and I can edit too, the problem is that I need to display the already existing information in the database in an edit form.

I have the following code:

A Class For the Edit Post Form

class editPostForm(Form):
    postTitle = TextField('postTitle', validators.Required()])
    postSubtitle = TextField('postSubtitle', validators.Required()])

A Route for the Edit Post Template

@app.route('/editpost/<postId>', methods = ['GET','POST'])
def editpost_page(postId):
try:
    form = editPostForm(form)

    if request.method == "POST" and form.validate():
        postTitle = form.postTitle.data
        postSubtitle = form.postSubtitle.data

        c, conn = connection()

        query = c.execute("SELECT * FROM posts WHERE post_id = (%s)",
                          [noinjection(postId)])

        c.execute("UPDATE posts SET post_title=%s, post_subtitle=%s WHERE post_id = %s",
                     [
                     noinjection(postTitle),
                     noinjection(postSubtitle),
                     noinjection(postId)
                     ])

        conn.commit()

        flash("Post Edited", 'success')

        c.close()
        conn.close()
        gc.collect()

        return redirect(url_for('posts'))

    return render_template("editpost.html", form = form, POST_ID = postId)

except Exception as e:
    return(str(e))

The Edit Post Template {jinja}

{% extends "header.html" %}

{% block body %}

<body>
    <div class="container-fluid">
        <br />
        <h4>Edit Post</h4>
        <br />
        {% from "_formhelpers.html" import render_field %}
        <form action="/editpost/{{ POST_ID }}" class="form-horizontal" method="post">
            {% from "_formhelpers.html" import render_field %}
            <form action="/editpost/" method="post">
              <div class="form-group">
                <label for="postTitle">Post Title</label>
                <input type="text" class="form-control" id="postTitle" name="postTitle" placeholder="Post Title" value="{{request.form.postTitle}}">
              </div>
              <div class="form-group">
                <label for="postSubtitle">Post Subtitle</label>
                <input type="text" class="form-control" id="postSubtitle" name="postSubtitle" placeholder="Post Subtitle" value="{{request.form.postSubtitle}}">
              </div>
              <button type="submit" class="btn btn-default">Submit</button>
            </form>
            {% if error %}
                <p class="error"><strong>Error: </strong>{{error}}</p>
            {% endif %}
        </form>
        {% if error %}
            <p class="error"><strong>Error: </strong>{{error}}</p>
        {% endif %}

    </div>
</body>

{% endblock %}

With the following code, I am getting a selected post to update in the database, but the editpost template is not showing the values which are already in the database and all the fields are blank.

How can I pre-populate the form before editing?

2
Yes but the manual is referring to an object, which I don't know how to use. Maybe I need to learn how to set that object but I cannot seem to find the proper information on how to create the object with the data, or I'm not using the right keywords to search online.Eric
Did you really mean form = editPostForm(form)? Seems like you're referencing form before assignment.fearless_fool

2 Answers

22
votes

You can populate each field separately like this:

form = editPostForm(form)
form.postTitle.data = postTitle_from_database
form.postSubtitle.data = postSubtitle_from_database

or you can populate your form fields from a given object using process method:

process(formdata=None, obj=None, **kwargs)

Take form, object data, and keyword arg input and have the fields process them.

Parameters:

  • formdata – Used to pass data coming from the enduser, usually request.POST or equivalent.
  • obj – If formdata has no data for a field, the form will try to get it from the passed object.
  • **kwargs – If neither formdata or obj contains a value for a field, the form will assign the value of a matching keyword argument to the field, if provided.

Since BaseForm does not take its data at instantiation, you must call this to provide form data to the enclosed fields. Accessing the field’s data before calling process is not recommended.

6
votes

I was able to pre-populate HTML input and textarea fields from a SQL database with Python and Jinja as follows:

1. Store relevant data from database in a variable:

    name = db.execute("""SELECT name FROM users WHERE id = :id""", id=session["user_id"])

    about = db.execute("""SELECT about FROM users WHERE id = :id""", id=session["user_id"])

2. Render template (with render_template function) and pass in the relevant variables:

return render_template("edit.html", name = name, about = about)

3. Pass variables via jinja to html input and textarea elements. Index into the object that has been passed as follows:

For an input tag use the value attribute as below:

    <input type="text" class="form-control" name="name" value="{{ name[0]["name"] }}">

For a textarea element:

    <textarea class="form-control" name="about">{{ about[0]["about"] }}</textarea>