【问题标题】:Why is the database of the webapp in the book "Head First Python 2nd Edition" not working as it should?为什么《Head First Python 2nd Edition》一书中的 webapp 的数据库不能正常工作?
【发布时间】:2022-06-14 01:23:03
【问题描述】:

我目前正在通过阅读《Head First Python 2nd Edition》这本书来学习 Python,它确实很有帮助并且写得很好,但我认为它有点不合时宜(因为它于 2016 年 12 月 16 日发布,我认为从那时起各种事情发生了变化)。

问题是:我刚刚写完(到目前为止我必须做的)webapp vsearch4web.py,它看起来像这样:

from flask import Flask, render_template, request, escape
from vsearch import search4letters

from DBcm import UseDatabase

app = Flask(__name__)


app.config['dbconfig'] = {'host': '127.0.0.1',
                          'user': 'vsearch',
                          'password': 'vsearchpasswd',
                          'database': 'vsearchlogDB', }


def log_request(req: 'flask_request', res: str) -> None:
    """Log details of the web request and the results"""

    with UseDatabase(app.config['dbconfig']) as cursor:
        _SQL = """insert into log
              (phrase, letters, ip, browser_string, results) 
              values
              (%s, %s, %s, %s, %s)"""
        cursor.execute(_SQL, (req.form['phrase'],
                              req.form['letters'],
                              req.remote_addr,
                              req.user_agent.browser,
                              res, ))
    
@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
    phrase = request.form['phrase']
    letters = request.form['letters']
    title = 'Here are your results:'
    results = ''.join(search4letters(phrase, letters))
    log_request(request, results)
    return render_template('results.html',
                           the_title=title,
                           the_phrase=phrase,
                           the_letters=letters,
                           the_results=results,)


@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
    return render_template('entry.html',
                           the_title='Welcome to search4letters on the web!')


@app.route('/viewlog')
def view_the_log() -> 'html':
    with UseDatabase(app.config['dbconfig']) as cursor:
        _SQL = """Select phrase, letters, ip, browser_string, results
                  from log"""
        cursor.execute(_SQL)
        contents = cursor.fetchall()
    titles = ('Phrase', 'Letters', 'Remote_addr', 'User_agent', 'Results')
    return render_template('viewlog.html',
                           the_title='View Log',
                           the_row_titles=titles,
                           the_data=contents,)


if __name__ == '__main__':
    app.run(debug=True)

这是我在代码中使用的类:

import mysql.connector

class UseDatabase:

    def __init__(self, config: dict) -> None:
        self.configuration = config

    def __enter__(self) -> 'cursor':
        self.conn = mysql.connector.connect(**self.configuration)
        self.cursor = self.conn.cursor()
        return self.cursor

    def __exit__(self, exc_type, exc_value, exc_trace) -> None:
        self.conn.commit()
        self.cursor.close()
        self.conn.close()

然后我在 MySQL 控制台中创建了数据库 "vsearchlogDB",然后(以用户 "vsearch" 的身份登录),我创建了表 “log”(准确输入书上写的内容,即使结果表略有不同,这也是我之前说这本书可能有点不合时宜的原因):

(这是书中显示的表格):

现在,当我在本地运行我的 webapp 并尝试时,会出现此错误:

mysql.connector.errors.IntegrityError: 1048 (23000): 列'browser_string'不能为空

谁能解释一下为什么代码无法提取 browser_string 的值?

我尝试从头开始重新创建表并将 browser_string 列设置为空,实际上在 browser_string 列中(在 /viewlog 页面中)它总是显示 None(即使我认为这是一个无用的测试,因为我不知道如何使用 MySQL),但它不应该是这样的,有人可以解释一下吗?

这里我还添加了webapp的(所有)页面的HTML和CSS代码(对不起所有代码,但我真的不知道问题出在哪里):

base.html:

<!doctype html>

<html>

    <head>
    
        <title>{{ the_title }}</title>
        
        <link rel="stylesheet" href="static/hf.css" />
        
    </head>
    
    <body>
    
        {% block body %}
        

        {% endblock %}
    </body>
    
</html>

entry.html:

{% extends 'base.html' %}

{% block body %}

<h2>{{ the_title }}</h2>

<form method='POST' action='/search4'>
<table>
<p>Use this form to submit a search request:</p>
<tr><td>Phrase:</td><td><input name='phrase' type='TEXT' width='60'></td></tr>
<tr><td>Letters:</td><td><input name='letters' type='TEXT' value='aeiou'></td></tr>
</table>
<p>When you're ready, click this button:</p>
<p><input value="Do it!" type="submit"></p>
</form>

