def __init__(self, item_field_type, *args, **kwargs): # This seems bonkers, we shout at people for specifying null=True, but then do it ourselves. But this is because # *we* abuse None values for our own purposes (to represent an empty iterable) if someone else tries to then # all hell breaks loose if kwargs.get("null", False): raise RuntimeError( "IterableFields cannot be set as nullable (as the datastore doesn't differentiate None vs []" ) kwargs["null"] = True default = kwargs.get("default", []) self._original_item_field_type = copy.deepcopy( item_field_type) # For deconstruction purposes if default is not None and not callable(default): kwargs["default"] = lambda: self._iterable_type(default) if hasattr(item_field_type, 'attname'): item_field_type = item_field_type.__class__ if callable(item_field_type): item_field_type = item_field_type() if isinstance(item_field_type, models.ForeignKey): raise ImproperlyConfigured( "Lists of ForeignKeys aren't supported, use RelatedSetField instead" ) self.item_field_type = item_field_type # We'll be pretending that item_field is a field of a model # with just one "value" field. assert not hasattr(self.item_field_type, 'attname') self.item_field_type.set_attributes_from_name('value') # Pop the 'min_length' and 'max_length' from the kwargs, if they're there, as this avoids # 'min_length' causing an error when calling super() min_length = kwargs.pop("min_length", None) max_length = kwargs.pop("max_length", None) # Check that if there's a min_length that blank is not True. This is partly because it # doesn't make sense, and partly because if the value (i.e. the list or set) is empty then # Django will skip the validators, thereby skipping the min_length check. if min_length and kwargs.get("blank"): raise ImproperlyConfigured( "Setting blank=True and min_length=%d is contradictory." % min_length) super(IterableField, self).__init__(*args, **kwargs) # Now that self.validators has been set up, we can add the min/max legnth validators if min_length is not None: self.validators.append(MinItemsValidator(min_length)) if max_length is not None: self.validators.append(MaxItemsValidator(max_length))
def __init__(self, to, limit_choices_to=None, related_name=None, on_delete=models.DO_NOTHING, **kwargs): # Make sure that we do nothing on cascade by default self._check_sane_on_delete_value(on_delete) from_fields = ['self'] to_fields = [None] min_length, max_length = self._sanitize_min_and_max_length(kwargs) if django.VERSION[1] == 8: # in Django 1.8 ForeignObject uses get_lookup_constraint instead # of get_lookup. We want to override it (but only for Django 1.8) self.get_lookup_constraint = self._get_lookup_constraint # Django 1.8 doesn't support the rel_class attribute so we have to pass it up # manually. kwargs["rel"] = self.rel_class( self, to, related_name=related_name, related_query_name=kwargs.get("related_query_name"), limit_choices_to=limit_choices_to, parent_link=kwargs.get("parent_link"), on_delete=on_delete) super(RelatedIteratorField, self).__init__(to, from_fields, to_fields, **kwargs) else: super(RelatedIteratorField, self).__init__(to, on_delete, from_fields, to_fields, related_name=related_name, limit_choices_to=limit_choices_to, **kwargs) # Now that self.validators has been set up, we can add the min/max legnth validators if min_length is not None: self.validators.append(MinItemsValidator(min_length)) if max_length is not None: self.validators.append(MaxItemsValidator(max_length))