如何使用Flask、jinja更新表单?

问题描述 投票:0回答:1

型号

class ContentOwner(db.Model):
    id = db.Column(db.String,primary_key=True, default=lambda: str(uuid.uuid4()))
    owner = db.Column(db.String(128), index=True)
    reference_code = db.Column(db.String(128), index=True)
    target_id = db.Column(db.Integer, db.ForeignKey('target.id'))
    def __repr__(self):
        return self.name

表格

class AddContentOwnerForm(FlaskForm):
    owner = StringField('Owner name')
    reference_code = StringField('reference code')
<div class="col-lg-4">
            <div class="card">
                <div class="card-header">{{ gettext('Content Owners')}}<button class="btn btn-sm btn-outline-success float-end" href="#" data-bs-toggle="modal" data-bs-target="#addContentOwnermodal">Add</button></div>
                <div class="card-body">
                    <table class="table">
                        <thead>
                        <th>Name</th>
                        <th>Ref Code</th>
                        </thead>
                        <tbody>
                          {% for owner in owners %}
                        <tr>
                            <td>{{owner.owner}}</td>
                            <td>{{owner.reference_code}}</td>
                            <td><button class="btn btn-outline-primary btn-sm float-end" href="{{ url_for('editOwner', id=owner.id) }}" data-bs-toggle="modal" data-bs-target="#editOwnerModal">Edit</button></td>
                            <td> <a href="{{url_for('deleteOwner', id=owner.id)}}" class="btn btn-outline-danger btn-sm float-end">Delete</a></td>
                        </tr>
                        {% endfor %} 
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

edit_owner_modal.html


<div class="modal fade" id="editOwnermodal" tabindex="-1" aria-labelledby="editOwnermodalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="editOwnerModalLabel">{{ gettext('Edit Owner')}}</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form method='POST' action="{{url_for('editOwner', id=owner.id)}}">
                    {{ AddContentOwnerForm.csrf_token }}
                    <input type="hidden" name="type" value="editOwner">
                    
                    <div class="input-group mb-3">
                        <span class="input-group-text">{{ gettext('Name')}}</span>
                        <input type="text" class="form-control" name="owner" value="{{owner.owner}}">
                    </div>
                    <div class="input-group mb-3">
                        <span class="input-group-text">{{ gettext('Reference Code')}}</span>
                        <input type="text" class="form-control" name="reference_code" value="{{owner.reference_code}}">
                    </div>
                    
                    <div class="d-grid col-12 mx-auto">
                        <button class="btn btn-outline-secondary" type="submit">{{ gettext('Update')}}</button>
                    </div>
                </form>
            </div>
            
            <div class="modal-footer">
                <button type="button" class="btn btn-outline-primary" data-bs-dismiss="modal">{{ gettext('Close')}}</button>
            </div>
        </div>
    </div>
</div>


路线.py

@app.route('/editowner/<id>', methods=['GET', 'POST'])
def editOwner(id):
    owner = ContentOwner.query.get_or_404(id)
    if request.method == 'POST':
        owner.owner = request.form['owner']
        owner.reference_code = request.form['reference_code']
        db.session.commit()
        return redirect(url_for('administration'))
    return render_template('edit_owner_modal.html', owner=owner, id=id)

@app.route('/administration', methods=['GET', 'POST'])
def administration():
    addcontentownerform = AddContentOwnerForm()

    if request.method == 'POST':  
        if request.form['type'] == 'addContentOwner':
            if addcontentownerform.validate_on_submit():
                content_owner = ContentOwner(owner=addcontentownerform.owner.data, 
                                 reference_code=addcontentownerform.reference_code.data)
                db.session.add(content_owner)
                db.session.commit()
                flash(f"Added Owner '{addcontentownerform.owner.data}'", "alert-success")
                return redirect(url_for('administration'))
         elif request.form['type'] == 'editOwner': 
            if addcontentownerform.validate_on_submit():
                id = request.form.get('id')
                owner = ContentOwner.query.get_or_404(id)
                owner.owner = request.form['owner']
                owner.reference_code = request.form['reference_code']
                db.session.commit()
                flash('Owner details updated successfully.', 'success')
                return render_template('administration.html', id=id)
                    
       
    owners = db.session.query(ContentOwner).all()
    owner = db.session.query(ContentOwner).all()
    return render_template('administration.html',AddCrawlerForm=addcrawlerform, EditContentOwnerForm=editcontentownerform, AddUserForm=adduserform, AddJobForm=addjobform, AddContentOwnerForm=addcontentownerform, crawlers=crawlers, users=users, jobs=jobs, owners=owners, owner=owner)

当我单击编辑按钮时,表单尚未填写以进行更新,并且单击更新时会引发 404 错误。救命!!!

我认为表单(模态)没有获取所有者 ID 详细信息。不确定管理页面访问路线是否有错误(editOwner)

python html forms flask jinja2
1个回答
0
投票

在模态中嵌入这种类型的表单并不是最佳选择,特别是因为我认为您想在单个模态上分配多个条目。更建议将任务分布在多个页面上。

