Django Admin Inline Form не работает в тесте, но работает в интерфейсе администратора

Я в растерянности, почему следующий пример не работает в тестовом случае, но прекрасно работает в интерфейсе администратора.

У меня есть очень простые модели User и Login. Модель Login просто записывает логины пользователей в систему через Django signal.

class User(AbstractUser):

    company = models.CharField(
        max_length=100, blank=True, null=True
    )


class Login(models.Model):
    """Represents a record of a user login event."""

    user = models.ForeignKey(
        get_user_model(), on_delete=models.CASCADE, related_name="logins"
    )

    ip = models.GenericIPAddressField()
    user_agent = models.TextField()
    date = models.DateTimeField(auto_now_add=True, db_index=True)

    domain = models.CharField(max_length=255)

    http_host = models.CharField(null=True, max_length=255)
    remote_host = models.CharField(null=True, max_length=255)
    server_name = models.CharField(null=True, max_length=255)

В admin.py я определяю UserAdmin с inlines = [LoginInline]. В принципе, при просмотре пользователя я могу видеть историю входа.

from django.contrib import admin
from django.contrib.auth import admin as auth_admin
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils.html import format_html

from users.models import Login

User = get_user_model()

class ReadOnlyModelMixin:
    def has_add_permission(self, request, obj=None):
        return False

    def has_change_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


class LoginAdmin(ReadOnlyModelMixin, admin.ModelAdmin):
    list_display = (
        'id',
        'user_link_with_name',
        'user_email',
        'user_company',
        'domain',
        'date',
        'ip',
        'remote_host',
        'http_host',
        'server_name',
        'user_agent',
    )

    @admin.display(description='Name', ordering='user__first_name')
    def user_link_with_name(self, obj):
        url = reverse("admin:users_user_change", args=[obj.user.id])
        return format_html(f'<a href="{url}">{obj.user}</a>')

    @admin.display(description='Email', ordering='user__email')
    def user_email(self, obj):
        return format_html(
            f'<a href="mailto:{obj.user.email}">{obj.user.email}</a>'
        )

    @admin.display(description='Company', ordering="user__company")
    def user_company(self, obj):
        return obj.user.company


class LoginInline(ReadOnlyModelMixin, admin.TabularInline):
    model = Login

class UserAdmin(auth_admin.UserAdmin):
    inlines = [LoginInline]

admin.site.register(User, UserAdmin)
admin.site.register(Login, LoginAdmin)

В интерфейсе администратора все работает отлично, я могу просматривать и ADD пользователей без проблем.

Затем я представил тест следующим образом:

class TestUserAdmin:
    def test_add(self, admin_client):
        url = reverse("admin:users_user_add")
        response = admin_client.get(url)
        assert response.status_code == 200

        response = admin_client.post(
            url,
            data={
                "username": "test",
                "password1": "My_R@ndom-P@ssw0rd",
                "password2": "My_R@ndom-P@ssw0rd",
            },
        )
        # below FAILS when UserAdmin includes inlines = [LoginInline]
        assert User.objects.filter(username="test").exists()
        assert response.status_code == 302

строка assert User.objects.filter(username="test").exists() будет FAIL до тех пор, пока у меня есть inlines = [LoginInline], включенный в UserAdmin. Если я закомментирую inline, то тест пройдет.

Я действительно хочу понять, что я упускаю, и почему этот тест не работает, учитывая, что он прекрасно работает в интерфейсе администратора.

Репо, воспроизводящее эту проблему: https://github.com/oizik/django_admin_inline_test_problem

Спасибо.

Вернуться на верх