【问题标题】:Python/MySQL: write to database successful ONLY one timePython/MySQL:仅一次成功写入数据库
【发布时间】:2017-04-10 04:41:26
【问题描述】:

慢慢构建我的应用程序(用于 CS50),它似乎可以工作,但它只会写入数据库一次。我可以去网站,下订单,它每次都会成功地在 HTML 页面上显示我的订单。但它只会将订单写入数据库并显示一次。我可以注销,但仍然只有一个订单会写入数据库。

@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
    if request.method == "POST":
        #http://stackoverflow.com/questions/32640090/python-flask-keeping-track-of-user-sessions-how-to-get-session-cookie-id
        id = session.get('user_id')

        url_start = 'http://download.finance.yahoo.com/d/quotes.csv?s='
        url_middle = request.form["symbol"]
        url_end = '&f=nsl1d1t1c1ohgv&e=.csv'
        full_url = url_start + url_middle + url_end

        # http://stackoverflow.com/questions/21351882/reading-data-from-a-csv-file-online-in-python-3
        response = urllib.request.urlopen(full_url)

        datareader = csv.reader(io.TextIOWrapper(response))
        quote_list = list(datareader)

        num_shares = request.form["num_shares"]

        name = quote_list[0][0]
        symbol = quote_list[0][1]
        price = float(quote_list[0][2])

        #http://stackoverflow.com/questions/12078571/jinja-templates-format-a-float-as-comma-separated-currency
        total_cost = round((float(price) * 100.0) * float(num_shares) / 100.0,2)

        username = db.execute("SELECT username FROM users WHERE id = :id", id=id)
        username = username[0]
        username = username.get('username')

        db.execute("INSERT INTO purchases (id, symbol, name, shares, price, total) VALUES(:id, :symbol, :name, :shares, :price, :total)",
            id=id, symbol=symbol, name=name, price=price, shares=num_shares, total=total_cost)

        return render_template("bought.html", username=username, id=id, name=name, symbol=symbol, price=price, num_shares=num_shares, total_cost=total_cost)
    else:
        return render_template("buy.html")

【问题讨论】:

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


    【解决方案1】:

    首先,大多数问题都可以通过将函数分成几部分并检查每个部分是否按预期工作来解决,所以让我们稍微重构一下代码。

    # additional import for generating URL from parts,
    # not by concatenating strings
    import urllib.parse
    
    
    @app.route("/buy", methods=["GET", "POST"])
    @login_required
    def buy():
        if request.method != "POST":
            return render_template("buy.html")
    
        # http://stackoverflow.com/questions/32640090/python-flask-keeping-track-of-user-sessions-how-to-get-session-cookie-id
        user_id = session.get('user_id')
    
        # what is "full_url"?
        # to which resource and what we get with it?
        full_url = generate_url(symbol=request.form["symbol"])
    
        # http://stackoverflow.com/questions/21351882/reading-data-from-a-csv-file-online-in-python-3
        response = urllib.request.urlopen(full_url)
    
        datareader = csv.reader(io.TextIOWrapper(response))
        quote_list = list(datareader)
    
        num_shares = request.form["num_shares"]
    
        # what first element means,
        # if it contains info about specific data
        # there should be name for it
        quote_list_first_element = quote_list[0]
        name = quote_list_first_element[0]
        # is this symbol different from one in "request.form"?
        symbol = quote_list_first_element[1]
        price = float(quote_list_first_element[2])
    
        # http://stackoverflow.com/questions/12078571/jinja-templates-format-a-float-as-comma-separated-currency
        total_cost = get_total_cost(price, num_shares)
    
        username = fetch_user_name(user_id)
    
        save_purchase(user_id=user_id,
                      symbol=symbol,
                      name=name,
                      price=price,
                      num_shares=num_shares,
                      total_cost=total_cost)
    
        return render_template("bought.html",
                               username=username,
                               id=user_id,
                               name=name,
                               symbol=symbol,
                               price=price,
                               num_shares=num_shares,
                               total_cost=total_cost)
    
    
    def fetch_user_name(user_id):
        username = db.execute("SELECT username FROM users WHERE id = :user_id",
                              user_id=user_id)
        username = username[0]
        username = username.get('username')
        return username
    
    
    def save_purchase(user_id, name, num_shares,
                      price, symbol, total_cost):
        db.execute(
            "INSERT INTO purchases (id, symbol, name, num_shares, price, total) "
            "VALUES (:user_id, :symbol, :name, :num_shares, :price, :total)",
            # FIXME: if "purchases" table's "id" column is a primary key 
            # here we are saving purchase by user id 
            # not by purchase id (which probably is auto-incremented 
            # and should not be specified in insert query at all), 
            # so for each user we will have only one purchase since primary key is unique
            user_id=user_id,
            symbol=symbol,
            name=name,
            price=price,
            # maybe it will be better to rename column into "num_shares"?
            shares=num_shares,
            # maybe it will be better to rename column into "total_cost"?
            total=total_cost)
    
    
    def get_total_cost(price, num_shares):
        return round((float(price) * 100.0) * float(num_shares) / 100.0, 2)
    
    
    def generate_url(symbol):
        scheme = 'http'
        netloc = 'download.finance.yahoo.com'
        path = '/d/quotes.csv'
        params = ''
        # what 's' query parameter means?
        # looks like it stands for "symbol", but which one?
        # is it product label or something else?
        query_dict = dict(s=symbol,
                          f='nsl1d1t1c1ohgv',
                          e='.csv')
        query_str = urllib.parse.urlencode(query_dict)
        fragment = ''
        components = [scheme, netloc, path, params, query_str, fragment]
        return urllib.parse.urlunparse(components)
    

    现在我们可以看到我们通过用户 ID 保存每次购买,但它可能是自动递增的列或者有用户 ID 列,而不是购买 ID,我不知道你的数据库架构是什么

    如果purchases表的id列是自增的,我们可以去掉user_id参数

    def save_purchase(name, num_shares,
                      price, symbol, total_cost):
        db.execute(
            "INSERT INTO purchases (symbol, name, num_shares, price, total) "
            "VALUES (:symbol, :name, :num_shares, :price, :total)",
            symbol=symbol,
            name=name,
            price=price,
            shares=num_shares,
            total=total_cost)
    

    如果purchases 表同时具有iduser_id 列,我们要插入指定user_id 的记录,它应该是这样的

    def save_purchase(user_id, name, num_shares,
                      price, symbol, total_cost):
        db.execute(
            "INSERT INTO purchases (user_id, symbol, name, num_shares, price, total) "
            "VALUES (:user_id, :symbol, :name, :num_shares, :price, :total)",
            user_id=user_id,
            symbol=symbol,
            name=name,
            price=price,
            shares=num_shares,
            total=total_cost)
    

    希望对你有帮助。

    【讨论】:

    • 谢谢,您的建议很好,但我的回答实际上要简单得多。
    • 当它完全符合我的假设时,你的答案怎么能更简单:你试图用相同的主键值保存记录
    • 嗯,我的意思是说,把它分解成函数是一个不错的建议,但核心问题是它被设置为唯一的。
    • 对我来说,如果不进行重构,就很难找出错误,因为我们都知道"readability counts"
    【解决方案2】:

    简单的答案:我将购买表设置为与用户表相同,并且 id_num 在两个表中都是唯一的。它在用户表中应该是唯一的,因为用户是唯一的。但它在购买表中不应该是唯一的,因为同一个用户可以进行多次购买。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-02
      • 1970-01-01
      • 2013-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-11
      相关资源
      最近更新 更多