Reputation: 57381
I'm trying to adapt the answer from Testing custom admin actions in django, but I'm running into some unexpected behavior. I've created a simplified Django app, myapp
, which has a Worker
and Invoice
model:
class Worker(models.Model):
name = models.CharField(max_length=255)
class Invoice(models.Model):
UNPAID = 0
PAID = 1
worker = models.ForeignKey(
'Worker', on_delete=models.CASCADE)
amount = models.DecimalField(
max_digits=10, decimal_places=2)
amount_paid = models.DecimalField(
max_digits=10, decimal_places=2, default=Decimal('0.00'))
status = models.IntegerField(
choices=[(UNPAID, 'Unpaid'), (PAID, 'Paid')], default=0)
I've create a custom admin action called mark_as_paid
which changes the status of the selected invoices to Invoice.PAID
in admin.py
:
from django.contrib import admin
from django.db.models import F
from .models import Invoice
@admin.register(Invoice)
class InvoiceAdmin(admin.ModelAdmin):
list_display = ('worker', 'status', 'amount', 'amount_paid')
actions = ['mark_as_paid']
def mark_as_paid(self, request, queryset):
queryset.update(amount_paid=F('amount'))
I'm trying to test this like so:
from decimal import Decimal
from django.contrib import admin
from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse
from myapp.models import Invoice, Worker
class InvoiceAdminTests(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='foobar',
email='[email protected]',
password='barbaz',
is_superuser=True)
self.client.force_login(user=self.user)
def test_mark_as_paid(self):
worker = Worker.objects.create(name="John Doe")
invoice = Invoice.objects.create(
worker=worker, amount=Decimal('100.00'))
response = self.client.post(
reverse('admin:myapp_invoice_changelist'),
data={
'action': 'mark_as_paid',
admin.ACTION_CHECKBOX_NAME: [invoice.id]})
import ipdb; ipdb.set_trace()
invoice.refresh_from_db()
self.assertEqual(invoice.amount_paid, Decimal('100.00'))
I've set a debugger trace in the test, but ultimately I would expect it to pass. Currently, however, it is failing because invoice.amount_paid
is still Decimal('0.00')
.
Strangely, the response has a status code of 302 (not 200) and empty content:
ipdb> response.status_code
302
ipdb> response.content
b''
I've also set a trace in the mark_as_paid()
method and it's not getting hit, so I suspect there is something wrong about the way I'm mocking the authentication of the user, since if I create a superuser with python manage.py createsuperuser
and test this manually, everything works as expected.
Any idea what is wrong with this approach?
Upvotes: 0
Views: 1412
Reputation: 57381
Looking at the example at Testing custom admin actions in django more closely, it turns out I need to use the create_superuser()
method instead of create_user()
with is_superuser=True
. The test passes with the following modified setUp()
method:
class InvoiceAdminTests(TestCase):
def setUp(self):
self.user = User.objects.create_superuser(
username='foobar',
email='[email protected]',
password='barbaz')
self.client.force_login(user=self.user)
Upvotes: 4