最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用Python的Flask框架來構(gòu)建一個簡單的數(shù)字商品支付解決方案

 更新時間:2015年03月31日 10:22:07   作者:Jeff Knupp  
這篇文章主要介紹了利用Python的Flask框架來構(gòu)建一個簡單的數(shù)字商品支付解決方案,文中用極簡的代碼展示了一個flask框架下的支付模版,需要的朋友可以參考下

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

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

在我開始賣書的時候,我綜合用了兩種支付服務(wù)(一種是信用卡,另一種是PayPal)。最終,我發(fā)現(xiàn)了一個可以支持兩者的處理方式??墒俏覍λ鼈兌疾粷M意。最常用的那個支付處理器,要求用戶在銷售商的系統(tǒng)中創(chuàng)建一個賬戶,并且輸入他們的郵箱地址(盡管郵箱并沒有用)。

另外,我嘗試使用Google Analytics 在全部的訪問中追蹤訪客,包括他們的結(jié)賬過程,這一過程也很艱辛。我經(jīng)常感覺到,如果我能夠讓它工作起來,并且能夠在我的書籍頁面進(jìn)行A/B測試,我能極大地提高銷量。但是因?yàn)椴荒芎芎玫淖粉?,我就沒那么走運(yùn)了。

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

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

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

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

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

開始的時候,我需要決定如何來存放用戶和交易信息。我決定使用SQLAlchemy,因?yàn)?a target="_blank" >sandman的原因,我比較熟悉它SQLAlchemy。Flask有一個插件叫Flask-SQLAlchemy,這使得結(jié)合使用兩者非常容易。因?yàn)槲也恍枰魏位ㄉ诘臄?shù)據(jù)庫操作,我選擇SQLite作為我的后臺數(shù)據(jù)庫。

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

 
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)

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

2015331102015017.jpg (1412×887)

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

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

 
@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 to
download the file up to five times, at which point the link will
expire.""".format(purchase.uuid),
    recipients=[email])
  with mail.connect() as conn:
    conn.send(message)
  return redirect('/{}'.format(purchase.uuid))

正如你所看到的,我寫代碼的時候有點(diǎn)偷懶了(因?yàn)槲艺趹嵟木幊獭┦紫?,我有一個內(nèi)聯(lián)HTML,在付費(fèi)不成功時返回,還有已購買成功時返回郵箱。這些東西應(yīng)該被放在一個全局變量,或者,更好的方法是放在一個單獨(dú)的文件中。另外,在創(chuàng)建Purchase 時我并沒有進(jìn)行任何的錯誤檢查。但是實(shí)際上,唯一可能出錯的地方是嘗試插入重復(fù)的 uuid,但是我并不擔(dān)心,因?yàn)榘l(fā)生的幾率太低了(潛臺詞:微乎其微)。

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

現(xiàn)在,支付的部分已經(jīng)搞定,我需要添加一個后端功能,在完成支付后初始化下載。因?yàn)槲沂褂肬UID作為主鍵,所以我同樣可以使用它作為URL。當(dāng)有人訪問包含UUID的URL時,我需要檢查該UUID是不是包含在數(shù)據(jù)庫中。如果是的話,提供書籍文件并且把剩余下載(downloads_left)次數(shù)屬性減少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變量,尋找交易信息。如果存在,就檢查是否還有可用下載次數(shù),然后提供所購買的文件。否則,等著你的是404錯誤。

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

@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))

能力越大…責(zé)任越大!

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

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

擁有Flask這樣的工具對解決這些問題非常重要。正如像作為程序員那樣進(jìn)步,你應(yīng)該建立你的一套解決“核心”問題的工具集。Flask就是很好的例子,因?yàn)榇掖颐γΦ钠礈愐粋€web應(yīng)用是一件司空見慣的事情。

當(dāng)然,分享你的作品同樣非常的重要。如果我做一些東西,對我自己有用,但沒有去分享給別人,我就會怠慢?!胺窒怼辈粌H僅意味著”把項目放進(jìn)一個GitHub公共倉庫“。你還需要讓大家知道有這個東西。從郵件列表到論壇再到個人博客,從來都不缺少讓大家知道你創(chuàng)造了一些東西的途徑。我總是設(shè)法回饋社區(qū),因?yàn)槲覐闹械玫搅撕芏鄸|西。

相關(guān)文章

最新評論

靖江市| 古丈县| 大邑县| 凌源市| 集贤县| 西林县| 图们市| 广西| 贵港市| 五大连池市| 修文县| 宁城县| 玉林市| 仲巴县| 眉山市| 咸阳市| 庆元县| 茶陵县| 灵武市| 邢台县| 泰兴市| 景宁| 图片| 新密市| 封开县| 金沙县| 思茅市| 中西区| 正定县| 松溪县| 马鞍山市| 新宁县| 凭祥市| 神农架林区| 抚州市| 庆云县| 寻乌县| 濮阳市| 姜堰市| 昭平县| 银川市|