邮件黑猩猩订阅不适用于 django

问题描述

大家好,我将我的 Django Web 应用程序与 mail chimp 集成在一起。在我的管理面板中,当我打开营销偏好时,它给了我错误。当我点击订阅时它不会订阅我的用户,当我点击保存时我的用户保持取消订阅。我得到的错误

{'type': 'https://mailchimp.com/developer/marketing/docs/errors/','title': 'Invalid Resource','status': 400,'detail': "The resource submitted Could not be validated. For field-specific details,see the 'errors' array.",'instance': '2b647b4f-6e58-439f-8c91-31a3223600a9','errors': [{'field': 'email_address','message': 'This value should not be blank.'}]}

我的 models.py 文件是:

class MarketingPreference(models.Model):
    user                    =models.OnetoOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
    subscribed              =models.BooleanField(default=True)
    mailchimp_subscribed    = models.NullBooleanField(blank=True)
    mailchimp_msg           =models.TextField(null=True,blank=True)
    timestamp               =models.DateTimeField(auto_Now_add=True)
    updated                 =models.DateTimeField(auto_Now=True)

    def __str__(self):
        return self.user.email

def marketing_pref_create_reciever(sender,instance,created,*args,**kwargs):
    if created:
        status_code,response_data = Mailchimp().subscribe(instance.user.email)
        print(status_code,response_data)
post_save.connect(marketing_pref_create_reciever,sender=MarketingPreference)


def marketing_pref_update_reciever(sender,**kwargs):
    if instance.subscribed != instance.mailchimp_subscribed:

        if instance.subscribed:
            #subscribing user
            status_code,response_data = Mailchimp().subscribe(instance.user.email)
        else:
            #unsubscribing user
            status_code,response_data = Mailchimp().unsubscribe(instance.user.email)
        if response_data['status'] =='subscribed':
            instance.subscribed = True
            instance.mailchimp_subscribed = True
            instance.mailchimp_msg = response_data
        else:
            instance.subscribed = False
            instance.mailchimp_subscribed = False
            instance.mailchimp_msg = response_data


pre_save.connect(marketing_pref_update_reciever,sender=MarketingPreference)


def make_marketing_pref_reciever(sender,**kwargs):
    if created:
        MarketingPreference.objects.get_or_create(user=instance)

post_save.connect(make_marketing_pref_reciever,sender=settings.AUTH_USER_MODEL)

我的 utils.py 是:

MAILCHIMP_API_KEY = getattr(settings,"MAILCHIMP_API_KEY",None)
MAILCHIMP_DATA_CENTER = getattr(settings,"MAILCHIMP_DATA_CENTER",None)
MAILCHIMP_EMAIL_LIST_ID = getattr(settings,"MAILCHIMP_EMAIL_LIST_ID",None)

def check_email(email):
    if not re.match(r".+@.+\..+",email):
        raise ValueError("String passed is not a valid email address")
    return email

def get_subscriber_hash(member_email):
    #check email
    check_email(member_email)
    member_email = member_email.lower().encode()
    m = hashlib.md5(member_email)
    return m.hexdigest()


class Mailchimp(object):
    def __init__(self):
        super(Mailchimp,self).__init__()
        self.key = MAILCHIMP_API_KEY
        self.api_url = "https://{dc}.api.mailchimp.com/3.0/".format(dc=MAILCHIMP_DATA_CENTER)
        self.list_id = MAILCHIMP_EMAIL_LIST_ID
        self.list_endpoint = '{api_url}/lists/{list_id}'.format(api_url=self.api_url,list_id=self.list_id)

    def get_members_endpoint(self):
        return self.list_endpoint + "/members"


    def change_subscription_status(self,email,status='unsubscribed'):
        hashed_email = get_subscriber_hash(email)
        endpoint = self.get_members_endpoint() +"/" + hashed_email
        data = {
            "status":self.check_valid_status(status)
        }
        r = requests.put(endpoint,auth=("",self.key),data=json.dumps(data))
        return r.status_code,r.json()

    def check_subscription_status(self,email):
        hashed_email = get_subscriber_hash(email)
        endpoint = self.get_members_endpoint() +"/" + hashed_email
        r = requests.get(endpoint,self.key))
        return r.status_code,r.json()


    def check_valid_status(self,status):
        choices = ['subscribed','unsubscribed','cleaned','pending']
        if status not in choices:
            raise ValueError("not a valid choice for email status")
        return status

    def add_email(self,email):
       status = "subscribed"
       self.check_valid_status(status)
       data = {
           "email_address":email,"status":  status
       }
       endpoint = self.get_members_endpoint()
       r = requests.post(endpoint,data=json.dumps(data))
       return self.change_subscription_status(email,status='subscribed')


    def unsubscribe(self,email):
        return self.change_subscription_status(email,status='unsubscribed')

    def subscribe(self,status='subscribed')

    def pending(self,status='pending')

