从网上商店一次购买许多产品

时间:2012-01-31 06:48:42

标签: python google-app-engine google-cloud-datastore python-2.7 webshop

通过我的支付系统(api.payson.se)编制一种产品很简单,但同时以不同数量购买许多产品给我带来了麻烦,因为它没有实施,我没有有一个好主意如何做到这一点。现在我有一个解决方案,我刚刚放在一起工作,但建模和控制流程非常快速和肮脏,我想知道这是否可以接受或者是否需要重写。系统现在表现得我可以进入商店(步骤1)并输入我想要购买的产品的金额

enter image description here

然后,如果我按下购买(“Köp”),我的Python会正确计算总和,这可以解决我所说的金额和产品的总和,这个页面也可以列出规范,但尚未实现: enter image description here 总和是瑞典货币是正确的,它已经向我的数据存储区写了一个订单,其状态为“未付”,并且包含订购了哪些产品以及数据存储区中每个产品的金额: enter image description here 然后,用户可以取消购买或继续并通过支付系统api.payson.se实际付款: enter image description here 所以我需要做的就是听听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,
            )

2 个答案:

答案 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中的函数进一步缩短它。

一些快速提示:

  • 避免字符串连接,尤其是在用户提供的字符串的情况下,特别是当涉及来自Web的用户提供的字符串时。使用str.format和"%d" % (5,)模数字符串格式。奖励:您不必将所有内容转换为字符串!
  • 从中间获取这些常量(例如ExtraCost = 2)并将它们放在安全的地方(在模块的顶部,或在包中的特殊文件中)
  • 您过分信任用户方式:在for item in self.request.POST:,您假设请求中的所有内容都是项目,并且验证。
  • 请拜托。 从不关闭自动填充功能。我真的不知道为什么这个属性存在,除了烦恼。