Forums

Following flask tutorial, unhandled exception on my website after I tried to submit a comment

I'm at the section where I change comments = [] to actually connect to the database, and I have an unhandled exception error and I'm not sure what's wrong.

Here's my code: python-

# A very simple Flask Hello World app for you to get started with...
from flask import Flask, redirect, render_template, request, url_for
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["DEBUG"] = True

SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://{username}:{password}@{hostname}/{databasename}".format(
    username="4ndy456",
    password="<pass>",
    hostname="4ndy456.mysql.pythonanywhere-services.com",
    databasename="4ndy456$comments",
)
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
app.config["SQLALCHEMY_POOL_RECYCLE"] = 299
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

db = SQLAlchemy(app)

class Comment(db.Model):

    __tablename__ = "comments"

    id = db.Column(db.Integer, primary_key=True)
    content = db.column(db.String(4096))

@app.route('/', methods=["GET", "POST"])
def index():
    if request.method == "GET":
        return render_template("main_page.html", comments=Comment.query.all())
    comment = Comment(content=request.form["contents"])
    db.session.add(comment)
    db.session.commit()
    return redirect(url_for('index'))

HTML:

<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
        <title>My scratchboard page</title>
    </head>

    <body>
        <nav class="navbar navbar-inverse">
             <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>

                    </button>
                    <a class="navbar-brand" href="#">My scratchpad</a>
                </div>
            </div>
        </nav>

    <div class="container">
        {% for comment in comments %}
            <div class="row">
                {{ comment.content }}
            </div>
        {% endfor %}

        <div class ="row">
            <form action="." method="POST">
                <textarea class="form-control" name="contents" placeholder="Enter a comment"></textarea>
                <input type="submit" class="btn btn-success" value="Post comment">
            </form>
        </div>
    </div><!-- /.container -->
    </body>
</html>

[edit by admin: formatting]

Look in the error log for your web app. That's where you'll find out what the error is.

.

2018-01-09 00:11:51,676: Error running WSGI application
2018-01-09 00:11:51,678: AttributeError: 'String' object has no attribute 'lower'
2018-01-09 00:11:51,678:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1994, in __call__
2018-01-09 00:11:51,678:     return self.wsgi_app(environ, start_response)
2018-01-09 00:11:51,678: 
2018-01-09 00:11:51,679:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1985, in wsgi_app
2018-01-09 00:11:51,679:     response = self.handle_exception(e)
2018-01-09 00:11:51,679: 
2018-01-09 00:11:51,679:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1540, in handle_exception
2018-01-09 00:11:51,679:     reraise(exc_type, exc_value, tb)
2018-01-09 00:11:51,679: 
2018-01-09 00:11:51,680:   File "/usr/local/lib/python3.6/dist-packages/flask/_compat.py", line 33, in reraise
2018-01-09 00:11:51,680:     raise value
2018-01-09 00:11:51,680: 
2018-01-09 00:11:51,680:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1982, in wsgi_app
2018-01-09 00:11:51,681:     response = self.full_dispatch_request()
2018-01-09 00:11:51,681: 
2018-01-09 00:11:51,681:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1614, in full_dispatch_request
2018-01-09 00:11:51,681:     rv = self.handle_user_exception(e)
2018-01-09 00:11:51,681: 
2018-01-09 00:11:51,682:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1517, in handle_user_exception
2018-01-09 00:11:51,682:     reraise(exc_type, exc_value, tb)
2018-01-09 00:11:51,682: 
2018-01-09 00:11:51,682:   File "/usr/local/lib/python3.6/dist-packages/flask/_compat.py", line 33, in reraise
2018-01-09 00:11:51,682:     raise value
2018-01-09 00:11:51,682: 
2018-01-09 00:11:51,683:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1612, in full_dispatch_request
2018-01-09 00:11:51,683:     rv = self.dispatch_request()
2018-01-09 00:11:51,683: 
2018-01-09 00:11:51,683:   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1598, in
dispatch_request
2018-01-09 00:11:51,684:     return self.view_functions[rule.endpoint](**req.view_args)
2018-01-09 00:11:51,684: 
2018-01-09 00:11:51,684:   File "/home/4ndy456/mysite/flask_app.py", line 32, in index
2018-01-09 00:11:51,684:     return render_template("main_page.html", comments=Comment.query.all())
2018-01-09 00:11:51,684: 
2018-01-09 00:11:51,685:   File "/usr/local/lib/python3.6/dist-packages/flask/templating.py", line 134, in render_template
2018-01-09 00:11:51,685:     context, ctx.app)
2018-01-09 00:11:51,685: 
2018-01-09 00:11:51,685:   File "/usr/local/lib/python3.6/dist-packages/flask/templating.py", line 116, in _render
2018-01-09 00:11:51,685:     rv = template.render(context)
2018-01-09 00:11:51,686: 
2018-01-09 00:11:51,686:   File "/usr/local/lib/python3.6/dist-packages/jinja2/asyncsupport.py", line 76, in render
2018-01-09 00:11:51,686:     return original_render(self, *args, **kwargs)
2018-01-09 00:11:51,686: 
2018-01-09 00:11:51,686:   File "/usr/local/lib/python3.6/dist-packages/jinja2/environment.py", line 1008, in render
2018-01-09 00:11:51,687:     return self.environment.handle_exception(exc_info, True)
2018-01-09 00:11:51,687: 
2018-01-09 00:11:51,687:   File "/usr/local/lib/python3.6/dist-packages/jinja2/environment.py", line 780, in handle_exception
2018-01-09 00:11:51,687:     reraise(exc_type, exc_value, tb)
2018-01-09 00:11:51,687: 
2018-01-09 00:11:51,688:   File "/usr/local/lib/python3.6/dist-packages/jinja2/_compat.py", line 37, in reraise
2018-01-09 00:11:51,688:     raise value.with_traceback(tb)
2018-01-09 00:11:51,688: 
2018-01-09 00:11:51,688:   File "/home/4ndy456/mysite/templates/main_page.html", line 30, in top-level template code
2018-01-09 00:11:51,688:     {{ comment.content }}
2018-01-09 00:11:51,689: 
2018-01-09 00:11:51,689:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/elements.py", line 446, in __str__
2018-01-09 00:11:51,689:     return str(self.compile())
2018-01-09 00:11:51,689: 
2018-01-09 00:11:51,689:   File "<string>", line 1, in <lambda>
2018-01-09 00:11:51,690: 
2018-01-09 00:11:51,690:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/elements.py", line 436, in compile
2018-01-09 00:11:51,690:     return self._compiler(dialect, bind=bind, **kw)
2018-01-09 00:11:51,690: 
2018-01-09 00:11:51,690:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/elements.py", line 442, in _compiler
2018-01-09 00:11:51,691:     return dialect.statement_compiler(dialect, self, **kw)
2018-01-09 00:11:51,691: 
2018-01-09 00:11:51,691:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/compiler.py", line 435, in __init__
2018-01-09 00:11:51,691:     Compiled.__init__(self, dialect, statement, **kwargs)
2018-01-09 00:11:51,691: 
2018-01-09 00:11:51,692:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/compiler.py", line 216, in __init__
2018-01-09 00:11:51,692:     self.string = self.process(self.statement, **compile_kwargs)
2018-01-09 00:11:51,692: 
2018-01-09 00:11:51,692:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/compiler.py", line 242, in process
2018-01-09 00:11:51,692:     return obj._compiler_dispatch(self, **kwargs)
2018-01-09 00:11:51,692: 
2018-01-09 00:11:51,693:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
2018-01-09 00:11:51,693:     return meth(self, **kw)
2018-01-09 00:11:51,693: 
2018-01-09 00:11:51,693:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/compiler.py", line 697, in visit_column
2018-01-09 00:11:51,693:     name = self.preparer.quote(name)
2018-01-09 00:11:51,694: 
2018-01-09 00:11:51,694:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/compiler.py", line 2909, in quote
2018-01-09 00:11:51,694:     if self._requires_quotes(ident):
2018-01-09 00:11:51,694: 
2018-01-09 00:11:51,694:   File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/sql/compiler.py", line 2880, in _requires_quotes
2018-01-09 00:11:51,696:     lc_value = value.lower()

