Monday, September 30, 2013

Using unique_together with foreign key fields which may be None

Hi,

I'm having trouble using the unique together constraint with a a field which may be None.  Given this model:

class Rule(models.Model):

    internal = models.BooleanField(default=False)

    port_range_from = models.PositiveIntegerField(null=True, blank=True)
    port_range_to = models.PositiveIntegerField(null=True, blank=True)

    # either cidr_ip or src_group for ingress rules
    cidr_ip = IPNetworkField(blank=True, null=True)
    is_ingress = models.BooleanField(default=True)

    # a security group is used as src in this rule
    src_security_group = models.ForeignKey(
        SecurityGroup, to_field='uuid', null=True, blank=True)

    class Meta:
        app_label = "nomos"
        unique_together = (
            ('port_range_from', 'port_range_to', 'cidr_ip', 'src_security_group', 'is_ingress'),
        )

Now in this instance src_security_group may be None OR cidr_ip may be None.  In this case they are mutually exclusive.  Regardless I want to use the unique_together to ensure that no two identical rules are created.  However, in the django models/base.py code the following logic is in _perform_unique_check:

lookup_kwargs = {}
            for field_name in unique_check:
                f = self._meta.get_field(field_name)
                lookup_value = getattr(self, f.attname)
                if lookup_value is None:
                    # no value, skip the lookup
                    continue
                if f.primary_key and not self._state.adding:
                    # no need to check for unique primary key when editing
                    continue
                lookup_kwargs[str(field_name)] = lookup_value

            # some fields were skipped, no reason to do the check
            if len(unique_check) != len(lookup_kwargs):
                continue

Because the lookup_value of a null field is None, the validation check is aborted entirely.  This seems wrong to me, and I'm wondering if I'm doing something wrong here.  Redefining the models is not something I can do at this point.

Berndt

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/fd542fd7-0cd2-40ed-ac3d-e1f3d8a019eb%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

No comments:

Post a Comment