{% endblock %}

结果.html:

{% extends 'base.html' %}

{% block body %}

<h2>{{ the_title }}</h2>

<p>You submitted the following data:</p>
<table>
<tr><td>Phrase:</td><td>{{ the_phrase }}</td></tr>
<tr><td>Letters:</td><td>{{ the_letters }}</td></tr>
</table>

<p>When "{{ the_phrase }}" is searched for "{{ the_letters }}", the following 
results are returned:</p>
<h3>{{ the_results }}</h3>

{% endblock %}

viewlog.html:

{% extends 'base.html' %}

{% block body %}

<h2>{{ the_title }}</h2>

<table>
    <tr>
        {% for row_title in the_row_titles %}
            <th>{{row_title}}</th>
        {% endfor %}
    </tr>
    {% for log_row in the_data %}
        <tr>
            {% for item in log_row %}
                <td>{{item}}</td>
            {% endfor %}
        </tr>
    {% endfor %}
</table>

{% endblock %}

hf.css:

body {
    font-family:      Verdana, Geneva, Arial, sans-serif;
    font-size:        medium;
    background-color: tan;
    margin-top:       5%;
    margin-bottom:    5%;
    margin-left:      10%;
    margin-right:     10%;
    border:           1px dotted gray;
    padding:          10px 10px 10px 10px;
  }
  a {
    text-decoration:  none; 
    font-weight:      600; 
  }
  a:hover {
    text-decoration:  underline;
  }
  a img {
    border:           0;
  }
  h2 {
    font-size:        150%;
  }
  table {
    margin-left:      20px;
    margin-right:     20px;
    caption-side:     bottom;
    border-collapse:  collapse;
  }
  td, th {
    padding:          5px;
    text-align:       left;
  }
  .copyright {
    font-size:        75%;
    font-style:       italic;
  }
  .slogan {
    font-size:        75%;
    font-style:       italic;
  }
  .confirmentry {
    font-weight:      600; 
  }
  
  /*** Tables ***/
  
  table {
  font-size:          1em;
  background-color:   #fafcff;
  border:             1px solid #909090;
  color:              #2a2a2a;
  padding:            5px 5px 2px;
  border-collapse:    collapse;
  }
  
  td, th {
  border:             thin dotted gray;
  }
  
  /*** Inputs ***/
  input[type=text] {
    font-size:        115%;
    width:            30em;
  }
  input[type=submit] {
    font-size:        125%;
  }
  select {
    font-size:        125%;
  }

【问题讨论】:

  • 对我来说看起来是正确的。它试图从烧瓶请求的 user_agent 中获取浏览器,这是查看的正确位置。您可以执行req.user_agent.browser if req.user_agent.browser is not None else 'Unknown' 之类的操作或一些此类技巧,以确保将值传递到 INSERT 语句中。或者您可以修改表以允许该列中的 NULL 值,以便您可以完成您的教程。
  • 是的,我可以这样做,但我仍然无法弄清楚为什么程序不采用浏览器名称的值(我尝试了不同的浏览器,但结果是相同),这很奇怪,因为当我之前在 .txt 文件中打印值(整个 req.user_agent 而不是 req.user_agent.browser)时,一切正常,然后我尝试更改(在当前程序上你在这个网站上看到)从req.user_agent.browser到req.user_agent,但是MySQL显示这个消息错误:_mysql_connector.MySQLInterfaceError: Python type UserAgent cannot be convert,so Idk
  • (我为字符限制写了另一条评论)那么,您认为这可能是数据库问题(因为它略有不同,即使字段browser_string的记录相同)或其他?
  • 当您打印出req.user_agent 时,它是否显示一个以browser 作为键之一的对象?我真的不确定它为什么会失败。你的蟒蛇是正确的。问题不是数据库问题。这只是一个整体问题,当前的代码 + 表不是以允许None 浏览器之类的方式构建的。代码是正确的。表是正确的。它只是没有超级硬化,因为它不会优雅地预测和处理这样的边缘情况。
  • 当我打印出“req.user_agent”(在 .txt 文件中)时,它显示(这里是一个示例):Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3。 9 (KHTML, 像 Gecko) 版本/9.0.2 Safari/601.3.9

标签: mysql python-3.x database flask mysql-python


【解决方案1】:

浏览器数据未传输。

解决方案:
req.user_agent.browser这一行改为req.headers.get('User-Agent')

【讨论】:

    猜你喜欢
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-16
    • 2019-01-04
    • 2020-09-03
    相关资源
    最近更新 更多