Custom actions in Django Admin

Question:

In my Django app, I have a Newsletter model. Now I’d like to be able to send the newsletter (and even resend it) from Django Admin.

I could do this with a hook on the Model.save() method but is there another way that is not tied to the Model?

Thanks.

Asked By: Lorenzo

||

Answers:

Admin actions allow you to easily hook up custom actions which can be performed on selected items from the admin’s list pages.

Answered By: Jonny Buchanan

If you are doing it from the admin then you’ll need to override the save() method, but it can be the AdminModel save… doesn’t need to be the full Model save.

However, if you are emailing a lot of emails, a better approach would be to install django-mailer which puts emails into a queue for later processing and then provides you with a new management command: send_mail.

So once you’re ready to send the newsletter out you can manually run python manage.py send_mail. Any emails with errors will be moved to a deferred queue where you can retry sending them later.

You can automate this by running manage.py send_mail from cron.

If you really want to get fancy and do it from admin site, install django-chronograph and set up your send_mail schedule from there.

Answered By: Van Gale

You can try this YouTube tutorial. Just change:

def available(modeladmin, request, queryset):
    queryset.update(status='ava')

def not_available(modeladmin, request, queryset):
    queryset.update(status='not')

to something like this:

def send(modeladmin, request, queryset):
    for data in queryset:
        subject=data.title
        message=data.mesage
           
        for d in Users.objects.filter(newsletter=True):
            email=d.email
            sendemail = EmailMessage(
                subject, message + unsubscribe,
                '[email protected]',
                [email], [],
                headers = {'Reply-To': '[email protected]'}
            )
            sendemail.content_subtype = "html" 
              
            sendemail.send()
Answered By: blaz1988

2022 Update:

django.__version__ == 4.1 and maybe ealier.

You can add a custom action at /admin/.../change by overriding django.contrib.admin.options.ModelAdmin._changeform_view:

from django.contrib import admin 

class MyModelAdmin(admin.ModelAdmin): 

    def _changeform_view(self, request, object_id, form_url, extra_context):

        if '<your-action>' in request: 
            # 1. check permissions
            # 2. do your thing 
            print(request)
        
        return super()._changeform_view(request, object_id, form_url, extra_context)

You can now add simple sumbit button to your form with your custom action:

<input type="submit" name="<your-action>" value="<button-title>">

Advantage

  • Zero javascript.
  • Authentication (CSRF) protected.
  • All stock admin actions will work with your form (add, save and continue, …)
Answered By: Sy Ker

You can create custom django admin actions.

For example, I have Person model below:

# "store/models.py"

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=30)
    
    def __str__(self):
        return self.name

Now, I created uppercase() and lowercase() admin actions in Person admin as shown below. *actions = ("uppercase", "lowercase") is necessary to display uppercase() and lowercase() admin actions:

# "store/admin.py"

from django.contrib import admin, messages
from .models import Person

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    
    actions = ("uppercase", "lowercase") # Necessary 
    
    @admin.action(description='Make selected persons uppercase')
    def uppercase(modeladmin, request, queryset):
        for obj in queryset:
            obj.name = obj.name.upper()
            obj.save()
            messages.success(request, "Successfully made uppercase!")

    @admin.action(description='Make selected persons lowercase')
    def lowercase(modeladmin, request, queryset):
        for obj in queryset:
            obj.name = obj.name.lower()
            obj.save()
            messages.success(request, "Successfully made lowercase!")

Then, if I select 2 persons and Make selected persons uppercase then click on Go as shown below:

enter image description here

I can make 2 persons uppercase as shown below:

enter image description here

Then, if I select 2 persons and Make selected persons lowercase then click on Go as shown below:

enter image description here

I can make 2 persons lowercase as shown below:

enter image description here

In addition, if I remove @admin.action() as shown below

# "store/admin.py"
    
    # ...
    
    # @admin.action(description='Make selected persons uppercase')
    def uppercase(modeladmin, request, queryset):
        for obj in queryset:
            obj.name = obj.name.upper()
            obj.save()
            messages.success(request, "Successfully made uppercase!")

    # @admin.action(description='Make selected persons lowercase')
    def lowercase(modeladmin, request, queryset):
        for obj in queryset:
            obj.name = obj.name.lower()
            obj.save()
            messages.success(request, "Successfully made lowercase!")

Actual function names are displayed as shown below:

enter image description here

Answered By: Kai – Kazuya Ito