Отправка почты с absolute_uri при создании модели (без объекта запроса)
Я пытаюсь сделать что-то, что кажется относительно простым, но я полностью в тупике. У меня есть модель, и я хочу отправить электронное письмо после первого создания экземпляра. Я могу сделать это достаточно легко, используя это:
@receiver(models.signals.post_save, sender=MyModel)
def execute_after_save(sender, instance, created, *args, **kwargs):
if created:
send_mail(mail_type='MyModel_created', instance=instance)
Однако проблема в том, что мне нужно отправить ссылку в электронном письме на представление изменения модели в админ-панели. Я использовал такой код (в других случаях) для создания ссылки внутри функции send_mail(), упомянутой выше:
mymodel_admin_url = request.build_absolute_uri(reverse('admin:mymodels_mymodel_change', args=(instance.id,)))
Но вы заметите, что это зависит от наличия объекта запроса, который не передается ни через сигнал post_save, ни даже от метода save. Какой лучший способ получить нужную мне ссылку в этом случае?
Перестройка и переопределение всего (т.е. метода сохранения, метода base_save, сигнала post_save и т. Д.) Для прохождения запросов кажется кошмаром. Однако я не могу получить нужную ссылку с помощью каркаса сайтов (иногда я использую сайт на поддоменах или, например, при использовании runserver manage.py для тестирования, и вызов каркаса сайтов не создает правильные ссылки).
1 ответ
Есть ли способ использовать структуру сайтов для возврата истинного абсолютного URL, например request.build_absolute_uri()
делает?
Проблема в том, что, как правило, нет истинного абсолютного URL. Django может прекрасно работать без веб-сервера, генерируя электронные письма, сохраняя модели (и вызывая сигнал после сохранения) и т. Д. И если есть веб-сервер, у Django нет возможности узнать, какие доменные имена он обслуживает, что Вот почему вам нужен объект запроса и почему вам нужны такие настройки, какALLOWED_HOSTS
, так далее.
Общий способ справиться с этим - явным образом сообщить Django, какой сайт он обслуживает. Например, у вас будет свой файл настроек для каждого дистрибутива, и каждый из этих файлов будет указывать, какое доменное имя он должен использовать (через SITE_ID
настройки, если вы используете sites
фреймворк; или вы можете указать это явно с вашей собственной настройкой). Использование разных файлов настроек для разных серверов является обычной практикой.
Теперь, в вашем конкретном случае, похоже, что сохранение запускается изнутри веб-запроса (через администратора?), Поэтому, если вы можете получить этот запрос, вы можете использовать его доменное имя для создания вашей ссылки. Django не предоставляет никакого способа получить этот запрос, кроме как в качестве аргумента. Вы не первый, кто хочет этого, поэтому, если вы ищете "глобальный запрос Django", вы можете увидеть, как другие подошли к проблеме. Эта статья, например, представляет пару идей, и это приложение разработано, чтобы "дать доступ к Django's HTTPRequest
объект всякий раз, когда это необходимо, без явной передачи его по пути кода ".