【问题标题】:How do I replace characters in a Google Datastore query result object?如何替换 Google Datastore 查询结果对象中的字符?
【发布时间】:2012-08-23 03:25:01
【问题描述】:

我是 Python、Google AppEngine 和 Jinja 的新手。如果我在下面发布了太多代码,我很抱歉。这是我在 StackOverflow 上发布的第一个问题。

我正在构建一个博客(为一个班级),我需要替换用户帖子中的换行符“\n”。查询数据库的函数将其结果发送到 render() 函数。

在我添加应该替换“\n”的代码行之前,所有代码都可以正常运行。

我进行了各种编辑,但我无法推断 AppEngine、Jinja 或 Python 要我做什么来满足它。

我的数据库类设置 db_blog Kind 有四种类型,包括 'post_content'

class db_blog(db.Model):
    post_subject = db.StringProperty(required = True)
    post_content = db.TextProperty(required = True)
    post_created = db.DateTimeProperty(auto_now_add = True)
    post_last_modified = db.DateTimeProperty(auto_now_add = True)

“Newpost”类我希望它从下面的Blog类接收“query_select”对象。

class Newpost(webapp2.RequestHandler):
    def write(self, *args, **kwds):
        self.response.out.write(*args, **kwds)

    def render_str(self, template, **params):
        t = jinja_env.get_template(template)
        return t.render(params)

    def render(self, template, **kwds):
        self._render_text = self.post_content.replace("\n", "<br />") ##<-- See here 
        self.write(self.render_str(template, **kwds))

博客类获取所有用户帖子并将它们发送到“Newpost”以进行呈现。

class Blog(Newpost):
    def get(self):
        query_select = db.GqlQuery("SELECT * FROM db_blog ORDER BY post_created DESC")
        self.render('blog_posts.htm', query_select = query_select)

1。 如上图,代码会产生这个错误:

AttributeError: 'Blog' 对象没有属性 'post_content'

我认为 Blog 类需要从 db_blog 继承,所以(参见 #2)

2。如果我将 db_blog 添加到 Blog 类的参数列表中,我会收到一个新错误:

AttributeError: 'NoneType' 对象没有属性 'replace'

我认为错误告诉我我正在传递一个不存在的对象,所以我真的很困惑。如果我注释掉试图替换“\n”字符的行,这段代码运行完美——那么它怎么能不传递对象呢?或者声称它 == 无?

更重要的是,我怎样才能让它工作!

非常感谢读到这里的你,感谢他/她的财富王国,让我继续前进。

【问题讨论】:

  • 尝试将“\n”替换为“\\n”。如果您接收信息的方式包括文本“\n”而不仅仅是一个新行,那么您需要这样表示。 python中的“\n”是一个只包含一个新行的字符串,而“\\n”取消了反斜杠,因此实际上包含了文本“slash n”。
  • 顺便说一句,您最好将模型名称更改为使用 CamelCase(“DB_Blog”或更具描述性的“BlogPost”),这更符合 Python 风格(并且清楚地表明它是一个类,而不是一个函数/对象)。您还可以考虑将 query_select 的名称更改为更具描述性的名称(例如 postspost_query 或类似名称),这将使您和其他人更容易理解您的代码。
  • 感谢两位的回复。对象的命名(原文如此)对我来说很重要,在对代码中的每个对象有全局理解之前很难做到。把尾巴钉在旋风上。

标签: python google-app-engine inheritance scope jinja2


【解决方案1】:

您收到属性错误的原因是因为Newpost.get 中的self 指的是RequestHandler (Blog) 而不是 是您想要的帖子。我建议不要在视图函数中定义转换,而是将其添加为模型的属性,例如

class db_blog(db.Model):

    post_subject = db.StringProperty(required = True)
    post_content = db.TextProperty(required = True)
    post_created = db.DateTimeProperty(auto_now_add = True)
    post_last_modified = db.DateTimeProperty(auto_now_add = True)

    @property
    def escaped_content(self):
        # possibly want to escape HTML in your post_content first
        return self.post_content.replace("\n", "<br />")

然后,您可以将query_select 传递给您的模板(就像您现在所做的那样):

{% for post in query_select %}
{{ post.escaped_content | safe }}
{% endfor %}

你需要在上面使用安全,否则 jinja 会逃脱你的&amp;lt;br /&amp;gt;。由于我看不到你的模板,我不知道这是否完全符合你正在做的事情,但希望你明白这一点。

解释一下上面三行神器:

  1. {% for post in query_select %} - 就像 for 循环一样,遍历帖子,每个帖子都应该是一个 db_blog 实例(来自您的查询)。
  2. post.escaped_content 完全等同于在 Python 中调用 db_blog 模型的 escaped_content 属性。
  3. {{ post.escaped_content | safe }}safe 过滤器应用于转义内容产生的字符串(没有safe,jinja 会将&amp;lt;br /&amp;gt; 转换为&amp;lt;br /&amp;gt;(这将在页面上按字面意思显示&amp;lt;br /&amp;gt;)。
  4. {% endfor %} 结束 for 循环。

【讨论】:

  • 我不明白您所说的“我想表达对每个值的原子控制”是什么意思。这假设您已经传递了一个名为“query_select”的项目列表,并且每个项目都是db_blog 模型的一个实例。如果你只是硬编码它会发生什么(例如,将db_blog.all() 传递为query_select,这样你就可以确定你实际上得到了db_blog 实例。
  • 太棒了。我只需要修改 20 分钟(还没有那么快)就可以将值从行中分离出来,但是它可以工作,并且可以按我的意愿工作。 Danke,Domo,Gracias,Merci,谢谢!!!
  • @user1473511 我很高兴它成功了。如果您发现该答案有帮助,您可以单击该答案上/下箭头下方的复选标记以接受它。这告诉其他人您的问题实际上已得到解决。 (无论您是否接受它们,对有帮助的答案进行投票也很好;))
  • 我是新手,所以我的代码可能很冗长。我在 query_select 'object'(sic) 中有多个列,我需要将每个值放在不同的 HTML 容器中。我修改了 HTML 模板文件,以及您向我展示的功能。 &lt;div class="subject" name="subject"&gt;{{p.escaped_content[0] | safe}}&lt;/div&gt; &lt;div class="content" name="content"&gt;{{p.escaped_content[1] | safe}}&lt;/div&gt;@property def escaped_content(self): ps = self.post_subject.replace("\n", "&lt;br /&gt;") pc = self.post_content.replace("\n", "&lt;br /&gt;") return ps, pc
  • 另外,我还不能投票支持你的评论,因为我的声誉只有 11。一旦我达到 15,我就可以投票了。我当然很感激,当我的声誉更高时我会回来,也许我仍然可以投票。这节省了我很多时间,我真的很想继续我班的最后一个单元。谢谢你!!! :)
【解决方案2】:

在我写这篇文章的时候,@JeffTratner 提出了一个很好的建议,让替换成为你模型的属性。我绝对支持这是一个很好的解决方案,所以希望这只会帮助您了解正在发生的事情:)


