Search code examples
pythondjangodjango-modelsmany-to-many

How to work with unsaved many-to-many relations in django?


I have a couple of models in django which are connected many-to-many. I want to create instances of these models in memory, present them to the user (via custom method-calls inside the view-templates) and if the user is satisfied, save them to the database.

However, if I try to do anything on the model-instances (call rendering methods, e.g.), I get an error message that says that I have to save the instances first. The documentation says that this is because the models are in a many-to-many relationship.

How do I present objects to the user and allowing him/her to save or discard them without cluttering my database?

(I guess I could turn off transactions-handling and do them myself throughout the whole project, but this sounds like a potentially error-prone measure...)

Thx!


Solution

  • I think that using django forms may be the answer, as outlined in this documentation (search for m2m...).

    Edited to add some explanation for other people who might have the same problem:

    say you have a model like this:

    from django.db import models
    from django.forms import ModelForm
    
    class Foo(models.Model):
        name = models.CharField(max_length = 30)
    
    class Bar(models.Model):
          foos = models.ManyToManyField(Foo)
    
      def __unicode__(self):
          return " ".join([x.name for x in foos])
    

    then you cannot call unicode() on an unsaved Bar object. If you do want to print things out before they will be saved, you have to do this:

    class BarForm(ModelForm):
        class Meta:
            model = Bar
    
    def example():      
        f1 = Foo(name = 'sue')
        f1.save()
        f2 = foo(name = 'wendy')
        f2.save()
        bf = BarForm({'foos' : [f1.id, f2.id]})
        b = bf.save(commit = false)
        # unfortunately, unicode(b) doesn't work before it is saved properly,
        # so we need to do it this way: 
        if(not bf.is_valid()):
            print bf.errors
        else:
            for (key, value) in bf.cleaned_data.items():
                print key + " => " + str(value)
    

    So, in this case, you have to have saved Foo objects (which you might validate before saving those, using their own form), and before saving the models with many to many keys, you can validate those as well. All without the need to save data too early and mess up the database or dealing with transactions...