Skip to content
Advertisement

How to constraint and validate Django m2m and foreign key fields

I have these models:

class Client(models.Model):
    name = models.CharField(_('name'), max_length=255)

    info = models.OneToOneField('ClientInfo',
                                verbose_name=_('info'),
                                related_name='client',
                                on_delete=models.PROTECT)

    is_active = models.BooleanField(_('is active'), default=False) 

class ClientInfo(models.Model):
    address = models.CharField(_('name'), max_length=255)
    
    other fields...

class Result(models.Model):
    RESULT_CHOICES = (('N', _('Notified')),
                     ('NL', _('No located')))

    created_by= models.ForeignKey(OfficeEmployee,
                                 verbose_name=_('created by'),
                                 on_delete=models.PROTECT)

    result_type = models.CharField(_('result type'),
                                   max_length=2,
                                   default='N',
                                   choices=RESULT_CHOICES)

    other fields...

class Visit(models.Model):
    client = models.ForeignKey(Client,
                                  verbose_name=_('client'),
                                  related_name='visit',
                                  on_delete=models.PROTECT)

    results = models.ManyToManyField(Result,
                                     verbose_name=_('results'),
                                     related_name='visit',
                                     blank=True)    

    other fields...

I want to add certain restrictions but I have difficulties with those models, since I hardly even see the need to add restrictions to related fields:

  1. How to avoid having “ClientInfo” entries if a “Client” has not created a relationship with it?
  2. How to prevent a “Result” entry of type “NL” being adde to existing “Visit” if the client it is related to is marked as not active
  3. I was thinking about using django built-in signals but, I don’t know if the wanted restrictions can be defined in the class itself by overriding some validation methods or using Meta class. This last is because I’m affraid about if the use of signals is very expensive in terms of performance

Advertisement

Answer

Best approach I found is m2m_changed:

@receiver(m2m_changed, sender=results_through, dispatch_uid='check_employeer_status')
def check_employeer_status(sender, **kwargs):
    instance = kwargs.get('instance')
    action = kwargs.get('action')
    model = kwargs.get('model')

    if action == 'pre_add':
        if model and model.result_type != 'NL':
            if instance and not instance.employeer.is_active:
                raise ValidationError(('employeer '
                                       'is not active. Only no located results are allowed'))
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement