【问题标题】:Email templating in djangodjango 中的电子邮件模板
【发布时间】:2011-01-04 07:46:30
【问题描述】:

众所周知(或应该),您可以使用 Django 的模板系统来呈现电子邮件正文:

def email(email, subject, template, context):
    from django.core.mail import send_mail
    from django.template import loader, Context

    send_mail(subject, loader.get_template(template).render(Context(context)), 'from@domain.com', [email,])

我认为这有一个缺陷:要编辑电子邮件的主题和内容,您必须同时编辑视图和模板。虽然我可以证明让管理员用户访问模板是合理的,但我并没有让他们访问原始 python!

如果您可以在电子邮件中指定块并在发送电子邮件时将它们单独拉出,那将是非常酷的:

{% block subject %}This is my subject{% endblock %}
{% block plaintext %}My body{% endblock%}
{% block html %}My HTML body{% endblock%}

但是你会怎么做呢?如何一次只渲染一个块?

【问题讨论】:

    标签: django email django-templates django-email


    【解决方案1】:

    这是我的第三次工作迭代。假设您有这样的电子邮件模板:

    {% block subject %}{% endblock %}
    {% block plain %}{% endblock %}
    {% block html %}{% endblock %}
    

    我已经重构,默认情况下通过列表迭代电子邮件发送,并且有一些实用方法可以发送到单个电子邮件和django.contrib.authUsers(单个和多个)。我所涵盖的内容可能超出了我的合理需要,但你去吧。

    我也可能对 Python 的热爱超过了顶峰。

    def email_list(to_list, template_path, context_dict):
        from django.core.mail import send_mail
        from django.template import loader, Context
    
        nodes = dict((n.name, n) for n in loader.get_template(template_path).nodelist if n.__class__.__name__ == 'BlockNode')
        con = Context(context_dict)
        r = lambda n: nodes[n].render(con)
    
        for address in to_list:
            send_mail(r('subject'), r('plain'), 'from@domain.com', [address,])
    
    def email(to, template_path, context_dict):
        return email_list([to,], template_path, context_dict)
    
    def email_user(user, template_path, context_dict):
        return email_list([user.email,], template_path, context_dict)
    
    def email_users(user_list, template_path, context_dict):
        return email_list([user.email for user in user_list], template_path, context_dict)
    

    和以往一样,如果您可以改进,请这样做。

    【讨论】:

    • 好吧 &*$# 我。有用。考虑向基础添加更多字段以允许设置 from/from-name/reply-to 设置。
    • 哈,我一直在用三个不同的模板来做这个,这是一个 PITA。绝对 +1 我!
    • 我喜欢。我一直只使用单独的模板,效果很好,但这样处理起来要好得多(尤其是因为您通常希望所有模板都使用相同的上下文)。
    • 它目前不支持模板继承 - 您需要在实际模板中指定每个所需的块。如果有人能弄清楚这一点,我将不胜感激,因为这将使在基本模板中设置默认值变得更加容易......但也许这是 settings.py
    • 当我升级到 Django 1.8 时,它坏了。但这很容易解决。将 loader.get_template(template_path).nodelist 更改为 loader.get_template(template_path).template。我通过stackoverflow.com/a/29633563/250962 找到了这个解决方案
    【解决方案2】:

    只需使用两个模板:一个用于正文,一个用于主题。

    【讨论】:

    • 两个文件意味着本质上相同的两个文件名。必须掌握这么多模板只是背后的痛苦。
    【解决方案3】:

    我无法使用{% body %} 标签使模板继承工作,所以我切换到这样的模板:

    {% extends "base.txt" %}
    
    {% if subject %}Subject{% endif %}
    {% if body %}Email body{% endif %}
    {% if html %}<p>HTML body</p>{% endif %}
    

    现在我们必须渲染模板 3 次,但继承工作正常。

    c = Context(context, autoescape = False)
    subject = render_to_string(template_name, {'subject': True}, c).strip()
    body = render_to_string(template_name, {'body': True}, c).strip()
    c = Context(context, autoescape = True)
    html = render_to_string(template_name, {'html': True}, c).strip()
    

    我还发现在呈现非 HTML 文本时有必要关闭自动转义以避免电子邮件中的转义文本

    【讨论】:

      猜你喜欢
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 2011-02-18
      • 2020-09-08
      • 1970-01-01
      相关资源
      最近更新 更多