vincentf
vincentf

Reputation: 1499

Can I use unique_together on ManyToMany field?

I have a model OrderPage which is manytomany to Site. In Django admin, I want to restrict the selection of sites(Sites which belong to existing OrderPage can not be selected again). Can I do it with unique_together ? I get an error with following model ManyToManyFields are not supported in unique_together

class OrderPage(models.Model):

    description = models.CharField(max_length=255, blank=False)
    sites = models.ManyToManyField(Site)

    class Meta:
        unique_together = (('id', 'sites'),)


class Order(models.Model):
    order_page = models.ForeignKey(OrderPage)


class OrderPageAdmin(admin.ModelAdmin):
    filter_horizontal = ('sites',)

admin.site.register(OrderPage, OrderPageAdmin)

Upvotes: 2

Views: 3076

Answers (1)

Dave
Dave

Reputation: 11889

If an Site can have only one OrderPage, you don't need to worry about unique_together.

Ideally you should subclass Site and use a ForeignKey from that to OrderPage. That would natively give you what you're looking for: each site would be able to have one OrderPage, and each OrderPage multiple Sites. This would be the cleanest but you would have to use your subclass throughout the program in place of the original Site which might be more work than you want right now.

class BetterSite(Site):
    order_page = models.ForeignKey('OrderPage')

The dirtier way is to keep your M2M and just set the site as unique, since there should only ever be one entry on each site in the M2M table. You would use a 'through' table so you could set the custom uniqueness value:

class OrderPage(models.Model):
    description = models.CharField(max_length=255, blank=False)
    sites = models.ManyToManyField(Site, through='OrderPageToSite')

class OrderPageToSite(models.Model):
    order_page = models.ForeignKey(OrderPage)
    site = models.ForeignKey(Site, unique=True)

(Note that I've left these simple but in your FK fields you should also consider setting on_delete and related_name)

Upvotes: 6

Related Questions