国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

利用Python的Flask框架來構建一個簡單的數字商品支付解決方案

2019-11-25 17:53:17
字體:
來源:轉載
供稿:網友

作為一個程序員,我有時候忘了自己所具有的能力。當事情沒有按照你想要的方式發展時,卻很容易忘記你有能力去改變它。昨天,我意識到,我已經對我所出售的書的付款處理方式感到忍無可忍了。我的書完成后,我使用了三個不同的數字商品支付處理器,在對它們三個都感到不滿后,我用Python和Flask,兩個小時的時間寫出了我自己的解決方案。沒錯!兩個小時!現在,這個系統支撐著我的書籍付費流程,整個過程難以置信的簡單,你可以在20秒內購買書籍并開始閱讀。

往下看,看我是如何在一夜之間完成我自己的數字商品支付解決方案的。
支付處理器的付款問題

在我開始賣書的時候,我綜合用了兩種支付服務(一種是信用卡,另一種是PayPal)。最終,我發現了一個可以支持兩者的處理方式。可是我對它們都不滿意。最常用的那個支付處理器,要求用戶在銷售商的系統中創建一個賬戶,并且輸入他們的郵箱地址(盡管郵箱并沒有用)。

另外,我嘗試使用Google Analytics 在全部的訪問中追蹤訪客,包括他們的結賬過程,這一過程也很艱辛。我經常感覺到,如果我能夠讓它工作起來,并且能夠在我的書籍頁面進行A/B測試,我能極大地提高銷量。但是因為不能很好的追蹤,我就沒那么走運了。

最后,使用三個不同的支付處理器,發送書籍更新非常耗時。沒有一個能很好的支持更新,而我希望有個“一鍵”解決方案來發送我的書籍更新。我就沒找到一個類似的服務。
歐耶,我是個程序員

昨天,當我收到一個顧客的郵件,抱怨支付過程是如何的困難并且告訴我可能因此損失了很多銷量后,我忍無可忍了。我決定整一個自己的數字商品管理解決方案。我需要做到下面這樣了流程:

當客戶點擊“Buy Now”按鈕后,他們應該僅僅被要求輸入他們的email地址和信用卡信息。點擊“Confirm”后被帶到一個獨一無二的URL去下載書籍(專門為了這次交易而生成的)。一封包含這個URL的郵件應該被發送給客戶(防止用戶需要重新下載這本書)。對他們重復下載的次數應該有個限制(5次)。交易信息和客戶信息應該被存放在數據庫中,發送書籍更新應該只是一個命令的事。

顯然,這并不是那么的復雜。最復雜的部分是動態生成導向特定書籍版本的獨一無二的URL。其他的事情都挺簡單的。
“Flask前來救援”或是“一個100行代碼的數字商品支付解決方案”

劇透:程序的最終結果正好是100行代碼。對于這種規模的web應用,Flask是個很好的選擇。并不需要大量的模板(cough就像 Django cough),但是有很多很好的插件作為支持。Bottle會是另外一個不錯的選擇,但是我最近都在用Flask,所以我就選它了。

開始的時候,我需要決定如何來存放用戶和交易信息。我決定使用SQLAlchemy,因為sandman的原因,我比較熟悉它SQLAlchemy。Flask有一個插件叫Flask-SQLAlchemy,這使得結合使用兩者非常容易。因為我不需要任何花哨的數據庫操作,我選擇SQLite作為我的后臺數據庫。

決定這樣做之后,我創建了一個app.py 文件并且創建了如下的模型:

 class Product(db.Model):  __tablename__ = 'product'  id = db.Column(db.Integer, primary_key=True)  name = db.Column(db.String)  file_name = db.Column(db.String)  version = db.Column(db.String)  is_active = db.Column(db.Boolean, default=True)  price = db.Column(db.Float) class Purchase(db.Model):  __tablename__ = 'purchase'  uuid = db.Column(db.String, primary_key=True)  email = db.Column(db.String)  product_id = db.Column(db.Integer, db.ForeignKey('product.id'))  product = db.relationship(Product)  downloads_left = db.Column(db.Integer, default=5)

在向數據庫添加了5種不同版本的書籍后(我創建了一個populate_db.py 文件,并把這些版本作為SQLAlchemy模型來添加進數據庫),我需要決定我究竟要如何處理支付。幸運的是,Stripe讓接受一個信用卡變得非常簡單,并且我也已經有了一個他們的賬戶。他們的”checkout.js”方案會在你的頁面上創建一個表單和按鈕。當點擊這個按鈕時,一個簡潔又引人注目的浮動層會彈出來。

2015331102015017.jpg (1412×887)

這個表單的action 屬性指向你的站點的一個頁面,當用戶完成支付后就會被帶到那里。我在我的書籍銷售頁面添加了5個這樣的按鈕,還有一個隱藏的表單欄,包含了被交易產品的id(product_id)(1-5之間的一個整數)
處理支付