mixins.py 是:

from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt

class CsrfExemptMixin(object):
    @method_decorator(csrf_exempt)
    def dispatch(self,request,**kwargs):
        return super(CsrfExemptMixin,self).dispatch(request,**kwargs)

我的 views.py 是:

from .mixins import CsrfExemptMixin
from .models import MarketingPreference
from . utils import Mailchimp
MAILCHIMP_EMAIL_LIST_ID = getattr(settings,None)
# Create your views here.

class MarketingPreferenceUpdateView(SuccessMessageMixin,UpdateView):
    form_class = MarketingPreferenceForm
    template_name = 'base/forms.html'
    success_url = '/settings/email/'   #this is a builtin method and by default it will go to marketig preference
    success_message = 'Your email preferences have been updated. Thank you'

    def dispatch(self,**kwargs): #when user came with incognito email will not show to him it will redirect him back to login page
        user = self.request.user
        if not user.is_authenticated:
            return redirect("/login/?next=/settings/email/") #HttpResponse("not allowed",status=400)
        return super(MarketingPreferenceUpdateView,self).dispatch(*args,**kwargs)#(request,*args...)

    def get_context_data(self,**kwargs):
        context = super(MarketingPreferenceUpdateView,self).get_context_data(*args,**kwargs)
        context['title'] = 'Update Email Preference'
        return context

    def get_object(self):
        user = self.request.user
        obj,created =  MarketingPreference.objects.get_or_create(user=user)
        return obj

class MailchimpWebhookView(CsrfExemptMixin,View): #it will not  work because our web application is not deployes yet and webhook mailchimp do not work with local host
    #def get(self,**kwargs):
     #   return HttpResponse('thank you',status=200)
    def post(self,**kwargs):
        data = request.POST
        list_id = data.get('data[list_id]')
        if str(list_id) == str(MAILCHIMP_EMAIL_LIST_ID):  # I CHECK THAT DATA DATA IS THE RIGHT LIST
            hook_type = data.get("type")
            email = data.get('data[email]')
            response_status,response = Mailchimp().check_subscription_status(email)
            sub_status = response['status']
            is_subbed = None
            mailchimp_subbed = None
            if sub_status == "subscribed":
                is_subbed,mailchimp_subbed = (True,True)
            elif sub_status == "unsubscribed":
                is_subbed,mailchimp_subbed = (False,False)
            if is_subbed is not None and mailchimp_subbed is not None:
                qs = MarketingPreference.objects.filter(user__email__iexact=email)
                if qs.exists():
                    qs.update(subscribed=is_subbed,mailchimp_subscribed=mailchimp_subbed,mailchimp_msg=str(data))
        return HttpResponse('thank you',status=200)

解决方法

这里您已经将 request.POST 分配给 data,它现在是一个字典,因此要从字典中获取值,您应该使用表单小部件的字段名称,例如 data == request.POST .
问题是你弄错了密钥。所以你的电子邮件永远是空的

list_id = data.get('data[list_id]')
email = data.get('data[email]')#You are getting wrong key

应该是这样的

list_id = data.get('list_id')
email = data.get('email')