尽管如此,还是有可能制定出可行的解决方案。

以下最小示例根据所有者的 ID 使用 AJAX 加载模式的内容。如果要显示表单,则从相应按钮中提取带有 id 的属性,并将 GET 请求发送到路由进行编辑。来自服务器的响应是已填写的表单,该表单将添加到模式中。如果现在通过 POST 请求发送表单,则根据条目是否有效,可以更新数据库或显示错误消息。

烧瓶(./app.py)
from flask import (
    Flask, 
    flash, 
    redirect, 
    render_template, 
    request, 
    url_for
)
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField
import uuid

app = Flask(__name__)
app.config.from_mapping(
    SECRET_KEY='your secret here', 
    SQLALCHEMY_DATABASE_URI='sqlite:///example.db'
)
db = SQLAlchemy(app)

class ContentOwner(db.Model):
    id = db.Column(db.String,primary_key=True, default=lambda: str(uuid.uuid4()))
    owner = db.Column(db.String(128), index=True)
    reference_code = db.Column(db.String(128), index=True)
    # ...

class AddContentOwnerForm(FlaskForm):
    owner = StringField('Name')
    reference_code = StringField('Ref Code')

with app.app_context():
    db.drop_all()
    db.create_all()

    content_owner = ContentOwner(
        owner='Unknown', 
        reference_code='12345678'
    )
    db.session.add(content_owner)
    content_owner = ContentOwner(
        owner='Unknown 1', 
        reference_code='abcdefgh'
    )
    db.session.add(content_owner)
    db.session.commit()

@app.route('/edit-owner/<uuid:id>', methods=['GET', 'POST'])
def edit_owner(id):
    owner = ContentOwner.query.get_or_404(str(id))
    form = AddContentOwnerForm(request.form, obj=owner)
    if request.method == 'POST': 
        if form.validate():
            form.populate_obj(owner)
            db.session.commit()
        else:
            for k,v in form.errors.items(): 
                for error in v:
                    flash(f'{k}: {error}', 'danger')
        return redirect(url_for('administration'))
    return render_template('edit_owner_modal.html', **locals())

@app.route('/administration')
def administration():
    owners = ContentOwner.query.all()
    return render_template('administration.html', **locals())
HTML (./templates/administration.html)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Administration</title>
    <link 
        rel="stylesheet" 
        href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" 
        integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" 
        crossorigin="anonymous"></head>
<body>
    <main class="container mt-4">

        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                <div class="alert alert-{{ (category,'primary')[category == 'message'] }} alert-dismissible fade show" role="alert">
                  {{ message }}
                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                </div>
                {% endfor %}
            {% endif %}
        {% endwith %}
        
        <table class="table">
            <thead>
                <th>Name</th>
                <th>Ref Code</th>
                <th></th>
            </thead>
            <tbody>
                {% for owner in owners -%}
                <tr>
                    <td>{{owner.owner}}</td>
                    <td>{{owner.reference_code}}</td>
                    <td>
                        <button 
                            class="btn btn-outline-primary btn-sm float-end" 
                            data-id="{{ owner.id }}" 
                            data-bs-toggle="modal" 
                            data-bs-target="#editOwnerModal">Edit</button>
                    </td>
                </tr>
                {% endfor -%} 
            </tbody>
        </table>

    </main>

    <div class="modal fade" id="editOwnerModal" tabindex="-1" aria-labelledby="editOwnerModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="editOwnerModalLabel">Edit Owner</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                
                <div class="modal-body"></div>

                <div class="modal-footer">
                    <button type="button" class="btn btn-outline-primary" data-bs-dismiss="modal">Close</button>
                </div>
            </div>
        </div>
    </div>

    <script 
        src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" 
        integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" 
        crossorigin="anonymous"></script>
    <script>
        (function() {
            const myModalEl = document.getElementById('editOwnerModal');
            myModalEl.addEventListener('show.bs.modal', event => {
                const relatedTarget = event.relatedTarget;
                const id = relatedTarget.dataset.id; 
                const modalBody = document.querySelector('#editOwnerModal .modal-body');
                modalBody.innerHTML = '<p style="text-align: center;">... Loading data ...</p>';
                fetch(`/edit-owner/${id}`)
                    .then(resp => resp.ok && resp.text())
                    .then(text => text && (modalBody.innerHTML = text));
            });
        })();
    </script>
</body>
</html>
HTML (./templates/edit_owner_modal.html)
<form method='POST' action="{{url_for('edit_owner', id=owner.id)}}">
    {{ form.csrf_token }}
    <div class="input-group mb-3">
        {{ form.owner.label(class_='input-group-text') }}
        {{ form.owner(class_='form-control') }}
    </div>
    <div class="input-group mb-3">
        {{ form.reference_code.label(class_='input-group-text') }}
        {{ form.reference_code(class_='form-control') }}
    </div>
    <div class="d-grid col-12 mx-auto">
        <button class="btn btn-outline-secondary" type="submit">Update</button>
    </div>
</form>
© www.soinside.com 2019 - 2024. All rights reserved.