欢迎!我会先说我没有使用过 jinja(也不是任何类型的 GAE 专家),所以我会尝试专注于我认为导致您的问题的原因(其他更聪明的人会很快纠正我)。

错误

当您使用 Gql 查询数据存储时,结果是可迭代的。 在您的代码中,query_select 是这些可迭代对象之一,其中每个项目都是具有您指定的四个属性的 db_blog 实体。 (注意:您可能会将db_blog 更改为Blog [样式约定等],无论如何我都会建议以后摆脱该类:))

看起来您正在尝试用&lt;br&gt; 替换任何换行符,为此您正在调用self.post_content 上的replace 方法。这个问题是 self 这个上下文是一个 Blog 实例,这完全不同于 你真正想要的(这将是query_select 中的项目)。 编辑: JeffTratner 的方法比我以前的方法要好,所以我要删除我所拥有的,并假设您按照他的建议设置模型 :) 既然如此,您可以简单地运行您的查询然后将结果传递给模板:

query_select = db.GqlQuery("SELECT * FROM db_blog ORDER BY post_created DESC")
self.write(self.render_str(template, **kwds))

关键点 - 查询数据存储将 [几乎] 总是返回一个可迭代的。因此,如果您想对返回的数据执行其他操作,则必须对结果进行迭代:

query_select = db.GqlQuery("SELECT * FROM db_blog ORDER BY post_created DESC")
for result in query_select:
    # Do stuff...

结构

因为我不确定你的意图是什么,所以对此持保留态度,但Blog 是它自己的类有什么原因吗? 我在 Newpost 中没有看到 get 方法 - 是否曾经直接访问过?如果没有,您能否通过完全删除Blog 并将get 方法移至Newpost 来实现相同的功能?

class Newpost(webapp2.RequestHandler):
    def get(self):
        query_select = db.GqlQuery("SELECT * FROM db_blog ORDER BY post_created DESC")
        self.render('blog_posts.htm', query_select = query_select)

    def write(self, *args, **kwds):
        self.response.out.write(*args, **kwds)

    def render_str(self, template, **params):
        t = jinja_env.get_template(template)
        return t.render(params)

    def render(self, template, **kwds):
        self.write(self.render_str(template, **kwds))

这种结构意味着所有getNewpost 的调用都将查询数据存储并呈现结果(不需要单独的类)。另外,这可能是因为我不熟悉 jinja,但似乎您可以将 render/render_str/write 方法浓缩为一个,但我想可以等待,因为它现在正在工作: ))。如果您想尝试,这是一种完全未经测试(而且很可能是错误的)的方法:

class Newpost(webapp2.RequestHandler):
    def get(self):
        query_select = db.GqlQuery("SELECT * FROM db_blog ORDER BY post_created DESC")
        self.render('blog_posts.htm', query_select = query_select)

    def render(self, template, **kwds):        
        t = jinja_env.get_template(template)
        self.response.out.write(t.render(**kwds))

对文字墙感到抱歉 - 希望那里有一些有用的东西!

【讨论】:

  • 谢谢你们的回答。 at:Rocket Donkey,“文字墙”非常有用。我非常喜欢术语,并且将事情拼写出来有助于确认逻辑。 at:Jeff Tratner,我想我明白了。谢谢冠军!!!
  • @user1473511 没有问题!我删除了进行替换的建议,因为 Jeff 的建议在所有方面都更好(而且我的原版需要更多步骤才能使其正常工作)。祝一切顺利。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 2020-03-01
  • 1970-01-01
相关资源
最近更新 更多