Many-To-Many Default Function Is Not Getting Updated Model Information

Hi, so I’m writing tests for a project, and the function that I’m using to populate the default values for the field seems to be unaware of the creation of other objects. Specifically, in my models.py:

def defaultTags():
    """ Returns a list of the default tags we think users should have """
    print(Tag.objects.all())  # returns <QuerySet []> during testing 
    return Tag.objects.filter(selectedDefault = True)  # also returns <QuerySet []>


# Our basic user class. The AbstractUser class already implements names, email, & username/password
class User(AbstractUser):
    """ User Model - extends AbstractUser Model """
    # Whether they're student, faculty, or community
    TYPES = TYPES  # Need this so User.TYPES works later
    type = models.CharField(choices=TYPES, max_length=3, blank=False, default="COM")
    likedEvents = models.ManyToManyField('Event', blank=True, related_name="likedUsers")
    interestedTags = models.ManyToManyField('Tag', blank=True, default=defaultTags)

I want a user that gets created without any interestedTags provided to just be set to all the tags with selectedDefault as true. I assume it’s not going to change anything, but here’s my Tag model:

class Tag(models.Model):
    """ A model for event filtering tags """
    name = models.CharField(max_length=32, unique=True)
    selectedDefault = models.BooleanField(default=False)

Now, in terms of the test, I create a Tag, and it shows up in the database there, but not when I get the tags in defaultTags:

class APITestCase(TestCase):
    """ Tests for the backend API """
    def setUp(self):
        self.time = timezone.now()
        self.tag = Tag.objects.create(name = "Interesting Events", selectedDefault = True)
        print(Tag.objects.all()) # returns <QuerySet [<Tag: Tag object (1)>]>
        self.user1 = User.objects.create_user(username="admin", password="admintest", type = 'STU')
        print(self.user1.interestedTags.all()) # returns <QuerySet []>

I need to be able to have the default tags update based on the tag default value. Any advice on how to fix this would be appreciated, and let me know if there’s more info I can provide.

I think default values don’t work with many-to-many relations. You need to either use a signal or override the user save method.

Not “automatically”. You’ll have to implement this as part of your logic at the appropriate points. For example, if you add a new Tag with selectedDefault = True, then you’ll need to update every User to add that tag. But that’s all work that you will need to do, Django doesn’t have anything to do that for you.

@KenWhitesell Sorry, I wasn’t clear. When users create an account, I want the tags that get assigned to them by default to update depending on which tags have the selectedDefault set to true (hence the need for a function rather than just giving it a list of tags to assign). I understand that I need to change current users’ tags individually if I want to update them after user creation.

Again, there’s nothing “automatic” about doing something like that.
The only tags that will get assigned are those that you assign to the user.

So it is not possible to even initialize a m2m field with a default set of associations? If it is, which was my understanding, then could I not just provide it with a list of preset tags? If can do that, then why is there any difference in the “automaticness” if I’m just generating that list on the spot instead of hardcoding it? What if I stored that list in a file that another script updated every hour? That feels like the same as hardcoding but is (on a high level) as “automatic” as generating the list live using Tag.objects.filter

And, just a conceptual question here, why does the defaultTags function seem to have a different scope than the setUp function that’s calling it, at least when it comes to the Tags.objects call?

I’m not trying to be contrarian here, and I’ve used your answers on this forum before, so I really respect how committed you are to helping others and I really appreciate you taking your time to respond to my dumb ass, I just feel like one of us (probably me) has a fundamental misunderstanding of what the other is saying.

I have not found any way to do this “automatically”, at all, regardless of how you create or provide the data. Everything I’m finding says that the default option on a ManyToManyField is only effective in the case of a form being prepared for using that field. See #2750 (ManyToManyField ignores 'default' option) – Django

Side note: SO is worthless to dangerous when it comes to Django-related information. It’s certainly not authoritative. There is nothing that I would trust from it without independent validation and verification. Use it as a starting point to kickstart research, sure. But never rely on anything from there at face value.

I’m sorry, I’m not following what you’re asking here.

Actually, I wouldn’t mind if you were - and working with the assumption on both sides that this is a “good faith effort” to increase mutual understanding.

I certainly don’t know everything there is to know about Django, and sometimes it’s me that needs to get certain ideas or concepts more clear or correct. I’m not the old man on the mountain dispensing the wisdom of the ages. (Well wait - I am old, I am a man, and I do live on a mountain. So I guess the only thing I’m missing is the wisdom of the ages.)

Anyway, I’m ok with being challenged, that way I get to learn, too.

1 Like