Проблема с тестированием пользовательских действий администратора

Столкнулся с некоторыми проблемами при тестировании моих пользовательских действий администратора.

Сначала я могу показать вам пример теста, который работает, и действия, которые он проверяет.

пользовательское действие, модель продукта

   @admin.action(description="Merge selected products")
   def merge_products(self, request, queryset):

    list_of_products = queryset.order_by("created_at")
    list_of_products = list(list_of_products)
    canonical_product = list_of_products[0]
    list_of_products.remove(canonical_product)
    for p in list_of_products:
        for ep in p.external_products.all():
            ep.internal_product = canonical_product
            ep.save()
        p.save()
    canonical_product.save()

связанный тест

class MockRequest(object):
    pass


class ProductAdminTest(TestCase):
    def setUp(self):
        self.product_admin = ProductAdmin(model=Product, admin_site=AdminSite())

        User = get_user_model()
        admin_user = User.objects.create_superuser(
            username="superadmin", email="superadmin@email.com", password="testpass123"
        )
        self.client.force_login(admin_user)

    def test_product_merge(self):
        self.boot1 = baker.make("products.Product", title="Filippa K boots", id=uuid4())
        self.boot2 = baker.make("products.Product", title="Filippa K boots", id=uuid4())
        self.external_product1 = baker.make(
            "external_products.ExternalProduct", internal_product=self.boot1
        )
        self.external_product2 = baker.make(
            "external_products.ExternalProduct", internal_product=self.boot2
        )

        self.assertEqual(self.boot1.external_products.count(), 1)
        self.assertEqual(self.boot2.external_products.count(), 1)

        request = MockRequest()
        queryset = Product.objects.filter(title="Filippa K boots")
        self.product_admin.merge_products(request, queryset)

        self.assertEqual(self.boot1.external_products.count(), 2)
        self.assertEqual(self.boot2.external_products.count(), 0)

Возможно, это не самый красивый тест, но он работает, как и действие.

Приведенный выше код работает как надо, но при попытке протестировать почти идентичное действие, но для другой модели, возникли проблемы.

заказное действие, Брендовая модель

    @admin.action(description="Merge selected brands")
    def merge_brands(self, request, queryset):
        qs_of_brands = queryset.order_by("created_at")
        list_of_brands = list(qs_of_brands)
        canonical_brand = list_of_brands[0]
        for brand in list_of_brands:
            if brand.canonical:
                canonical_brand = brand
        list_of_brands.remove(canonical_brand)

        for brand in list_of_brands:

            brand.canonical_brand = canonical_brand
            brand.save()

            for product in Product.objects.filter(brand=brand):
                product.brand = canonical_brand
                product.save()

        canonical_brand.save()

связанный тест

class MockRequest(object):
    pass


    def setUp(self):
        self.brand_admin = BrandAdmin(model=Brand, admin_site=AdminSite())

        User = get_user_model()
        admin_user = User.objects.create_superuser(
            username="superadmin", email="superadmin@email.com", password="testpass123"
        )
        self.client.force_login(admin_user)


    def test_brand_merge(self):
        self.brand1 = baker.make("brands.Brand", title="Vans")
        self.brand1.canonical_brand = self.brand1
        self.brand1.active = True
        self.brand1.save()

        self.brand2 = baker.make("brands.Brand", title="Colmar")

        self.boot1 = baker.make("products.Product", brand=self.brand1, id=uuid4())
        self.boot2 = baker.make("products.Product", brand=self.brand2, id=uuid4())

        self.assertEqual(self.boot1.brand, self.brand1)
        self.assertEqual(self.boot2.brand, self.brand2)
        self.assertEqual(self.brand1.active, True)
        self.assertEqual(self.brand2.active, False)

        request = MockRequest()
        queryset = Brand.objects.all()

        self.brand_admin.merge_brands(request, queryset)

        self.assertEqual(self.boot1.brand, self.brand1)
        self.assertEqual(self.boot2.brand, self.brand1)
        self.assertEqual(self.brand1.active, True)
        self.assertEqual(self.brand2.active, False)
        self.assertEqual(self.brand1.canonical_brand, self.brand1)
        self.assertEqual(self.brand2.canonical_brand, self.brand1)


На самом деле не обязательно, как работает код выше, но я включил его для контекста.

Действие администрирования продукта работает как при ручной проверке, так и в тестовом пакете. Действие бренда работает как положено при проверке вручную, но в тестовом пакете оно ничего не делает

self.brand_admin.merge_brands(request, queryset)

никак не изменяет тестируемые объекты.

У меня есть еще одно пользовательское действие администратора для модели Brand, и там та же проблема, работает как шарм, когда я пробую вручную, но ничего не делает в тестовом наборе. Из-за этих фактов я предполагаю, что проблема связана с моей настройкой администратора в тестовом наборе, но она идентична настройке администратора, используемой для первого теста, который работает.

Есть идеи?

При необходимости предоставьте больше контекста.

Похоже, что вам нужно обновить объекты из базы данных, в вашем тесте self.brand1, boot1 и т.д. находятся в памяти и не будут автоматически обновляться из базы данных, вам нужно получить новые значения из базы данных

https://docs.djangoproject.com/en/4.0/ref/models/instances/#refreshing-objects-from-database

Если вам нужно перезагрузить значения модели из базы данных, вы можете использовать метод refresh_from_db(). Когда этот метод вызывается без аргументов, происходит следующее:

Все не отложенные поля модели обновляются до значений, имеющихся в базе данных. Все кэшированные отношения очищаются из перезагруженного экземпляра.

После вызова merge_brands необходимо обновить каждый объект.

self.boot1.refresh_from_db()
self.boot2.refresh_from_db()
# etc..       
Вернуться на верх