Sending mail with absolute_uri on model creation (no request object)

I'm trying to do something that seems relatively simple, but I'm completely stumped. I have a model and I want to send an email as soon as the instance is created the first time. I can do it quite easily using this:

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

      

However, the problem is that I need to send the link in an email to the change model window in the admin panel. I used code like this (in other cases) to create a link inside the send_mail () function mentioned above:

mymodel_admin_url = request.build_absolute_uri(reverse('admin:mymodels_mymodel_change', args=(instance.id,)))

      

But you will notice that it depends on the presence of a request object that is not passed through the post_save signal, and even the save method. What's the best way to get the link I need in this case?

Restoring and redefining everything (i.e. save method, base_save method, post_save signal, etc.) to pass requests through seems like a nightmare. However, I cannot get the link I need using the site infrastructure (sometimes I use the site on subdomains, or for example when using the run.py server for testing and the site structures do not build the correct links when I call) ...

+3


source to share


1 answer


Is there a way to use the site structure to return a true absolute url, for example request.build_absolute_uri()

?

The problem is that there is generally no true absolute url. Django works fine without a web server, generates emails, saves models (and fires a signal after saving), etc. And if there is a web server, Django doesn't know what domain names it serves, what why you need the request object, and why you need settings like ALLOWED_HOSTS

etc.



A general way you could handle this would be to tell Django explicitly which site it serves. For example, you will have a different settings file for each distribution, and each of those files will specify which domain name it should use (with a parameter SITE_ID

if you are using a framework sites

, otherwise you could specify this explicitly with your own customization). It is common practice to use different configuration files for different servers.

Now, in your specific case, it looks like the save is being triggered from within a web request (via admin?), So if you can get that request, you can use its domain name to generate your link. Django does not include any way to get this request, except that it is passed as an argument. However, you are not the first to want this, so if you are looking for "global Django request" you can see how others have approached this problem. This article , for example, presents a few ideas, and this application is designed to "provide access to a Django object HTTPRequest

whenever needed, without explicitly wrapping it in the code path."

+2


source







All Articles