Django Отправка электронного письма при создании нового объекта модели
Я хочу отправлять электронное письмо, если пользователь разместил новый заказ. Я хочу сделать функцию отправки электронной почты из моего models.py. Возможно ли это? Я настроил свой settings.py для электронной почты. Я ищу самый простой способ сделать это. Я не хочу трогать мои представления, так что возможно ли это?
#это моя модель заказа
class Order(models.Model):
PENDING_PAYMENT = 'Pending Payment'
ON_HOLD = 'On Hold'
status_choices = [
('Cancel', 'Cancel'),
('Pending Payment', 'Pending Payment'),
('On Hold', 'On Hold'),
('Waiting For Payment', 'Waiting For Payment'),
('Processing', 'Processing'),
('Done', 'Done'),
]
orderstatus_choices = [
('Cancel', 'Cancel'),
('Pending Payment', 'Pending Payment'),
('On Hold', 'On Hold'),
('Waiting For Payment', 'Waiting For Payment'),
('Processing', 'Processing'),
('Done', 'Done'),
]
Ordinary = 'Ordinary'
customer_choices = [
('Ordinary', 'Ordinary'),
('Police', 'Police'),
('RAB', 'RAB'),
('DGIF', 'DGIF'),
('CID', 'CID'),
('NAVY', 'NAVY'),
('Air Force', 'Air Force'),
('Army', 'Army'),
('DB', 'DB'),
('Administration', 'Administration'),
]
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
paymentMethod = models.CharField(max_length=200, null=True, blank=True)
taxPrice = models.DecimalField(max_digits=11, decimal_places=2, null=True, blank=True)
shippingPrice = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
totalPrice = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
isPaid = models.BooleanField(default=False)
paidAt = models.DateTimeField(auto_now_add=False, null=True, blank=True)
isDelivered = models.BooleanField(default=False)
deliverAt = models.DateTimeField(auto_now_add=False, null=True, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=220, choices=status_choices, default=PENDING_PAYMENT)
orderStatus= models.CharField(max_length=220, choices=orderstatus_choices, default=ON_HOLD, blank=True, null=True)
customerType = models.CharField(max_length=200, blank=True, null=True, choices=customer_choices, default=Ordinary)
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self._id)
Да, вы можете это сделать. Но, вероятно, не стоит. Он будет пытаться отправить письмо, пока пользователь ждет завершения запроса, что в целом заставит его ждать дольше (плохой пользовательский опыт), а также может произойти таймаут соединения с почтовым сервером, и пользователь увидит ошибку только потому, что вы не смогли отправить письмо в данный момент.
Пересмотрите подход и попробуйте отправить письмо либо через очередь задач, либо через cronjob. Если вы настаиваете на прямом подходе, вы можете вставить условие типа if not self.pk
в метод save()
class Order(models.Model):
def save(self, *args, **kwargs):
# model does not have primary key, it's a new order then
if not self.pk:
self.send_order_email()
return super().save(*args, **kwargs)
Лучшим (но все же не рекомендуемым) подходом было бы запустить его в представлении, поскольку таким образом логика электронной почты не будет связана непосредственно с сохранением новой модели заказа, а с представлением, в котором заказ завершен (это два разных случая, даже если они выглядят одинаково, например, вы можете создавать модели в тестах и не хотите подражать электронной почте в каждом случае).
примечание: согласно PEP8, в именах переменных следует использовать snake_case
вместо camelCase
(например, is_delivered
вместо isDelivered
)
Да, Вы можете использовать функцию post_save сигналов Django. Используя сигналы, вы можете отправить письмо пользователю, не трогая файл представления, а также получить доступ к любому из ваших полей, например, _id в вашем случае.
from django.db.models.signals import pre_save
from django.dispatch import receiver
@receiver(pre_save, sender=Order)
def send_email(sender, instance, **kwargs):
obj_id = instance._id
# your code to send email
...
Вы можете прочитать больше о сигналах django в официальной документации также https://docs.djangoproject.com/en/3.2/topics/signals/