This is my error log, not sure what WSGI application is.

[edit by admin: formatting]

WSGI is a system for communicating between web servers and Python code, so Python code that runs a website can be called a "WSGI application" -- so in this case, it's just a way to refer to your code.

Anyway, the error you're getting is this bit:

'String' object has no attribute 'lower'

I was going to give a detailed step-by-step explanation of how you could get from that to working out what the error was, but actually it's a really obscure problem! I think it's being caused by a minor typo in your code; you have this:

content = db.column(db.String(4096))

where instead you should have this:

content = db.Column(db.String(4096))

Note the capital "C" on "Column".

Thank you so much! Sorry to keep bothering the forums with questions but another issue arose haha.

2018-01-09 20:13:21,098: sqlalchemy.exc.ProgrammingError: (mysql.connector.errors.ProgrammingError) 1054 (42S22): Unknown column 'comments.content' in 'field list' [SQL: 'SELECT comments.id AS comments_id, comments.content AS comments_content \nFROM comments']

I checked my MySQL console and this showed up:

mysql> show tables;
+----------------------------+
| Tables_in_4ndy456$comments |
+----------------------------+
| comments                   |
+----------------------------+
1 row in set (0.00 sec)
mysql> describe comments;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.00 sec)
mysql>

It should have two fields, id and content as per the tutorial but only the id field is shown, which i think would cause the error to show up. I have my account and my friend's account as I'm setting up a website and database for her too, and copied her working code (python and html) into my .py and .html files yet the issue is still there. Any way I could fix this?

[edit by admin: formatting]

I think that your table is missing the content column because that typo was present when you created it.

The easiest fix is probably to delete the table (run drop table comments; from your MySQL console), and then to go back to your bash console and go through the bit of the tutorial again where you run ipython3.6, import your code, then run db.create_all().

Thank you thank you thank you!

also for just in case I post here in the forums, how do I make code from mysql python or html pretty in those boxes?

No problem, glad to help!

To make the code pretty, just select it then click the "code" button above the test input field -- it's the one that says "101010". If it's Python code, you can also add a line above it with " :::python" (that's four spaces before the ":::") and it will do syntax-highlighting.