简体   繁体   中英

How to model “One or Many” relationship in Django?

I have a model Owner . The Owner has a type which can be either Individual or Business . Based on type, the Owner may have One-to-One or One-to-Many relationship with Property model. If Individual , it can only have one Property but if it's Business , it may have many Property s. How do you model this in Django? How can I enforce the Individual to have only one Property .

If you're using PostgreSQL or SQLite you can enforce this with a partial unique index. As of Django 2.2 you can do this declaratively , something like:

from django.db.models import Model, Q, UniqueConstraint

class Property(Model):
    ...
    class Meta:
        constraints = [UniqueConstraint(fields=["owner"], condition=Q(type="Individual"))]

Before Django 2.2 you can do this with a migration. Something like:

class Migration(migrations.Migration):

    dependencies = [ ... ]

    operations = [
        migrations.RunSQL("CREATE UNIQUE INDEX property_owner 
                           ON property(owner_id) 
                           WHERE type = 'Individual'"),
    ]

I would recommend creating the Property model with a ForeignKey to Owner and then add some custom validation by overriding the save function of the class as such.

from django.db import IntegrityError

class Property(models.Model):
    owner = models.ForeignKey(Owner)

    def save(self, *args, **kwargs):
        if self.owner.type == "Individual":
            if Property.objects.filter(owner=self.owner).exists():
                raise IntegrityError
        super(Property, self).save(*args, **kwargs)

This won't cover all cases such as manually adding records to the database or using certain django methods that bypass the save functionality but it will cover a majority of cases.

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