Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 537
qollin Avatar asked Feb 05 '09 22:02

qollin


People also ask

How does Django handle many to many relationship?

Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many field and the name of the table for the model that contains it.

How fetch data from many to many field in Django?

A ManyToManyField in Django is a field that allows multiple objects to be stored. This is useful and applicable for things such as shopping carts, where a user can buy multiple products. To add an item to a ManyToManyField, we can use the add() function.

How can I get ForeignKey ID in Django?

Just add str function in your foreign reference model Product.

What is OneToOneField Django?

This field can be useful as a primary key of an object if that object extends another object in some way. For example – a model Car has one-to-one relationship with a model Vehicle, i.e. a car is a vehicle. One-to-one relations are defined using OneToOneField field of django.


2 Answers

I would add a field which indicates whether the objects are "draft" or "live". That way they are persisted across requests, sessions, etc. and django stops complaining.

You can then filter your objects to only show "live" objects in public views and only show "draft" objects to the user that created them. This can also be extended to allow "archived" objects (or any other state that makes sense).

like image 112
Aaron Maenpaa Avatar answered Oct 18 '22 07:10

Aaron Maenpaa


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...

like image 38
lilith Avatar answered Oct 18 '22 08:10

lilith