2010-01-12 28 views
7

Như chúng ta đều biết (hoặc phải), bạn có thể sử dụng hệ thống mẫu của Django để render cơ quan email:Email khuôn mẫu trong 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)), '[email protected]', [email,]) 

này có một lỗ hổng trong tâm trí tôi: để chỉnh sửa các chủ đề và nội dung của một email, bạn phải chỉnh sửa cả chế độ xem và mẫu. Mặc dù tôi có thể biện minh cho người dùng quản trị quyền truy cập vào các mẫu, tôi không cấp cho họ quyền truy cập vào trăn thô!

gì sẽ thực sự mát mẻ là nếu bạn có thể chỉ định các khối trong email và kéo chúng ra riêng khi bạn gửi email:

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

Nhưng làm thế nào bạn sẽ làm điều đó? Làm thế nào bạn sẽ đi về rendering chỉ là một khối tại một thời điểm?

Trả lời

11

Đây là lần lặp lại thứ ba của tôi. Nó giả sử bạn có một email mẫu như vậy:

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

Tôi đã refactored để lặp email gửi qua một danh sách theo mặc định và có những phương pháp hữu ích cho việc gửi một email duy nhất và django.contrib.authUser s (đơn và nhiều). Tôi đang bao gồm có lẽ nhiều hơn tôi sẽ cần một cách hợp lý nhưng có bạn đi.

Tôi cũng có thể đã vượt lên trên cùng với tình yêu của 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'), '[email protected]', [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) 

Như mọi khi, nếu bạn có thể cải thiện điều đó, vui lòng thực hiện.

+0

Vâng & * $ # tôi. Nó hoạt động. Xem xét thêm nhiều trường hơn vào cơ sở để cho phép thiết lập cài đặt từ/từ-tên/trả lời đến. – Oli

+0

Hah, tôi đã làm điều này với ba mẫu khác nhau mà là một PITA. Xác định +1 từ tôi! –

+0

Tôi thích nó. Tôi đã luôn luôn chỉ sử dụng các mẫu riêng biệt, mà hoạt động tốt, nhưng điều này là rất nhiều đẹp hơn để đối phó với (đặc biệt là kể từ khi bạn thường muốn cùng một bối cảnh cho tất cả các mẫu anyway). –

0

Chỉ cần sử dụng hai mẫu: một mẫu cho phần thân và một cho chủ thể.

+0

Hai tệp có nghĩa là hai tên tệp về cơ bản giống nhau. Nó chỉ là một nỗi đau ở phía sau phải giữ trên đầu trang của nhiều mẫu. – Oli

0

tôi không thể có được mẫu thừa kế để làm việc bằng cách sử dụng {% body %} thẻ, vì vậy tôi chuyển sang một mẫu như thế này:

{% extends "base.txt" %} 

{% if subject %}Subject{% endif %} 
{% if body %}Email body{% endif %} 
{% if html %}<p>HTML body</p>{% endif %} 

Bây giờ chúng ta phải làm cho mẫu ba lần, nhưng kế thừa hoạt động đúng.

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() 

Tôi cũng thấy nó cần thiết để tắt autoescape khi vẽ các văn bản không phải là HTML để tránh văn bản đã trốn thoát trong email