Unique Combination of ManyToMany












0















I'm trying to create a unique Availability status for Player on given Hour. Here goes the code:



class Player(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)

class Hour(models.Model):
date = models.DateTimeField()
players = models.ManyToManyField(Player, blank=True,
through='Availability')

class Availability(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
available = models.BooleanField()


My problem is that it's currently possible to add same Availability few times - I want to programatically limit it to just one per combination.



Thanks in advance!










share|improve this question























  • See docs for unique_together. This is enforced in the admin and at the database level. See this answer below.

    – djvg
    Jan 4 at 20:25


















0















I'm trying to create a unique Availability status for Player on given Hour. Here goes the code:



class Player(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)

class Hour(models.Model):
date = models.DateTimeField()
players = models.ManyToManyField(Player, blank=True,
through='Availability')

class Availability(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
available = models.BooleanField()


My problem is that it's currently possible to add same Availability few times - I want to programatically limit it to just one per combination.



Thanks in advance!










share|improve this question























  • See docs for unique_together. This is enforced in the admin and at the database level. See this answer below.

    – djvg
    Jan 4 at 20:25
















0












0








0


1






I'm trying to create a unique Availability status for Player on given Hour. Here goes the code:



class Player(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)

class Hour(models.Model):
date = models.DateTimeField()
players = models.ManyToManyField(Player, blank=True,
through='Availability')

class Availability(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
available = models.BooleanField()


My problem is that it's currently possible to add same Availability few times - I want to programatically limit it to just one per combination.



Thanks in advance!










share|improve this question














I'm trying to create a unique Availability status for Player on given Hour. Here goes the code:



class Player(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)

class Hour(models.Model):
date = models.DateTimeField()
players = models.ManyToManyField(Player, blank=True,
through='Availability')

class Availability(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
available = models.BooleanField()


My problem is that it's currently possible to add same Availability few times - I want to programatically limit it to just one per combination.



Thanks in advance!







django django-models






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jun 25 '17 at 20:28









Franek MadejFranek Madej

7210




7210













  • See docs for unique_together. This is enforced in the admin and at the database level. See this answer below.

    – djvg
    Jan 4 at 20:25





















  • See docs for unique_together. This is enforced in the admin and at the database level. See this answer below.

    – djvg
    Jan 4 at 20:25



















See docs for unique_together. This is enforced in the admin and at the database level. See this answer below.

– djvg
Jan 4 at 20:25







See docs for unique_together. This is enforced in the admin and at the database level. See this answer below.

– djvg
Jan 4 at 20:25














3 Answers
3






active

oldest

votes


















2














You can have the unique_together on the "throuh" table (in your case the Avaliability Table)



class Availability(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
available = models.BooleanField()
class Meta:
unique_together = (('player','hour'),)


And then use the get_or_create for adding/modifying:



 obj,created = Availability.objects.get_or_create(hour=hour,player=player)





share|improve this answer































    1














    I've worked around it modifying save() for Availability:



    def save(self, *args, **kwargs):
    if self.pk is None:
    combination = Availability.objects.filter(player=self.player,
    hour=self.hour).first()
    if combination:
    self.pk = combination.pk
    super(Availability, self).save(*args, **kwargs)





    share|improve this answer































      1














      You can't have a unique constraint in a ManyToManyField, as reasoned in ticket 702. What you can do is validate the model when saving, as shown in an online snippet:



      class MyModel(models.Model):
      site = models.ManyToManyField(Site)
      on_site = CurrentSiteManager()

      foobar = ... # A unique field

      def save(self, *args, **kwargs):
      if self.id == None: # new item should be created.
      # manually check a unique togeher, because django can't do this with a M2M field.
      # Obsolete if unique_together work with ManyToMany: http://code.djangoproject.com/ticket/702
      exist = MyModel.on_site.filter(foobar=self.foobar).count()
      if exist != 0:
      from django.db import IntegrityError
      # We can use attributes from this model instance, because it needs to have a primary key
      # value before a many-to-many relationship can be used.
      site = Site.objects.get_current()
      raise IntegrityError(
      "MyModel item with same foobar field exist on site %r" % site
      )

      return super(MyModel, self).save(*args, **kwargs)

      class Meta:
      #unique_together = ("foobar", "site") # unique_together doesn't work with ManyToMany!
      # See: http://code.djangoproject.com/ticket/702


      Note that the logic can change depending on your goal. As Carl Meyer argues in the ticket linked above, different behavior can make sense in your model (e.g. a field being unique with every item of the ManyToManyField or with the exact combination).






      share|improve this answer
























      • Sorry, but I believe this answer is incorrect: Ticket 702, as well as the docs for unique_together mention that "A ManyToManyField cannot be included in unique_together." I believe what the OP wants is the opposite, viz. to include foreign key fields player and hour from the Availability model in that model's unique_together. As described in the answer by Oded Har-Tal, this most certainly is possible.

        – djvg
        Jan 4 at 20:23













      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f44750308%2funique-combination-of-manytomany%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2














      You can have the unique_together on the "throuh" table (in your case the Avaliability Table)



      class Availability(models.Model):
      player = models.ForeignKey(Player, on_delete=models.CASCADE)
      hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
      available = models.BooleanField()
      class Meta:
      unique_together = (('player','hour'),)


      And then use the get_or_create for adding/modifying:



       obj,created = Availability.objects.get_or_create(hour=hour,player=player)





      share|improve this answer




























        2














        You can have the unique_together on the "throuh" table (in your case the Avaliability Table)



        class Availability(models.Model):
        player = models.ForeignKey(Player, on_delete=models.CASCADE)
        hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
        available = models.BooleanField()
        class Meta:
        unique_together = (('player','hour'),)


        And then use the get_or_create for adding/modifying:



         obj,created = Availability.objects.get_or_create(hour=hour,player=player)





        share|improve this answer


























          2












          2








          2







          You can have the unique_together on the "throuh" table (in your case the Avaliability Table)



          class Availability(models.Model):
          player = models.ForeignKey(Player, on_delete=models.CASCADE)
          hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
          available = models.BooleanField()
          class Meta:
          unique_together = (('player','hour'),)


          And then use the get_or_create for adding/modifying:



           obj,created = Availability.objects.get_or_create(hour=hour,player=player)





          share|improve this answer













          You can have the unique_together on the "throuh" table (in your case the Avaliability Table)



          class Availability(models.Model):
          player = models.ForeignKey(Player, on_delete=models.CASCADE)
          hour = models.ForeignKey(Hour, on_delete=models.CASCADE)
          available = models.BooleanField()
          class Meta:
          unique_together = (('player','hour'),)


          And then use the get_or_create for adding/modifying:



           obj,created = Availability.objects.get_or_create(hour=hour,player=player)






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 22 '18 at 7:04









          Oded Har-TalOded Har-Tal

          907




          907

























              1














              I've worked around it modifying save() for Availability:



              def save(self, *args, **kwargs):
              if self.pk is None:
              combination = Availability.objects.filter(player=self.player,
              hour=self.hour).first()
              if combination:
              self.pk = combination.pk
              super(Availability, self).save(*args, **kwargs)





              share|improve this answer




























                1














                I've worked around it modifying save() for Availability:



                def save(self, *args, **kwargs):
                if self.pk is None:
                combination = Availability.objects.filter(player=self.player,
                hour=self.hour).first()
                if combination:
                self.pk = combination.pk
                super(Availability, self).save(*args, **kwargs)





                share|improve this answer


























                  1












                  1








                  1







                  I've worked around it modifying save() for Availability:



                  def save(self, *args, **kwargs):
                  if self.pk is None:
                  combination = Availability.objects.filter(player=self.player,
                  hour=self.hour).first()
                  if combination:
                  self.pk = combination.pk
                  super(Availability, self).save(*args, **kwargs)





                  share|improve this answer













                  I've worked around it modifying save() for Availability:



                  def save(self, *args, **kwargs):
                  if self.pk is None:
                  combination = Availability.objects.filter(player=self.player,
                  hour=self.hour).first()
                  if combination:
                  self.pk = combination.pk
                  super(Availability, self).save(*args, **kwargs)






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jun 25 '17 at 21:52









                  Franek MadejFranek Madej

                  7210




                  7210























                      1














                      You can't have a unique constraint in a ManyToManyField, as reasoned in ticket 702. What you can do is validate the model when saving, as shown in an online snippet:



                      class MyModel(models.Model):
                      site = models.ManyToManyField(Site)
                      on_site = CurrentSiteManager()

                      foobar = ... # A unique field

                      def save(self, *args, **kwargs):
                      if self.id == None: # new item should be created.
                      # manually check a unique togeher, because django can't do this with a M2M field.
                      # Obsolete if unique_together work with ManyToMany: http://code.djangoproject.com/ticket/702
                      exist = MyModel.on_site.filter(foobar=self.foobar).count()
                      if exist != 0:
                      from django.db import IntegrityError
                      # We can use attributes from this model instance, because it needs to have a primary key
                      # value before a many-to-many relationship can be used.
                      site = Site.objects.get_current()
                      raise IntegrityError(
                      "MyModel item with same foobar field exist on site %r" % site
                      )

                      return super(MyModel, self).save(*args, **kwargs)

                      class Meta:
                      #unique_together = ("foobar", "site") # unique_together doesn't work with ManyToMany!
                      # See: http://code.djangoproject.com/ticket/702


                      Note that the logic can change depending on your goal. As Carl Meyer argues in the ticket linked above, different behavior can make sense in your model (e.g. a field being unique with every item of the ManyToManyField or with the exact combination).






                      share|improve this answer
























                      • Sorry, but I believe this answer is incorrect: Ticket 702, as well as the docs for unique_together mention that "A ManyToManyField cannot be included in unique_together." I believe what the OP wants is the opposite, viz. to include foreign key fields player and hour from the Availability model in that model's unique_together. As described in the answer by Oded Har-Tal, this most certainly is possible.

                        – djvg
                        Jan 4 at 20:23


















                      1














                      You can't have a unique constraint in a ManyToManyField, as reasoned in ticket 702. What you can do is validate the model when saving, as shown in an online snippet:



                      class MyModel(models.Model):
                      site = models.ManyToManyField(Site)
                      on_site = CurrentSiteManager()

                      foobar = ... # A unique field

                      def save(self, *args, **kwargs):
                      if self.id == None: # new item should be created.
                      # manually check a unique togeher, because django can't do this with a M2M field.
                      # Obsolete if unique_together work with ManyToMany: http://code.djangoproject.com/ticket/702
                      exist = MyModel.on_site.filter(foobar=self.foobar).count()
                      if exist != 0:
                      from django.db import IntegrityError
                      # We can use attributes from this model instance, because it needs to have a primary key
                      # value before a many-to-many relationship can be used.
                      site = Site.objects.get_current()
                      raise IntegrityError(
                      "MyModel item with same foobar field exist on site %r" % site
                      )

                      return super(MyModel, self).save(*args, **kwargs)

                      class Meta:
                      #unique_together = ("foobar", "site") # unique_together doesn't work with ManyToMany!
                      # See: http://code.djangoproject.com/ticket/702


                      Note that the logic can change depending on your goal. As Carl Meyer argues in the ticket linked above, different behavior can make sense in your model (e.g. a field being unique with every item of the ManyToManyField or with the exact combination).






                      share|improve this answer
























                      • Sorry, but I believe this answer is incorrect: Ticket 702, as well as the docs for unique_together mention that "A ManyToManyField cannot be included in unique_together." I believe what the OP wants is the opposite, viz. to include foreign key fields player and hour from the Availability model in that model's unique_together. As described in the answer by Oded Har-Tal, this most certainly is possible.

                        – djvg
                        Jan 4 at 20:23
















                      1












                      1








                      1







                      You can't have a unique constraint in a ManyToManyField, as reasoned in ticket 702. What you can do is validate the model when saving, as shown in an online snippet:



                      class MyModel(models.Model):
                      site = models.ManyToManyField(Site)
                      on_site = CurrentSiteManager()

                      foobar = ... # A unique field

                      def save(self, *args, **kwargs):
                      if self.id == None: # new item should be created.
                      # manually check a unique togeher, because django can't do this with a M2M field.
                      # Obsolete if unique_together work with ManyToMany: http://code.djangoproject.com/ticket/702
                      exist = MyModel.on_site.filter(foobar=self.foobar).count()
                      if exist != 0:
                      from django.db import IntegrityError
                      # We can use attributes from this model instance, because it needs to have a primary key
                      # value before a many-to-many relationship can be used.
                      site = Site.objects.get_current()
                      raise IntegrityError(
                      "MyModel item with same foobar field exist on site %r" % site
                      )

                      return super(MyModel, self).save(*args, **kwargs)

                      class Meta:
                      #unique_together = ("foobar", "site") # unique_together doesn't work with ManyToMany!
                      # See: http://code.djangoproject.com/ticket/702


                      Note that the logic can change depending on your goal. As Carl Meyer argues in the ticket linked above, different behavior can make sense in your model (e.g. a field being unique with every item of the ManyToManyField or with the exact combination).






                      share|improve this answer













                      You can't have a unique constraint in a ManyToManyField, as reasoned in ticket 702. What you can do is validate the model when saving, as shown in an online snippet:



                      class MyModel(models.Model):
                      site = models.ManyToManyField(Site)
                      on_site = CurrentSiteManager()

                      foobar = ... # A unique field

                      def save(self, *args, **kwargs):
                      if self.id == None: # new item should be created.
                      # manually check a unique togeher, because django can't do this with a M2M field.
                      # Obsolete if unique_together work with ManyToMany: http://code.djangoproject.com/ticket/702
                      exist = MyModel.on_site.filter(foobar=self.foobar).count()
                      if exist != 0:
                      from django.db import IntegrityError
                      # We can use attributes from this model instance, because it needs to have a primary key
                      # value before a many-to-many relationship can be used.
                      site = Site.objects.get_current()
                      raise IntegrityError(
                      "MyModel item with same foobar field exist on site %r" % site
                      )

                      return super(MyModel, self).save(*args, **kwargs)

                      class Meta:
                      #unique_together = ("foobar", "site") # unique_together doesn't work with ManyToMany!
                      # See: http://code.djangoproject.com/ticket/702


                      Note that the logic can change depending on your goal. As Carl Meyer argues in the ticket linked above, different behavior can make sense in your model (e.g. a field being unique with every item of the ManyToManyField or with the exact combination).







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Apr 11 '18 at 11:27









                      Paulo AlmeidaPaulo Almeida

                      5,3531727




                      5,3531727













                      • Sorry, but I believe this answer is incorrect: Ticket 702, as well as the docs for unique_together mention that "A ManyToManyField cannot be included in unique_together." I believe what the OP wants is the opposite, viz. to include foreign key fields player and hour from the Availability model in that model's unique_together. As described in the answer by Oded Har-Tal, this most certainly is possible.

                        – djvg
                        Jan 4 at 20:23





















                      • Sorry, but I believe this answer is incorrect: Ticket 702, as well as the docs for unique_together mention that "A ManyToManyField cannot be included in unique_together." I believe what the OP wants is the opposite, viz. to include foreign key fields player and hour from the Availability model in that model's unique_together. As described in the answer by Oded Har-Tal, this most certainly is possible.

                        – djvg
                        Jan 4 at 20:23



















                      Sorry, but I believe this answer is incorrect: Ticket 702, as well as the docs for unique_together mention that "A ManyToManyField cannot be included in unique_together." I believe what the OP wants is the opposite, viz. to include foreign key fields player and hour from the Availability model in that model's unique_together. As described in the answer by Oded Har-Tal, this most certainly is possible.

                      – djvg
                      Jan 4 at 20:23







                      Sorry, but I believe this answer is incorrect: Ticket 702, as well as the docs for unique_together mention that "A ManyToManyField cannot be included in unique_together." I believe what the OP wants is the opposite, viz. to include foreign key fields player and hour from the Availability model in that model's unique_together. As described in the answer by Oded Har-Tal, this most certainly is possible.

                      – djvg
                      Jan 4 at 20:23




















                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f44750308%2funique-combination-of-manytomany%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      404 Error Contact Form 7 ajax form submitting

                      How to know if a Active Directory user can login interactively

                      Refactoring coordinates for Minecraft Pi buildings written in Python