3

First off, I'm planning on running my project on google app engine so I'm using djangoappengine which as far as I know doesn't support django's ManyToManyField type. Because of this I've setup my models like this:

from django.db import models
from django.contrib.auth.models import User

class Group(models.Model):
    name = models.CharField(max_length=200)

class UserGroup(models.Model):
    user = models.ForeignKey(User)
    group = models.ForeignKey(Group)

On a page I have a form field where people can enter a group name. I want the results from this form field to create a UserGroup object for the user - group combination and if the group doesn't yet exist create a new Group object. At first I started putting this logic in the UserGroup class with a add_group method but quickly realized that it doesn't really make sense to put this in the UserGroup class. What would the proper way of doing this be? I saw some stuff about model managers. Is this what those are for?

Ian Burris
  • 6,325
  • 21
  • 59
  • 80

1 Answers1

3

From the Django docs:

A Manager is the interface through which database query operations are provided to Django models

So a manager is not the way to create new instances of a model.

I would just have a constructor for the Group model which pulls the User (if it is given) from the keyword arguments and creates a new UserGroup.

So if you instantiated a new Group as Group(name='group name', user=some_user) the constructor could strip the user keyword argument away and create the appropriate UserGroup with that user:

class Group(models.Model):
    name = models.CharField(max_length=200)

    def __init__(self, *args, **kwargs):
        # Remove user from the kwargs.
        # It is important that user is removed from the kwargs before calling
        # the super.__init__(). This is because the `user` kwarg is not expected.
        user = kwargs.pop('user', None)

        # call the normal init method
        super(Group, self).__init__(*args, **kwargs)

        # Create the UserGroup instance for the specified user
        if user is not None:
            # Maybe some other logic here ...
            UserGroup(user=user, group=self).save()

This way if you provide a user when instantiating your Group it will create a UserGroup and will do nothing otherwise.

Of course you could equally do a similar thing in the constructor of the UserGroup model, it is not really that important, it just depends which metaphorically makes sense to your code.

EDIT:

A fix to the problems pointed out in the comments:

...
def __init__(self, *args, **kwargs):
    ...
    self._user_group = UserGroup(user=user, group=self)

def save(self, *args, **kwargs):
    super(Group, self).save(*args, **kwargs)
    self._user_group.save()
Marcus Whybrow
  • 19,578
  • 9
  • 70
  • 90
  • How can it self the m2m when there is no Group yet? Maybe I read it wrong. Didn't read all. – Sam Stoelinga May 07 '11 at 14:57
  • That's what I meant hehe. But it is an elegant way! I typed wrong i meant how can it save the m2m when there is no group yet. – Sam Stoelinga May 08 '11 at 05:53
  • 1
    In the edit I made, the UserGroup m2m through model is saved after the super call is made to the Group model. Therefor the Group is saved and then the UserGroup is saved afterwards. So the Group does exist. – Marcus Whybrow May 08 '11 at 10:09