0

通过我的支付系统(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,
            )
4

2 回答 2

1

伙计,这是一个非常奇怪的代码。如果您想在您的商店中添加新商品,您必须重写您的商店脚本。在第一次从界面取消链接您的项目时,您必须使用您的项目 ID 和数量向控制器发送 POST 请求,我不知道 gae 请求对象是如何工作的,但它必须是这样的:从您的订单页面发出带有项目字典的 POST 请求真正需要{“item_id”:“qnt”}。在控制器中时,您可以获取所有对象,例如:

for item, qnt in request.POST:
    {do something with each item, for example where you can sum total}

等等 不要直接将控制器与您的接口链接。如果你想制作真正灵活的应用程序,你必须编写更多的抽象代码。

于 2012-01-31T07:55:12.037 回答
1

我将尝试专注于您的代码中一个非常明显的问题,但它有很多问题我不打算讨论。我的建议是立即停止。您正在实施一个基于网络的支付系统。你真的应该把它留给有更多技能和经验的人。在确保安全的同时,“基于网络”是一件很难做到的事情,但是在线支付系统是具有数十年经验的高薪顾问所获得的高薪,但他们仍然设法弄错了很经常。你让自己承担很多法律责任。

如果您仍然对此一无所知,请阅读The Python Tutorial封面,可能要多读几遍。Python 是一种非常不同的语言,与您在脑海中塞进的任何经典 OOP 语言都不同。之后,至少浏览其他文档。如果您在这些方面遇到问题,请阅读 O'Reilly 的 Python 书籍;从另一个角度接近它应该会有所帮助。在你完成所有这些(可能同时)之后,尽可能多地编写代码,如果你做错了不会让你被遗忘。那么也许你可以编写一个订单/支付系统。

如果这听起来很苛刻,我很抱歉,但世界不再需要任何劣质的网上商店;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

我认为这是您现在应该离开的方式,因为它很清楚但不重复。但是,您可以使用模块中itertools函数进一步缩短它。

一些快速提示:

  • 避免字符串连接,尤其是在用户提供的字符串的情况下,尤其是在涉及来自网络的用户提供的字符串时。使用 str.format 和"%d" % (5,)模数字符串格式。奖励:您不必将所有内容都转换为字符串!
  • 从中间取出那些常量(例如,ExtraCost = 2)并将它们放在安全的地方(在模块的顶部,或在包中的特殊文件中)
  • 您过于信任用户:在,您假设请求中的所有内容都将是一个项目,并且您进行验证for item in self.request.POST:
  • 请,请,请。 永远不要关闭自动完成。我真的不知道为什么该属性存在,除了惹恼。
于 2012-02-01T01:44:41.657 回答