简体   繁体   中英

Mutually exclusive many-to-many relationship in Django models

I'm trying to create a simple model to keep track of discount coupons in Django 1.10 (with Postgres 9.5 as underlying database) and I was wondering if there's a way to make sure that a coupon instance ( id , perhaps is a more accurate term?) doesn't appear in two M2M relationships at the same time.

I'm sure everyone is familiar with how discount coupons work but, just in case, let me explain my use case :

  1. Some coupons would be always applied. For instance: "Free delivery in your first purchase" , or "10% off Pepsi for the rest of your life" ... things like that.
  2. Some other coupons would be applied through a code (a simple string, really) that the user would have to input somewhere (like "Get a 5% off with the code "5-OFF" " ... yeah, I'll probably have to work on the obfuscation of the codes :-D )
  3. The user could say "No, I don't want to apply this coupon to this order, I'll use it later" . For instance: if the user can use a one-time 5% off coupon, but wants to keep it for a large purchase. Let's say the customer knows he's going to make a large purchase in the upcoming future, and right now he's doing a small one. He might wanna keep the 5% off for the later (bigger) purchase.

To keep track of those things, I have a model like this:

class CouponTracker(models.Model):
    # Coupons that require a code to be activated:
    extra_applied_coupons = ManyToManyField('Coupon', related_name='+')

    # Coupons that the user could have applied and specifically
    # said no (such as 5% off if the purchase is small, and wants
    # to use it later):
    vetoed_coupons = ManyToManyField('Coupon', related_name='+')

So, the question is:

How can I enforce (at a database level, through a constraint) that a coupon does not appear at the same time in extra_applied_coupons and vetoed_coupons ?

Thank you in advance!

Why don't you combine 2 extra_applied_coupons and vetoed_coupons and have 1 more fields (for example, type ) to determine coupon's group. Then problem will be simpler, just ensure unique in 1 ManyToMany relationship

class CouponTracker(models.Model):
    coupons = ManyToManyField('Coupon', related_name='+')
    type = models.IntegerField(default=0)

type can be 0 for extra_applied_coupons and 1 for vetoed_coupons . If you want to add more relationship attribute, you can check https://docs.djangoproject.com/en/1.11/topics/db/models/#extra-fields-on-many-to-many-relationships

Since ManyToMany relations creating a seperate table, AFAIK there cannot make an UNIQUE constraint across tables. So there is no direct way to add contraint on db level. Check this . Either you have to do on application layer or some hackish way like this

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM