I’m trying to use TestCase and setUpTestData() to create a test of a model. There are several problems in the below code (marked with "TODO"s), but right now I’m just focusing on the users_following_cause=cls.user
part where I was trying to set up a M2M field for the test data. I’ve tried a few iterations based on online answers but all throw errors and I’m still struggling. The full error message when I use the code shown in this post is:
============================================================================ ERRORS ============================================================================
______________________________________________ ERROR at setup of CauseTests.test_cause_createview_anonymous_user _______________________________________________
cls = <class 'causes.tests.CauseTests'>
@classmethod
def setUpTestData(cls):
cls.user = get_user_model().objects.create_user(
username="testuser1",
email="test@email.com",
password="testpass123",
)
> cls.cause = Cause.objects.create(
#date_added is auto_now so it fills this field in automatically
cause_name="Cause Name",
created_by=cls.user,
users_following_cause=cls.user, # TODO: figure out how to do the testing for now M2M fields...
)
causes/tests.py:18:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/django/db/models/manager.py:85: in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
.venv/lib/python3.10/site-packages/django/db/models/query.py:512: in create
obj = self.model(**kwargs)
.venv/lib/python3.10/site-packages/django/db/models/base.py:554: in __init__
_setattr(self, prop, kwargs[prop])
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x112239150>, instance = <Cause: Cause Name>, value = <CustomUser: testuser1>
def __set__(self, instance, value):
> raise TypeError(
"Direct assignment to the %s is prohibited. Use %s.set() instead."
% self._get_set_deprecation_msg_params(),
)
E TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use users_following_cause.set() instead.
.venv/lib/python3.10/site-packages/django/db/models/fields/related_descriptors.py:595: TypeError
=================================================================== short test summary info ====================================================================
ERROR causes/tests.py::CauseTests::test_cause_createview_anonymous_user - TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use users_following_cause.set() instead.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
======================================================================= 1 error in 1.26s =======================================================================
Other things I’ve tried
The error message clearly says TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use users_following_cause.set() instead.
but I’m just struggling to understand how to do this. Among many other things, I’ve tried:
users_following_cause=users_following_cause.set(cls.user)
which results in this error:NameError: name 'users_following_cause' is not defined
users_following_cause=cls.cause.users_following_cause.set(cls.user)
which results in this error:AttributeError: type object 'CauseTests' has no attribute 'cause'
My Question
Can you please help me understand how to add a M2M field to a test?
tests.py
class CauseTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.user = get_user_model().objects.create_user(
username="testuser1",
email="test@email.com",
password="testpass123",
)
cls.cause = Cause.objects.create(
#date_added is auto_now so it fills this field in automatically
cause_name="Cause Name",
created_by=cls.user,
users_following_cause=cls.user, # TODO: figure out how to do the testing for now M2M fields
)
def test_cause_model(self):
#self.assertEqual(self.cause.date_added, ) TODO: figure out how to do the testing for "now" when the "now" of the creation and the "now" of the test is different
self.assertEqual(self.cause.cause_name, "Cause Name")
self.assertEqual(self.cause.created_by.username, "testuser1")
#self.assertEqual(self.cause.users_following_cause.email, "test@email.com") # TODO: figure out how to do the testing for now M2M fields
self.assertEqual(str(self.cause), "Cause Name")
#self.assertEqual(self.cause.get_absolute_url(), "/causes/1/") # TODO: figure out how to do this when pk is UUID?
models.py
CustomUser = get_user_model()
class Cause(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False)
date_added = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
cause_name = models.CharField(max_length=100)
users_following_cause = models.ManyToManyField(CustomUser, related_name="causes_user_follows", blank=True)
def __str__(self):
return self.cause_name
def get_absolute_url(self):
return reverse("cause_detail", args=[str(self.id)])
Thank you in advance.