Search code examples
pythondjangopostgresqldjango-tests

Test fails with `django.db.utils.IntegrityError`


My test case gives me following error.

django.db.utils.IntegrityError: insert or update on table "django_admin_log" violates foreign key constraint "django_admin_log_user_id_c564eba6_fk_auth_user_id" DETAIL: Key (user_id)=(1) is not present in table "auth_user".

In my view class I have a log entry, during the test request.user.id is always None. so it use anonymous_user which is id = 1. (If I commented out the LogEntry.objects.log_action(), the test pass)

My view class:

class MyView(CreateAPIView):
    # For admin LogEntry
    anonymous_user_id = get_anonymous_user_id()

    def post(self, request, *args, **kwargs):
        """
        ...
        """

        LogEntry.objects.log_action(
            user_id=request.user.id or self.anonymous_user_id,
            content_type_id=self.content_type_id,
            object_id=target.id,
            object_repr=str(target),
            action_flag=ADDITION,
            change_message='message',
        )

        return Response({}, status=status.HTTP_200_OK)

My test:

def test_myview_append_api_works(self):

    def myview_append(url, p1, p2):
        resp = None
        resp = self.client.post(url, data={'paraphrase': p1, 'data_id': p2})
        return resp

    url = reverse('api-my_data:paraphrase_append')
    current_qa = Qa.objects.all()[0]  # get current existing qa = the qa created in the setUp

    p1 = 'test paraphrase'
    p2 = target.id
    resp = myview_append(url, p1, p2)
    self.assertEqual(resp.status_code, status.HTTP_200_OK)

I Tried using request_factory to set user in request but it didn't work

        request = self.request_factory.post(url,  data={'paraphrase': p1, 'qa_id': p2})
        request.user = self.user

        resp = MyView.as_view()(request)

Can any one help me with this test.


Solution

  • LogEntry.user requires an actual user record in your database. As a part of your setUp code in your test you need to create a user whose id will map to the id that's returned by get_anonymous_user_id.

    Side note, you're heading down a path of pain with

    class MyView(CreateAPIView):
        # For admin LogEntry
        anonymous_user_id = get_anonymous_user_id()
    

    If for some reason the data changes such that get_anonymous_user_id would return a different value, the server will need to restart in order to update this value as the class will be loaded into memory. The other potential problem is that if get_anonymous_user_id hits the database, it means as your class is being loaded into memory, it's running hitting the database. If that sql query were to perform poorly then it's going to take longer to deploy.