Я пытаюсь получить все обновленные значения в модели и отправить пользователям электронное письмо об изменениях в django - PullRequest
0 голосов
/ 01 мая 2018

У меня есть модель A, которая имеет отношение много к одному с другой моделью B, я хочу получить возможность отправлять уведомления по электронной почте на электронные письма, которые будут запрашиваться из модели B при любом изменении значений в модели A, как я могу сделать это в Django?

class ModelA(models.Model):
    """
    model to store informations about the ModelA
    """

    name = models.CharField(max_length=15, blank=True, unique=True)
    creator = models.ForeignKey(AppUser, blank=True, null=True, on_delete=models.CASCADE)
    periodicity = models.CharField(max_length=10, blank=False, choices=PERIODICITY_CHOICES)
    begin_date = models.DateField(blank=False)
    end_date = models.DateField(blank=True, null=True)
    subscription_fee = models.DecimalField(max_digits=5, decimal_places=2, blank=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    public = models.BooleanField(default=False)
    maximum_sub = models.PositiveIntegerField(blank=True, null=True, validators=[MinValueValidator(2)])

    def save(self):
        emails = []
        body = """
        Hello <user first name or nothing>,
        This is to notify you that ModelA you're subscribed to has been updated. Here is what has changed:
        <field_name_1>: <current_value>
        <field_name_2>: <current_value>
        etc...
        Thank you
        """
        if self.pk is not None:
            modelA_id = ModelA.objects.get(pk=self.pk)
            modelA_members = ModelB.objects.filter(pk=modelA_ID)
            emails = [i for i in modelA_members.email]
            send_mail('ModelA change Notification', body, "noreply@example.com", [emails])
        super(ModelB, self).save() #

    def __unicode__(self):
        return u'{0}'.format(self.name)

class ModelB(models.Model):
    """
    defineModelB

    """

    modelA = models.ForeignKey(ModelA, on_delete=models.CASCADE, blank=False)
    user = models.ForeignKey(AppUser, on_delete=models.CASCADE, blank=False, )
    cash_out_date = models.DateField(blank=True, null=True)

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Хорошо, так что это один из способов решить вашу проблему обнаружения «измененных полей» и автоматической отправки электронной почты:

Вот как это работает. Миксин переопределяет класс init и сохраняет существующие значения в атрибуте с именем self.__initial. Ваши новые значения находятся в self._dict, а разница между ними - измененные значения, это фиксируется свойством diff. Мы можем использовать diff, чтобы получить словарь {key: (old_value, new_value)}, который вы затем сможете использовать в своих шаблонах

class ModelA(ModelDiffMixin, models.Model):
    pass  # Your code goes here

    def save(self):
        changed_fields = self.diff
        for key, old, new in changed_fields.items():
            # Do something here with the values

        emails = []
        body = """
        Hello <user first name or nothing>,
        This is to notify you that ModelA you're subscribed to has been updated. Here is what has changed:
        <field_name_1>: <current_value>
        <field_name_2>: <current_value>
        etc...
        Thank you
        """
        if self.pk is not None:
            modelA_id = ModelA.objects.get(pk=self.pk)
            modelA_members = ModelB.objects.filter(pk=modelA_ID)
            emails = [i for i in modelA_members.email]
            send_mail('ModelA change Notification', body, "noreply@example.com", [emails])
        super(ModelB, self).save() #





class ModelDiffMixin(object):  # Credit to ivanperelivskiy here: /1326949/django-pri-sohranenii-kak-vy-mozhete-proverit-izmenilos-li-pole
    """
    A model mixin that tracks model fields' values and provide some useful api
    to know what fields have been changed.
    """

    def __init__(self, *args, **kwargs):
        super(ModelDiffMixin, self).__init__(*args, **kwargs)
        self.__initial = self._dict

    @property
    def diff(self):
        d1 = self.__initial
        d2 = self._dict
        diffs = [(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]]
        return dict(diffs)

    @property
    def has_changed(self):
        return bool(self.diff)

    @property
    def changed_fields(self):
        return self.diff.keys()

    def get_field_diff(self, field_name):
        """
        Returns a diff for field if it's changed and None otherwise.
        """
        return self.diff.get(field_name, None)

    def save(self, *args, **kwargs):
        """
        Saves model and set initial state.
        """
        super(ModelDiffMixin, self).save(*args, **kwargs)
        self.__initial = self._dict

    @property
    def _dict(self):
        return model_to_dict(self, fields=[field.name for field in
                             self._meta.fields])
0 голосов
/ 01 мая 2018

Вы преуспели, переопределив метод сохранения, чтобы получить доступ ко всем modelB, связанным с экземпляром modelA, вы должны использовать обратный запрос related_name

Class ModelA(models.Model):

    def save(self,*args,**kwargs):
        if self.pk is not None:
            body = """
               Hello <user first name or nothing>,
               This is to notify you that ModelA you're subscribed to has been updated. Here is what has changed:
               <field_name_1>: <current_value>
               <field_name_2>: <current_value>
               etc...
               Thank you
           """
            modelB_members = self.modelb_set.all()
            emails = [i.user.email for i in modelB_members]
            send_mail('ModelA Change Notification', body, "noreply@example.com", [emails])
        super(ModelA, self).save(*args,**kwargs) #


class ModelB(models.Model):
    modelA = models.ForeignKey(ModelA, on_delete=models.CASCADE, blank=False)
    user = models.ForeignKey(AppUser, on_delete=models.CASCADE, blank=False, )
    cash_out_date = models.DateField(blank=True, null=True)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...