Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Andy Hughes
Andy Hughes
8,479 Points

Forms, tables, throwing validation error [Solved]

So I've mastered copying from a video and have built the social app, which seems to work just as it should.

However, I'm now trying to apply the learning and create some additional tables, forms etc and I'm getting some errors I can't understand. I'll try to explain what I'm doing and include the code.

  1. I created what I think is a model/function in app.py that will create a route to the form and validate on submission.
  2. I created the html template that the user will submit the data through.
  3. I created the function/class method that creates the database table and process the form data.
  4. I've created the python forms to go with the html template

When I run the app, I get the following error:

Traceback (most recent call last):
  File "app.py", line 7, in <module>
    import forms
  File "D:\Dropbox\Coding Projects\learner-driver-app\forms.py", line 62, in <module>
    class StandardForm(FlaskForm):
  File "D:\Dropbox\Coding Projects\learner-driver-app\forms.py", line 64, in StandardForm
    standard = TextAreaField('Enter the standard to be added', validators=[DataRequired])
  File "D:\business\python-development\anaconda3\lib\site-packages\wtforms\fields\core.py", line 33, in __new__
    return UnboundField(cls, *args, **kwargs)
  File "D:\business\python-development\anaconda3\lib\site-packages\wtforms\fields\core.py", line 384, in __init__
    self.field_class.check_validators(validators)
  File "D:\business\python-development\anaconda3\lib\site-packages\wtforms\fields\core.py", line 185, in check_validators
    raise TypeError(
TypeError: <class 'wtforms.validators.DataRequired'> is not a valid validator because it is a class, it should be an instance

The error makes me think that I've incorrectly created the forms and validators, but I have copied these from other forms created in the social app. So I can't see why they would cause an error. So I'm wondering if this is one of those situations where the error is not the actual error but rather a stalling point. I've tried to read the documention and look on stack overflow, but I can't find anything the same or that makes it clear what the error is.

I am including my code below. Just the bit's I have built, not the entire files as that's lot's of code! However, if anyone feels it necessary to helping me fix the problems then I can include it later.

Also, an additional error is that my template "standards.html" throws a 404 error. Again I've copied the format from another function so not sure why it doesn't find the template.

Thanks in advance.

app.py

@app.route('/add_standard', methods=('GET', 'POST'))
@login_required
def set_standard():
    form = forms.StandardForm()
    if form.validate_on_submit():
        models.Standards.create(user=g.user._get_current_object(),
                                content=form.content.data.strip())
        flash("Standard created! Thanks!", "success")
        return redirect(url_for('index'))
    return render_template('standards.html', form=form)

models.py

class Standards(Model):
    section = CharField(unique=False)
    standard = CharField(unique=True)

    class Meta:
        database = DATABASE


    @classmethod
    def create_standard(cls, section, standard):
        try:
            with DATABASE.transaction():
                cls.create(
                    section=section,
                    standard=standard
                )
        except IntegrityError:
            raise ValueError("Standard already exists")


class Faults(Model):
    section = CharField()
    fault = CharField()

    class Meta:
        database = DATABASE


    @classmethod
    def create_faults(cls, section, fault):
        try:
            with DATABASE.transaction():
                cls.create(
                    section=section,
                    fault=fault
                    )
        except IntegrityError:
            raise ValueError("Fault already exists")

forms.py

class StandardForm(FlaskForm):
    section = TextAreaField('Set section title', validators=[DataRequired()])
    standard = TextAreaField('Enter the standard to be added', validators=[DataRequired])


class FaultForm(FlaskForm):
    section = TextAreaField('Set section title', validators=[DataRequired])
    fault = TextAreaField('Enter fault', validators=[DataRequired])

standards.html

{% extends "layout.html" %} {% from 'macros.html' import render_field %} {% block content %}
<form method="POST" action="">
    {{ form.hidden_tag() }} {% for field in form %} {{ render_field(field) }} {% endfor %}
    <button type="submit" id="submit">Add Standard</button>
</form>
{% endblock %}

Any questions, please ask and I'll give whatever info I can :)

Andy Hughes
Andy Hughes
8,479 Points

Ok so I think I've managed to identify the problems, just in case anyone else is trying to do the same as me.

So the error:

TypeError: <class 'wtforms.validators.DataRequired'> is not a valid validator because it is a class, it should be an instance

was indeed referring to the fact that in my code above, I have called DataRequired instead of DataRequired(). So without the parenthesis it's just a classname and I should have been creating an instance. I only picked this up because, out of the four similar lines of code, one has the parenthesis. It's seeing this that made me realise what the error was telling me.

Note to self: understand what the error message is saying in literal terms!

With that fixed, my form showed up and it allowed me to enter data. On submit however, I got a new error. This error was in relation to the model processing the form data to the database.

If you look in my app.py you will see the code that I copied from the "post" model. Then I just changed the "route, function name and form name to match my requirements, which is absolutely right and correct. However, I had missed a major element in this code. The code is processing data to the database table! When I looked at my code (code above in app.py) I realised, it would be processing data to a "User" column and "Content" column.......which aren't columns in my table.

So I then looked at each element of the code and started to think about my columns and changed my code to the following:

models.Standards.create_standard(
            section=form.section.data,
            standard=form.standard.data
        )

So what I realised is........my columns were "section" and "standard" so they need to replace the old "User" and "Content" columns. form is still correct, but I also needed to change bit between "form.<xxxx>.data" to the column names.

Once I'd done all of that, I tested my form, checked the table and it's now working and the data is where it should be.

What this has really taught me though, is that you just can't learn from copying a video. It gives you a starting base for understanding terms, phrases, structure and a bit of rationale. However, it's only when you try to code something yourself with no pre-built answer to check against, that you really start to learn.

This was really frustrating but utterly useful. :)

Good job finding the source of the error. I completely agree with you about not being able to really understand something by just copying from a video. This is my single greatest frustration with online learning. The only way I really learn stuff is by banging my head against an issue for a while trying to grasp why it won't work when it looks like it should, and doing lots of research around the issue to try to figure it out. Videos take out this element of effort and involvement, which not only keeps you from really learning stuff, but also makes it so you forget the simple stuff because you're not having to type it over and over. I would recommend that you also check out some other sites that allow you to apply your knowledge like codewars. I know there are other sites like it, but that's the one I'm familiar with. There, they give you a challenge, and it's up to you to code it. Once you've solved the challenge, then you can see how others solved it and compare the way you did it to the way others did it. I find it incredibly useful for helping me think through issues and also for learning better ways to create solutions.

1 Answer

Andy Hughes
Andy Hughes
8,479 Points

Jason Larson - I've loved the videos, because the trainers are all pretty engaging and compared to many sites, it feels more like a classroom learning session. But I totally agree, there is something missing which is the application of the learners own lateral thinking in coding, testing and error resolution. Hugely satisfying to know you've fixed something yourself. Even more satisfying when you created your own code and then managed to fix it, without help.

I think treehouse would benefit their users a lot by introducing the codewars type thing. Maybe give students an opportunity to form code hubs, where they collectively work on code challenges. I used to find my university study group invaluable for aiding my understanding of theory.

Thanks for your comment and advice. :)