station
station

Reputation: 7145

How to save a many to many model in django

I have the following two model class in django.

class Rule(models.Model):
    name = models.CharField(max_length=50)
    user = models.ForeignKey(User, related_name='rules', null=True, blank=True)
    threshold = models.CharField(max_length=50, null=True, blank=True)
    alert_value = models.CharField(max_length=50, null=True, blank=True)
    is_internal = models.BooleanField(default=False)

    def __unicode__(self):
        return self.name

    def to_json(self):
        return {
            'name': self.name,
            'threshold': self.threshold,
            'alert_value': self.alert_value
         }


class Module(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField(null=True, blank=True)
    is_internal = models.BooleanField(default=False)
    rules = models.ManyToManyField(Rule)

    def to_json(self):
        return {
            'name': self.name,
            'description': self.description,
            'rules': [r.to_json() for r in self.rules.all()]
        }


    def __unicode__(self):
         return self.name

Now I have the following code to save a Module object which implicitly contains a rules object in my view.py

def create_module(request):
    if request.method == 'POST':
        module_name = request.POST.get('name')
        module_description = request.POST.get('description')
        rule_ids = request.POST.getlist('rule_id')
        rules = None
        for rule_id in rule_ids:
            try:
                rules = models.Rule.objects.filter(pk__in=rule_id)
            except models.Rule.DoesNotExist:
                pass
        module = models.Module(name=module_name,
                           description=module_description,
                           rules=rules)
        module.save()

I get the rules correctly here but when save gets called I get an error

Exception Type: TypeError at /modules/create/ Exception Value: 'rules' is an invalid keyword argument for this function

How to overcome this when I want to save an object graph.

Upvotes: 0

Views: 69

Answers (2)

doniyor
doniyor

Reputation: 37846

you are overriding the rules queryset inside try and filter() doesnot raise DoesNotExist exception btw..

try this:

module = models.Module(name=module_name,description=module_description)
module.save()
#first save 'module' and add 'rules' from filter()-result

rules = models.Rule.objects.filter(pk__in=rule_ids)
module.rules = rules 
module.save()

more about how to save m2m in django

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599480

rules is not really a field on the model, it's an entry in a linking table - so it can't be saved until the Module entry exists. Also note that your loop is such that it will never consist of more than one Rules object, because you overwrite the rules variable each time. Instead you should simply get all the Rules and add them in one go.

module = models.Module(name=module_name,
                       description=module_description)
module.save()
rules = models.Rule.objects.filter(pk__in=rule_ids)
module.rules = rules

There's no need to save again after that: assigning to a related queryset does the database operation automatically. Also note that filter will not raise a DoesNotExist exception: if there is no matching rule, then there simply won't be an element in the resulting queryset.

Upvotes: 1

Related Questions