Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Django QuerySet Object Has No Attribute

I’m trying to add a new action to my OrderAdmin class called "order_shipped", whereby it’ll send an email to the customer informing them that their order has been shipped.

class OrderAdmin(admin.ModelAdmin):
    actions = ['order_shipped'] 

def order_shipped(self, request, obj):
    customer_email = obj.customer.email
    if request.method == 'POST':
       send_mail(
                'Order Shipped',
                'Your order has been shipped. Please expect it within the next 3-5 days. Thank you for your business.',
                EMAIL_HOST_USER,
                [customer_email],
                fail_silently=False
            )
       return HttpResponseRedirect('/admin/store/order')

order_shipped.short_description = 'Send Order Shipped Email'

The problem that I’m having is that I keep getting this error:

'QuerySet' object has no attribute 'customer'.

obj <QuerySet [<Order: 19>]>
request <WSGIRequest: POST '/admin/store/order/'>
self    <OrderAdmin: model=Order site=AdminSite(name='admin')>

If I add a new column called "order_shipped_btn" to the list_display using the code below, it shows the correct email for each customer.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

def order_shipped_btn(self, obj):
    return format_html('<a href="mailto:{}">SEND</a>', obj.customer.email)

What I’m super confused about is why does it work for the later, but not the former? What am I doing wrong with the former?

>Solution :

A QuerySet s a collection of Order objects, not a single Order object, hence obj.customer makes not much sense.

The third parameter of the action is not a single item, but a QuerySet of items, you thus might want to enumerate. To boost performance, we can use .select_related(…) [Django-doc] to avoid an N+1 problem:

def order_shipped(self, request, queryset):
    for obj in queryset.select_related('customer'):
        customer_email = obj.customer.email
        if request.method == 'POST':
            send_mail(
                'Order Shipped',
                'Your order has been shipped. Please expect it within the next 3-5 days. Thank you for your business.',
                EMAIL_HOST_USER,
                [customer_email],
                fail_silently=False,
            )
    return HttpResponseRedirect('/admin/store/order')
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading