6

Many questions already on this topic, but not what i'm searching for.

I have this Model:

class Options(TimeStampedModel) option_1 = models.CharField(max_length=64) option_2 = models.CharField(max_length=64) class Meta: unique_together = ('option_1', 'option_2') 

Now I have a unique constraint on the fields. Is there a way to also define this the other way around so that it doesn't matter what was option_1 and what was option_2

As example:

Options.create('spam', 'eggs') # Allowed Options.create('spam', 'eggs') # Not allowed Options.create('eggs', 'spam') # Is allowed but should not be 

Thanks in advance!

6
  • 1
    This seems like a strange thing to want to do, what is your specific use case? Commented Apr 13, 2018 at 12:30
  • They are options.. and options shouldn't go together more than once, left or rightways Commented Apr 13, 2018 at 12:37
  • 1
    I feel a better solution might be a many to many relationship and making an Option model. Commented Apr 13, 2018 at 12:45
  • 2
    You could do that with a CHECK constraint on the database, but then you'll want more options and it will be messy... @etene's solution is more appropriate here Commented Apr 13, 2018 at 13:02
  • @Kos How would you do this using a CheckConstraint? I'd like to push more validation into the database itself, but using a ManyToMany relationship as in @etene's solution below is not an option. The problem I'm finding with CheckConstraint's is they seem to be limited to the data in the row being inserted. Commented Feb 23, 2023 at 19:54

2 Answers 2

7

I think a ManyToMany relation with a custom through table and an unique_together constraint on that table should do what you want.

Example code:

from django.db.models import Model, ForeignKey, ManyToManyField, CharField class Option(Model): name = CharField() class Thing(TimeStampedModel): options = ManyToManyField("Option", through="ThingOption") class ThingOption(Model): thing = ForeignKey(Thing) option = ForeignKey(Option) value = CharField() class Meta: unique_together = ('thing', 'option') 

For Django 2.2+ it is recommended to use UniqueConstraint. In the docs there is a note stating unique_together may be deprecated in the future. See this post for its usage.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! I think this is the way to go
I'm struggling to understand this. The options are a field on the Thing model. So I can select the 'spam' and 'eggs' Option models in that? How does the ThingOption table prevent the selection the other way around? And what is value?
This is a bit old for me, but you should probably read the docs I've linked, esp. on many-to-many through tables. The ThingOption table doesn't prevent selection in any way, it just prevents setting the same Option more than once for the same Thing, through the unique_together constraint.
1

You can override create method, do something like

from django.db import models class MyModelManager(models.Manager): def create(self, *obj_data): # Do some extra stuff here on the submitted data before saving... # Ex- If obj_data[0]=="eggs" and obj_data[1]=="spam" is True don't allow it for your blah reason # Call the super method which does the actual creation return super().create(*obj_data) # Python 3 syntax!! class MyModel(models.model): option_1 = models.CharField(max_length=64) option_2 = models.CharField(max_length=64) objects = MyModelManager() 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.