通过我的支付系统(api.payson.se)编制一种产品很简单,但同时以不同数量购买许多产品给我带来了麻烦,因为它没有实施,我没有有一个好主意如何做到这一点。现在我有一个解决方案,我刚刚放在一起工作,但建模和控制流程非常快速和肮脏,我想知道这是否可以接受或者是否需要重写。系统现在表现得我可以进入商店(步骤1)并输入我想要购买的产品的金额
然后,如果我按下购买(“Köp”),我的Python会正确计算总和,这可以解决我所说的金额和产品的总和,这个页面也可以列出规范,但尚未实现: 总和是瑞典货币是正确的,它已经向我的数据存储区写了一个订单,其状态为“未付”,并且包含订购了哪些产品以及数据存储区中每个产品的金额: 然后,用户可以取消购买或继续并通过支付系统api.payson.se实际付款: 所以我需要做的就是听听Payson的回复并更新获得付款的订单的状态。但我的解决方案看起来不是很干净,我想知道我是否可以继续使用这样的代码,数据模型是两个字符串列表,一个是数量,一个是产品(项目ID),因为这是我能解决的最简单方法但它不能直接访问,只能从列表中访问。我可以使用更好的数据模型吗?
执行处理的代码有点混乱,可以使用更好的数据模型和更好的算法,而不仅仅是字符串和列表:
class ShopHandler(NewBaseHandler):
@user_required
def get(self):
user = \
auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
]))
self.render_jinja('shop.htm', items=Item.recent(), user=user)
return ''
@user_required
def post(self, command):
user = \
auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
]))
logging.info('in shophandler http post item id'+self.request.get('item'))
items = [ self.request.get('items[1]'),self.request.get('items[2]'),self.request.get('items[3]'),self.request.get('items[4]'),self.request.get('items[5]'),self.request.get('items[6]'),self.request.get('items[7]'),self.request.get('items[8]') ]
amounts = [ self.request.get('amounts[1]'),self.request.get('amounts[2]'),self.request.get('amounts[3]'),self.request.get('amounts[4]'),self.request.get('amounts[5]'),self.request.get('amounts[6]'),self.request.get('amounts[7]'),self.request.get('amounts[8]') ]
total = 0
total = int(self.request.get('amounts[1]'))* long(Item.get_by_id(long(self.request.get('items[1]'))).price_fraction()) if self.request.get('amounts[1]') else total
total = total + int(self.request.get('amounts[2]'))* long(Item.get_by_id(long(self.request.get('items[2]'))).price_fraction()) if self.request.get('amounts[2]') else total
total = total + int(self.request.get('amounts[3]'))* long(Item.get_by_id(long(self.request.get('items[3]'))).price_fraction()) if self.request.get('amounts[3]') else total
total = total + int(self.request.get('amounts[4]'))* long(Item.get_by_id(long(self.request.get('items[4]'))).price_fraction()) if self.request.get('amounts[4]') else total
total = total + int(self.request.get('amounts[5]'))* long(Item.get_by_id(long(self.request.get('items[5]'))).price_fraction()) if self.request.get('amounts[5]') else total
total = total + int(self.request.get('amounts[6]'))* long(Item.get_by_id(long(self.request.get('items[6]'))).price_fraction()) if self.request.get('amounts[6]') else total
total = total + int(self.request.get('amounts[7]'))* long(Item.get_by_id(long(self.request.get('items[7]'))).price_fraction()) if self.request.get('amounts[7]') else total
total = total + int(self.request.get('amounts[8]'))* long(Item.get_by_id(long(self.request.get('items[8]'))).price_fraction()) if self.request.get('amounts[8]') else total
logging.info('total:'+str(total))
trimmed = str(total)+',00'
order = model.Order(status='UNPAID')
order.items = items
order.amounts = amounts
order.put()
logging.info('order was written')
ExtraCost = 0
GuaranteeOffered = 2
OkUrl = 'http://' + self.request.host + r'/paysonreceive/'
Key = '3110fb33-6122-4032-b25a-329b430de6b6'
text = 'niklasro@gmail.com' + ':' + str(trimmed) + ':' + str(ExtraCost) \
+ ':' + OkUrl + ':' + str(GuaranteeOffered) + Key
m = hashlib.md5()
BuyerEmail = user.email
AgentID = 11366
self.render_jinja('order.htm', order=order, user=user, total=total, Generated_MD5_Hash_Value = hashlib.md5(text).hexdigest(), BuyerEmail=user.email, Description='Bnano Webshop', trimmed=trimmed, OkUrl=OkUrl, BuyerFirstName=user.firstname, BuyerLastName=user.lastname)
我的订单模型(不使用所有字段)是
class Order(db.Model):
'''a transaction'''
item = db.ReferenceProperty(Item)
items = db.StringListProperty()
amounts = db.StringListProperty()
owner = db.UserProperty()
purchaser = db.UserProperty()
created = db.DateTimeProperty(auto_now_add=True)
status = db.StringProperty( choices=( 'NEW', 'CREATED', 'ERROR', 'CANCELLED', 'RETURNED', 'COMPLETED', 'UNPAID', 'PAID' ) )
status_detail = db.StringProperty()
reference = db.StringProperty()
secret = db.StringProperty() # to verify return_url
debug_request = db.TextProperty()
debug_response = db.TextProperty()
paykey = db.StringProperty()
shipping = db.TextProperty()
产品的模型即项目
class Item(db.Model):
'''an item for sale'''
owner = db.UserProperty() #optional
created = db.DateTimeProperty(auto_now_add=True)
title = db.StringProperty(required=True)
price = db.IntegerProperty() # cents / fractions, use price_decimal to get price in dollar / wholes
image = db.BlobProperty()
enabled = db.BooleanProperty(default=True)
silver = db.IntegerProperty() #number of silver
def price_dollars( self ):
return self.price / 100.0
def price_fraction( self ):
return self.price / 100.0
def price_silver( self ): #number of silvers an item "is worth"
return self.silver / 1000.000
def price_decimal( self ):
return decimal.Decimal( str( self.price / 100.0 ) )
def price_display( self ):
return str(self.price_fraction()).replace('.',',')
@staticmethod
def recent():
return Item.all().filter( "enabled =", True ).order('-created').fetch(10)
我认为你现在知道发生了什么,这种方式对用户有用,但代码看起来不太好。你认为我可以保留这样的代码并继续保持这个“解决方案”,还是我必须重写以使其更合适?商店里只有8种产品,这个解决方案很难添加新的商品,因为那时我必须重新编写不完美的脚本。
您能否发表评论或回答,我很高兴收到有关这个快速而肮脏的解决方案的反馈意见。
谢谢
我做了一次重写以允许添加新产品,以下内容似乎比以前更好:
class ShopHandler(NewBaseHandler):
@user_required
def get(self):
user = \
auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
]))
self.render_jinja('shop.htm', items=Item.recent(), user=user)
return ''
@user_required
def post(self, command):
user = \
auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id'
]))
logging.info('in shophandler http post')
total = 0
order = model.Order(status='UNPAID')
for item in self.request.POST:
amount = self.request.POST[item]
logging.info('item:'+str(item))
purchase = Item.get_by_id(long(item))
order.items.append(purchase.key())
order.amounts.append(int(amount))
order.put()
price = purchase.price_fraction()
logging.info('amount:'+str(amount))
logging.info('product price:'+str(price))
total = total + price*int(amount)
logging.info('total:'+str(total))
order.total = str(total)
order.put()
trimmed = str(total).replace('.',',') + '0'
ExtraCost = 0
GuaranteeOffered = 2
OkUrl = 'http://' + self.request.host + r'/paysonreceive/'
Key = '6230fb54-7842-3456-b43a-349b340de3b8'
text = 'niklasro@gmail.com' + ':' + str(trimmed) + ':' \
+ str(ExtraCost) + ':' + OkUrl + ':' \
+ str(GuaranteeOffered) + Key
m = hashlib.md5()
BuyerEmail = user.email # if user.email else user.auth_id[0]
AgentID = 11366
self.render_jinja(
'order.htm',
order=order,
user=user,
total=total,
Generated_MD5_Hash_Value=hashlib.md5(text).hexdigest(),
BuyerEmail=user.email,
Description='Bnano Webshop',
trimmed=trimmed,
OkUrl=OkUrl,
BuyerFirstName=user.firstname,
BuyerLastName=user.lastname,
)
答案 0 :(得分:1)
伙计,这是一个非常奇怪的代码。如果您想在商店中添加新商品,则必须重写商店的脚本。 首先取消您的项目与界面的链接,您必须向您的项目ID和数量发送POST请求到控制器,我不知道如何工作gae请求对象,但它必须是这样的: 从你的订单页面发出POST请求,带有真正需要{“item_id”:“qnt”}的项目的dict。 在控制器中,您可以获取所有对象,如:
for item, qnt in request.POST:
{do something with each item, for example where you can sum total}
等 不要直接将控制器与您的接口链接。如果你想制作非常灵活的app,你必须编写更多的抽象代码。
答案 1 :(得分:1)
我将尝试着重于您的代码中一个非常明显的问题,但是它有很多问题,我不打算进入。我的建议是立即停止。您正在实施基于网络的支付系统。你真的应该把它留给拥有更多技能和经验的人。在确保安全性的同时,“基于网络”是一件非常困难的事情,但在线支付系统是那些拥有数十年经验的高薪顾问付出的代价,他们仍然设法弄错了很经常。你要承担很多法律责任。
如果你仍然死定,请阅读The Python Tutorial封面,可能需要多次覆盖。 Python是一种非常不同的语言,与你在心理上融入其中的经典OOP语言完全不同。在那之后,至少翻阅其他文档。如果你遇到这些问题,请拿一本关于Python的O'Reilly书;从另一个角度接近它应该会有所帮助。完成所有这些(也许是在同一时间)之后,尽可能多地编写代码,如果你做错了就不会让你被遗忘。然后也许你可以写一个订单/支付系统。
如果这听起来很苛刻,我很抱歉,但世界上不需要任何伪劣的网店; 1999年为我们照顾了这一点。
无论如何,关于你的代码:D当你写一些重复的东西并像这样复制粘贴时:
items = [ self.request.get('items[1]'),self.request.get('items[2]'),self.request.get('items[3]'),self.request.get('items[4]'),self.request.get('items[5]'),self.request.get('items[6]'),self.request.get('items[7]'),self.request.get('items[8]') ]
你应该自己思考,“等一下!重复任务正是计算机的设计目标。”您可以让文本编辑器执行此操作(请参阅Vim宏),但简洁(但不是太简洁;)代码总是比长代码更好,因为您可以更快地维护,更不容易出现程序员错误,并且更容易调试,更不用说你保存而不是复制和粘贴的时间,所以让我们改进代码。
以下是我将如何在Python中对其进行修改(高级程序员在他们的头脑中执行此操作,或者只是跳到最后):
#1. with a for loop
MAX_ITEMS = 8
items = []
for i in range(MAX_ITEMS):
items.append(self.request.get('items[{}]'.format(i + 1))
#2. with a list comprehension
MAX_ITEMS = 8
items = [self.request.get('items[{}]'.format(i + 1)) for i in range(MAX_ITEMS)]
实际上,限制项目数量是相当业余的,只会让用户感到沮丧。你可以像这样解决它:
items = []
i = 0
while True:
try:
items.append(self.request[i + 1]) #attempt to get the next item
except IndexError as exc: #but if it fails...
break #we must be at the last one
i += 1
我认为这是你现在应该放弃的方式,因为它清晰但不重复。但是,您可以使用the itertools
module中的函数进一步缩短它。
一些快速提示:
"%d" % (5,)
模数字符串格式。奖励:您不必将所有内容转换为字符串!ExtraCost = 2
)并将它们放在安全的地方(在模块的顶部,或在包中的特殊文件中)for item in self.request.POST:
,您假设请求中的所有内容都是项目,并且零验证。