[Fixed]-Django Bi-directional ManyToMany – How to prevent table creation on second model?

28👍

I also found this solution, which worked perfectly for me :

class Test1(models.Model):
    tests2 = models.ManyToManyField('Test2', blank=True)

class Test2(models.Model):
    tests1 = models.ManyToManyField('Test1', through=Test1.tests2.through, blank=True)

6👍

You don’t need to put a ManyToManyField on both sides of the relation. Django will do that for you.

You probably want something more like this:

class Model1(models.Model):
    name = models.CharField(max_length=128)
    ...

class Model2(models.Model):
    name = models.CharField(max_length=128)
    othermodels = models.ManyToManyField(Model1, through='Model1Model2')
    ...        

class Membership(models.Model):
    class Meta:
        db_table = 'model1_model2'
    model1 = models.ForeignKey(Model1)        
    model2 = models.ForeignKey(Model2)

When you’re working with your models, an instance of Model1 will have a othermodels_set field which is automatically added by django. Instances of Model2 will have othermodels.

👤Seth

2👍

class Awesome(models.Model):
 one = models.TextField()
 class Meta:
  # Prevent table creation. 
  abstract = True

http://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes

It’s not what you’re looking for, but it’s the closest they have I belive. Would it not be simpler to make a view?

Maybe:

class Awesome(models.Model):
  one = models.CharField(max_length = 255)
  two = models.CharField(max_length = 255)

class AwesomeOne(Awesome):
  fieldOne = models.ForeignKey(User, related_name = 'one')
  class Meta:
   abstract = True
class AwesomeTwo(Awesome):
  fieldTwo = models.ForeignKey(User, related_name = 'two')
  class Meta:
   abstract = True

Then, you can have one table created and override the __getattr__ to block access to the original fields.

2👍

In Django ManyToMany are bi-directional by default. The think is that you only have to define it on one model, not on both (and usually you don’t need to give a name to the table):

class Model1(models.Model):
    othermodels = ManyToManyField('Model2')

class Model2(models.model):
    ...

That’s it. Now syncdb will be happy. For more info: Django docs

The only drawback is, if you use the admin, you will have access to othermodels only in Model1.

Edit

So, if you want to have access to the ManyToMany in both models in the Admin, currently the official solution is to use inlinemodel for the second model. I had also this same problem/need just a few days ago. And I was not really satisfied with the inlinemodel solution (heavy in DB queries if you have a lot of entries, cannot use the *filter_horizontal* widget, etc.).

The solution I found (that’s working with Django 1.2+ and syncdb) is this:

class Model1(models.Model):
    othermodels = models.ManyToManyField('Model2', through='Model1Model2')

class Model2(models.Model):
    othermodels = models.ManyToManyField('Model1', through='Model1Model2')

class Model1Model2(models.Model):
    model1 = models.ForeignKey(Model1)
    model2 = models.ForeignKey(Model2)

    class Meta:
        db_table = 'app_model1_model2'
        auto_created = Model1

See ticket 897 for more info.

Unfortunately, if you’re using South you will have to remove the creation of the app_model1_model2 table in every migration file created automatically.

Leave a comment