Running test together fails, running test alone succeeds

I'm using pytest.

Going through the tests with a debugger, running both test_joining_previously_entered_queue_returns_previous_queue_details and test_joining_queue_enters_correct_position together, test_joining_previously_entered_queue_returns_previous_queue_details succeeds but test_joining_queue_enters_correct_position fails at queue = get_object_or_404(Queue, pk=kwargs["pk"]) in the JoinQueue view, where the view throws a 404

If I run test_joining_previously_entered_queue_returns_previous_queue_details individually, then the test will pass no problem.

What should happen is that create_company_one creates a Company object, which in turn creates a Queue object (shown in the overridden save method of Company). The associated Queue object does not seem to be created if test_joining_queue_enters_correct_position is run with the other test, but works if the test is run standalone

Why does this happen and how can I fix it?

test_join_queue.py

def create_company_one():

    return Company.objects.create(name='kfc')

@pytest.mark.django_db
def test_joining_previously_entered_queue_returns_previous_queue_details(authenticated_client: APIClient):
    
    create_company_one()
    
    url = reverse('user-queue-join', args=[1])
    
    first_response = authenticated_client.put(url)
    
    first_data = first_response.data
    
    second_response = authenticated_client.put(url)
    
    second_data = second_response.data
    
    assert first_data == second_data

@pytest.mark.django_db
def test_joining_queue_enters_correct_position(factory: APIRequestFactory):
    """
    Makes sure that whenever a user joins a queue, their position is sorted correctly
    based on WHEN they joined. Since all users in self.users join the queue
    in a time canonical manner, we can iterate over them to test for their queue positions.
    """
    
    create_company_one()
    
    users = create_users()
    view = JoinQueue.as_view()
    url = reverse('user-queue-join',args=[1])
    request = factory.put(url)
    for queue_position, user in enumerate(users):
        
        force_authenticate(request, user=user)
        response = view(request, pk=1)
        assert response.data["position"] == queue_position + 1

views.py

class JoinQueue(APIView):

    permission_classes = [IsAuthenticated]

    def put(self, request, *args, **kwargs):

        # throws 404 here

        queue = get_object_or_404(Queue, pk=kwargs["pk"])

        user = request.user

        try:
            queue_details_of_a_user = user.queue_details.get(queue=queue)
        except ObjectDoesNotExist:
            queue_details_of_a_user = QueueDetails.objects.create(user=user, queue=queue)
            serializer = QueueDetailsSerializer(queue_details_of_a_user)
            return Response(serializer.data)
        else:
            serializer = QueueDetailsSerializer(queue_details_of_a_user)
            return Response(serializer.data)

models.py

class Company(models.Model):
    name = models.CharField(max_length=15, unique=True)
    
    def save(self, *args: Any, **kwargs: Any) -> None:
        created = bool(self.pk)
        super().save(*args, **kwargs)
        if not created:
            Queue.objects.create(company=self)
            logging.info(f"{self.name} has created its queue")

        return None

    def __str__(self) -> str:
        return self.name

class Queue(models.Model):
    company = models.OneToOneField(
        Company, on_delete=models.CASCADE, related_name="queue"
    )
    users = models.ManyToManyField(User, through="QueueDetails", related_name="queues")

    @property
    def length(self) -> int:
        return len(self.users.all())

    @property
    def sorted_users(self) -> "QuerySet[User]":
        return self.users.all().order_by("queue_details__joined_at")

    def __str__(self) -> str:
        return f"{self.company}'s queue"


class QueueDetails(models.Model):
    
    joined_at = models.DateTimeField(auto_now_add=True)
    queue = models.ForeignKey(
        Queue,
        related_name="queue_details",
        on_delete=models.CASCADE,
    )
    user = models.ForeignKey(
        User,
        related_name="queue_details",
        on_delete=models.CASCADE,
    )

    @property
    def position(self) -> int:
        for index, user in enumerate(self.queue.sorted_users):
            if user == self.user:
                return index + 1
        raise ValueError("User is not in the queue, Invalid queue position")
Back to Top