顯然,我的應用需要一個后端來處理一次成功付款。我添加了以下這些函數來完成這一目的:

 @app.route('/buy', methods=['POST'])def buy():  stripe_token = request.form['stripeToken']  email = request.form['stripeEmail']  product_id = request.form['product_id']  product = Product.query.get(product_id)  try:    charge = stripe.Charge.create(        amount=int(product.price * 100),        currency='usd',        card=stripe_token,        description=email)  except stripe.CardError, e:    return """<html><body><h1>Card Declined</h1><p>Your chard could not    be charged. Please check the number and/or contact your credit card    company.</p></body></html>"""  print charge  purchase = Purchase(uuid=str(uuid.uuid4()),      email=email,      product=product)  db.session.add(purchase)  db.session.commit()  message = Message(      subject='Thanks for your purchase!',    sender="jeff@jeffknupp.com",    html="""<html><body><h1>Thanks for buying Writing Idiomatic Python!</h1><p>If you didn't already download your copy, you can visit<a >your private link</a>. You'll be able todownload the file up to five times, at which point the link willexpire.""".format(purchase.uuid),    recipients=[email])  with mail.connect() as conn:    conn.send(message)  return redirect('/{}'.format(purchase.uuid))

正如你所看到的,我寫代碼的時候有點偷懶了(因為我正在憤怒的編程……)首先,我有一個內聯HTML,在付費不成功時返回,還有已購買成功時返回郵箱。這些東西應該被放在一個全局變量,或者,更好的方法是放在一個單獨的文件中。另外,在創建Purchase 時我并沒有進行任何的錯誤檢查。但是實際上,唯一可能出錯的地方是嘗試插入重復的 uuid,但是我并不擔心,因為發生的幾率太低了(潛臺詞:微乎其微)。

你可以看的我使用了一個mail 對象,這個對象來自于Flask-Mail包,這個插件讓發送郵件變得輕松。我就設置它使用GMail作為服務器,然后所有東西都可以正常工作了。
好吧,現在該給我書了

現在,支付的部分已經搞定,我需要添加一個后端功能,在完成支付后初始化下載。因為我使用UUID作為主鍵,所以我同樣可以使用它作為URL。當有人訪問包含UUID的URL時,我需要檢查該UUID是不是包含在數據庫中。如果是的話,提供書籍文件并且把剩余下載(downloads_left)次數屬性減少1次。如果不是的話,就返回404錯誤。下面是我寫的代碼:
 

@app.route('/<uuid>')def download_file(uuid):  purchase = Purchase.query.get(uuid)  if purchase:    if purchase.downloads_left <= 0:      return """<html><body><h1>No downloads left!</h1><p>You have      exceeded the allowed number of downloads for this file. Please email      jeff@jeffknupp.com with any questions.</p></body></html>"""    purchase.downloads_left -= 1    db.session.commit()    return send_from_directory(directory='files',        filename=purchase.product.file_name, as_attachment=True)  else:    abort(404)

非常直觀。使用UUID作為一個URL變量,尋找交易信息。如果存在,就檢查是否還有可用下載次數,然后提供所購買的文件。否則,等著你的是404錯誤。

最后,我需要我需要添加一個測試來讓我可以模擬交易過程。下面是測試代碼和讓這個app運行的代碼:

@app.route('/test')def test():  return """<http><body><form action="buy" method="POST"><script  src="https://checkout.stripe.com/checkout.js" class="stripe-button"  data-key="pk_test_w3qNBkDR8A4jkKejBmsMdH34"  data-amount="999"  data-name="jeffknupp.com"  data-description="Writing Idiomatic Python 3 PDF ($9.99)"></script><input type="hidden" name="product_id" value="2" /></form></body></html>"""if __name__ == '__main__':  sys.exit(app.run(debug=True))

能力越大…責任越大!

實際上我對于自己能如此快速簡單讓這一切工作起來感到吃驚。整個應用程序包含在一個100行代碼的文件中。而且它替代了我每天使用的那些重要服務,我對那些服務一直都不滿意。最后,我可以追蹤交易,沒有任何問題,這讓我確信自己可以提高銷量。

作為一個開發者,能意識到你有能力塑造我們和數字世界的交互是很好的一件事。比方說,我會忘記,如果有一些科技不能按照我預想的方式去工作,我有能力改變它。從自動化機械式的任務比如輸入數據,到自動排序和整理電子郵件,開發者們有能力去簡化他們每天的工作。

擁有Flask這樣的工具對解決這些問題非常重要。正如像作為程序員那樣進步,你應該建立你的一套解決“核心”問題的工具集。Flask就是很好的例子,因為匆匆忙忙的拼湊一個web應用是一件司空見慣的事情。

當然,分享你的作品同樣非常的重要。如果我做一些東西,對我自己有用,但沒有去分享給別人,我就會怠慢。“分享”不僅僅意味著”把項目放進一個GitHub公共倉庫“。你還需要讓大家知道有這個東西。從郵件列表到論壇再到個人博客,從來都不缺少讓大家知道你創造了一些東西的途徑。我總是設法回饋社區,因為我從中得到了很多東西。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 桦南县| 林甸县| 涟源市| 华阴市| 肇东市| 通海县| 抚州市| 六枝特区| 松江区| 江北区| 青海省| 电白县| 奎屯市| 新化县| 池州市| 游戏| 兴仁县| 亳州市| 平乐县| 凤城市| 德钦县| 天门市| 伊川县| 临潭县| 周口市| 宁阳县| 呈贡县| 广安市| 都江堰市| 虎林市| 石景山区| 河曲县| 哈巴河县| 贡嘎县| 屏山县| 淮北市| 广平县| 南郑县| 内黄县| 崇阳县| 顺昌县|