kvesteri / wtforms-alchemy

Tools for creating wtforms from sqlalchemy models
Other
245 stars 59 forks source link

meta config seems to be getting ignored #90

Open SkyLeach opened 8 years ago

SkyLeach commented 8 years ago

I'm at a loss here. The entire meta confguration seems to just be getting ignored in my code (testing wtforms-alchemy for generalized model forms handling)

stackoverflow link: http://stackoverflow.com/questions/34028546/wtforms-alchemy-meta-configuration-doesnt-seem-to-be-working

local copy:

Looking at the below code, you should see that in the _modelforms.py file I have set the Meta child class include_primary_keys = True and the only list (which should limit showing any field other than those explicitly marked). The resulting form should show only the cve_id field (one text field input) but instead the form is being rendered with the notes and references fields and the cve_id field simply isn't there. It isn't in the html result at all either (not hidden).

relevant classes from models.py

    # coding: utf-8
    from sqlalchemy import Column, DateTime, Float, ForeignKey, Index, Numeric, String, Table, Text, CLOB
    from sqlalchemy.orm import relationship
    from sqlalchemy.ext.declarative import declarative_base

    Base = declarative_base()
    metadata = Base.metadata

    from sqlalchemy.sql.functions import GenericFunction
    class XMLTypeFunc(GenericFunction):
        type=CLOB
        name='XMLType'
        identifier='XMLTypeFunc'

    class GetClobVal(GenericFunction):
        type=CLOB
        name='XMLType.GetClobVal'
        identifier='XMLTypeFunc'

    from sqlalchemy.types import TypeDecorator
    from lxml import etree
    class XMLType(TypeDecorator):

        impl = CLOB
        type = 'XMLTYPE' #etree.Element

        def bind_processor(self, dialect):
            def process(value):
                if value is not None:
                    return etree.tostring(value, encoding='UTF-8', pretty_print='True')
                else:
                    return None
            return process

        def bind_expression(self, bindvalue):
            return XMLTypeFunc(bindvalue, type_=self)

        def column_expression(self, colexpr):
            return GetClobVal(colexpr, type_=self)

    class CvmsCveDetail(Base):
        __tablename__ = 'cvms_cve_detail'

        cve_id = Column(String(20), nullable=False, primary_key=True)
    #    notes = Column(CLOB)
    #    references = Column(CLOB)
        notes = Column(XMLType)
        references = Column(XMLType)

        def getIO(self):
            from io import StringIO
            self.notesIO = StringIO(self.notes)
            self.referencesIO = StringIO(self.references)
            return (self.notesIO,self.referencesIO)

        def __init__(self, elem=None):
            if elem is not None: #we are being initialized with an lxml element, assume it's in CVE export format
                for child in elem:
                    #for CVE dump the text name
                    if etree.QName(child.tag).localname.upper() == 'CVE':
                        self.cve_id="".join(child.itertext())
                    #for the rest, our typedecorator should take the etree class directly
                    else:
                        if etree.QName(child.tag).localname.upper() == 'NOTES':
                            self.notes = child #etree.tostring(child, encoding='UTF-8', pretty_print='True')
                        elif etree.QName(child.tag).localname.upper() == 'REFERENCES':
                            self.references = child #etree.tostring(child, encoding='UTF-8', pretty_print='True')

from _modelforms.py

    # form wrappers for the model.

    from flask.ext.wtf import Form
    from wtforms_alchemy import model_form_factory

    ModelForm = model_form_factory(Form)

    from .models import CvmsCveDetail

    from wtforms import StringField, \
        BooleanField, \
        PasswordField, \
        SubmitField, \
        RadioField, \
        FieldList, \
        FormField, \
        SelectField, \
        TextField
    from wtforms.validators import DataRequired

    class CvmsCveDetailForm(ModelForm):
        class Meta:
            # use/show only the following fields
            include_primary_keys = True
            only = ['cve_id']
            model = CvmsCveDetail
        # cve_id = TextField(validators=[DataRequired()])

in my blueprint module _simplestubs.py:

    from flask import Flask, \
        Blueprint, \
        session, \
        redirect, \
        url_for, \
        escape, \
        request, \
        current_app

    from flask import render_template, Response
    import itertools
    import pprint
    import traceback
    stubs = Blueprint('stubs', __name__)

    from flask.ext.wtf import Form
    from wtforms import StringField, \
        BooleanField, \
        PasswordField, \
        SubmitField, \
        RadioField, \
        FieldList, \
        FormField, \
        SelectField

    from wtforms.validators import DataRequired

    ###################################################
    # blueprint module pre-configuration helpers
    ###################################################
    from .model_forms import *

    @stubs.route('/cve_lookup', methods=['GET', 'POST'])
    def cve_lookup():
        db = current_app.config['db']
        form = CvmsCveDetailForm(request.form)
        if request.method == 'POST' and apiform.validate():
            try:
                CvmsCveDetail.query.one(form.cve_id.data)
            except:
                traceback.print_exc()
        return render_template('dumbform.html', form=form,
            action_endpoint='stubs.cve_lookup',
            action_text='Lookup CVE',
            form_class='dumbclass')

finally, my template call is pretty simple...

from dumbform.html

    {% extends 'base.html' %}
    {# macro import for bootstrap-enabled field rendering #}
    {% import 'bootstrap3_form_macros.html' as macros %}
    {% block content %}
        <div class="container">
            <div class="panel panel-primary panel-green">
                <div class="panel panel-heading panel-green">
                    <span>{{ action_text }}</span>
                </div>
                <div class="panel apiform-panel form-group panel-body">
                    {% call macros.render_form(form,
                        action_url=url_for(action_endpoint),
                        action_text=action_text,
                        class_=form_class)
                     %}
                        {#  SPECIFIC FIELD HANDLING HERE #}
                        {# { macros.render_field(form.cve_id) } #}
                        {% for field in form %}
                            {{ macros.render_field(field) }}
                        {% endfor %}
                    {% endcall %}
                </div>
            </div>
        </div>
    {% endblock %}

the resulting html:

    <div class="container">
        <div class="panel panel-primary panel-green">
            <div class="panel panel-heading panel-green">
                <span>Lookup CVE</span>
            </div>
            <div class="panel apiform-panel form-group panel-body">
                <form method="POST" action="/cve_lookup" role="form" class="dumbclass">
        <div style="display:none;"><input id="csrf_token" name="csrf_token" type="hidden" value="1448999065##0baa56a31ec10b28d8d826ad7fb1ec2f9a016190"></div>
                        <div class="form-group  ">
        <input class="form-control" id="csrf_token" name="csrf_token" type="hidden" value="1448999065##0baa56a31ec10b28d8d826ad7fb1ec2f9a016190">
    </div>
                        <div class="form-group  ">
            <label for="notes" class="control-label"><label for="notes">notes</label></label>
        <textarea class="form-control" id="notes" name="notes"></textarea>
    </div>
                        <div class="form-group  ">
            <label for="references" class="control-label"><label for="references">references</label></label>
        <textarea class="form-control" id="references" name="references"></textarea>
    </div>
        <button type="submit" class="btn btn-default">Lookup CVE </button>
    </form>
            </div>
        </div>
    </div>