【问题标题】:Prevent duplicate property in ndb datastore防止 ndb 数据存储中的重复属性
【发布时间】:2017-06-11 05:31:08
【问题描述】:

我正在构建一个简单的时事通讯应用程序来收集电子邮件地址。我有一个通过 ajax 将电子邮件值发送到我的 python 应用程序的表单,但是我一辈子都无法弄清楚如何查看电子邮件是否已经存在。下面的代码目前可以正常工作,我只是不知道在哪里/如何添加“检查预先存在的实体”的东西。

import webapp2
import json

from google.appengine.ext import ndb

class Email(ndb.Model):
    email = ndb.StringProperty()
    subscribed = ndb.BooleanProperty()

    @staticmethod
    def create(email):
        ekey = ndb.Key("Email", email)
        entity = Email.get_or_insert(ekey)
        if entity.email:  ###
            # This email already exists
            return None
        entity.email = email
        entity.subscribed = True
        entity.put()
        return entity

class Subscribe(webapp2.RequestHandler):
    def post(self):
        add = Email.create(self.request.get('email'))
        success = add is not None 
        self.response.headers['Content-Type'] = 'application/json'   
        obj = {
            'success': success
        } 
        self.response.out.write(json.dumps(obj))


app = webapp2.WSGIApplication([
    webapp2.Route(r'/newsletter/new', Subscribe),
], debug=True)

【问题讨论】:

标签: python google-app-engine datastore


【解决方案1】:

根据 Dan 的评论更新了答案。丹,谢谢你纠正我。进一步更新,以回应更新后的问题。

您可以将电子邮件地址设置为电子邮件实体的 id 并使用get_or_insert。在这里,电子邮件存储是多余的,因为它是 id 也是一个属性。您可能可以通过检查下面### 处的另一个属性来摆脱这种冗余。

class Email(ndb.Model):
    email = ndb.StringProperty()
    subscribed = ndb.BooleanProperty()

    @staticmethod
    def create(email):
        ekey = ndb.Key("Email", email)
        entity = Email.get_or_insert(ekey)
        if entity.email:  ###
            # This email already exists
            return None
        entity.email = email
        entity.subscribed = True
        entity.put()
        return entity

class Subscribe(webapp2.RequestHandler):
    def post(self):
        add = Email.create(self.request.get('email'))
        success = add is not None 
        self.response.headers['Content-Type'] = 'application/json'   
        obj = {
            'success': success
        } 
        self.response.out.write(json.dumps(obj))

我没有测试上面的代码,所以可能会有错误,但它应该会引导你走上正确的道路。

【讨论】:

  • #2 选项不起作用,因为您不能在事务中进行非祖先查询。此外,此类查询最终是一致的,因此仍有可能出现重复。
  • 但这是一个跨组事务,所以不应该工作吗?
  • "在事务中,只允许祖先查询。" - 交易类型无关紧要
  • @JeffO'Neill 1. 它是说 create(email): 中的“e”处有语法错误:和 2. 我是否需要在我的课程中添加一些内容订阅以将电子邮件设置为id,还是静态方法为我做的?
  • @user2250471,对于 1,我修正了错字。对于 2,id 在密钥中,并在创建密钥时将电子邮件作为第二个参数传递,将电子邮件设置为 id。您无需在其他任何地方设置 id。
【解决方案2】:

始终创建单独的模型类是一种好方法。我创建了单独的模型类并更新了您的订阅者类发布方法,如果电子邮件存在,它将返回 false,否则将返回 true。希望能解决你的问题。

class EmailModel(ndb.Model):
       email = ndb.StringProperty()
       subscribed = ndb.BooleanProperty()

class Subscribe(webapp2.RequestHandler):
      def post(self):
         email = self.request.get('email')
         entity = EmailModel.query(EmailModel.email == email).get()
         if entity:
             # Duplicate
             check = False
         else:
             add = Email()
             add.email = self.request.get('email')
             add.subscribed = True
             add.put()
             check = True
         if check:
              self.response.headers['Content-Type'] = 'application/json'   
              obj = {
                'success': True
              } 
              self.response.out.write(json.dumps(obj))
         else:
              self.response.headers['Content-Type'] = 'application/json'   
              obj = {
                'success': False
              } 
              self.response.out.write(json.dumps(obj))

【讨论】:

  • 应该注意,由于最终的一致性,此方法为重复条目留出了空间 - 即使实体存在(最近创建),查询也可能不返回任何结果。
  • @DanCornilescu 我在我的不同网站中使用这种方法,还没有遇到任何重复。您能否建议一个可靠的解决方案,以便我也可以在我的网站上更新它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
  • 2012-07-20
相关资源
最近更新 更多