Django / Pytest / Splinter : IntegrityError дублирование ключа только в тесте

Я знаю, что это очень распространенная проблема, и я читал много подобных вопросов. Но я не могу найти никакого решения, и вот я здесь, с 987-м вопросом на Stackoverflow об ошибке Django Integrity.

Я начинаю проект Django с базой данных Postgres, чтобы познакомиться с фреймворком. Я сделал классическое создание профиля для пользователей, автоматизированное с помощью сигнала post_save. Вот модель:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    description = models.TextField(max_length=280, blank=True)
    contacts = models.ManyToManyField(
        "self",
        symmetrical=True,
        blank=True
    )

А это сигнал, который идет вместе с ним :

def create_profile(sender, instance, created, **kwargs):
    if created:
        user_profile = Profile(user=instance)
        user_profile.save()

post_save.connect(create_profile, sender=User, dispatch_uid="profile_creation")

Проект только начинается, и пока я создаю пользователей только в админке. С помощью сигнала post_save предполагается создать профиль с той же формой.

Вот настройка администратора :

class ProfileInline(admin.StackedInline):
    model = Profile

class UserAdmin(admin.ModelAdmin):
    model = User
    list_display = ["username", "is_superuser"]
    fields = ["username", "is_superuser"]
    inlines = [ProfileInline]

Я использую pytest и Splinter для тестирования, и вот интеграционный тест, который не работает :

@pytest.mark.django_db
class TestAdminPage:
    def test_profile_creation_from_admin(self, browser, admin_user):
        browser.visit('/admin/login/')

        username_field = browser.find_by_css('form input[name="username"]')
        password_field = browser.find_by_css('form input[name="password"]')

        username_field.fill(admin_user.username)
        password_field.fill('password')

        submit = browser.find_by_css('form input[type="submit"]')
        submit.click()

        browser.links.find_by_text("Users").click()
        browser.links.find_by_partial_href("/user/add/").click()
        
        browser.find_by_css('form input[name="username"]').fill('Super_pseudo')
        browser.find_by_css('textarea[name="profile-0-description"]').fill('Super description')

        browser.find_by_css('input[name="_save"]').click()

        assert browser.url is '/admin/auth/user/'
        assert Profile.objects.last().description is 'Super description'

Когда я запускаю это, я получаю эту ошибку :

django.db.utils.IntegrityError: duplicate key value violates unique constraint "profiles_profile_user_id_key"
DETAIL:  Key (user_id)=(2) already exists.

Сначала я также увидел эту ошибку при создании пользователя на локальном сервере. Но только если я писал описание. Если я оставлял поле описания пустым, все работало нормально. Поэтому я написал этот интеграционный тест, чтобы решить проблему. Потом я много читал, кое-что подправил, и ошибка перестала возникать в моем локальном браузере. Но не в моем тестовом наборе.

Поэтому я использовал точку останова, там :

def create_profile(sender, instance, created, **kwargs):
    breakpoint()
    if created:
        user_profile = Profile(user=instance)
        user_profile.save()

И вот тут начинается самое интересное. Этот единственный тест вызывает сигнал 3 раза.

В первый раз он вызывается используемым мной приспособлением admin_user.

(Pdb) from profiles.models import Profile
(Pdb) instance
<User: admin>
(Pdb) created
True
(Pdb) instance.profile
*** django.contrib.auth.models.User.profile.RelatedObjectDoesNotExist: User has no profile.
(Pdb) Profile.objects.count()
0
(Pdb) continue

Кажется законным, у пользователя admin нет профиля, почему бы и нет. Затем сигнал вызывается снова на том же экземпляре.

(Pdb) instance
<User: admin>
(Pdb) instance.profile
<Profile: admin>
(Pdb) Profile.objects.count()
1
(Pdb) Profile.objects.last()
<Profile: admin>
(Pdb) created
False
(Pdb) continue

Все еще законно, странно, но это ничего не делает. created - False, поэтому он не создает второй профиль. Первый не нужен, но это не делает тест неудачным. И тут :

(Pdb) instance
<User: Super_pseudo>
(Pdb) created
True
(Pdb) instance.profile
<Profile: Super_pseudo>
(Pdb) Profile.objects.count()
1
(Pdb) Profile.objects.last()
<Profile: admin>

Это так странно. Профиль не сохраняется, но все равно выдает ошибку целостности. Он выглядит инстанцированным, когда я вызываю instance.profile, я получаю что-то, но не похоже, что он сохранен в базе данных. Но ошибка все равно происходит. Я понятия не имею, я потратил уже несколько часов, и я не знаю, что искать.

Чувствую, что упускаю что-то важное, и поэтому прошу вашей помощи.

Редактирование

Я пробовал обновить сигнал с помощью if created and not kwargs.get('raw', False):, но это не работает.

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