I agree this feature would be useful, at least to allow bundling check constraints with custom field classes. As you point out the PositiveIntegerField classes do this within Django, and doubtless many custom fields have used the db_check() method.
The only thing I'm not a fan of in your proposal is repeating the field name within the check expression, like "price" in: price = DecimalField(..., check=Q(price__gte=0)) This seems repetitive at least, and would increase error refactoring. Also Django field classes typically don't “know” their name until the Model meta class logic runs, and contribute_to_class() is called. Requiring the name within check() would mean it would need to accept any name and validate it later. Perhaps we could support only a special name instead, like “self” or the shorter “f”? price = DecimalField(..., check=Q(f__gte=0)) On Wed, Apr 5, 2023 at 7:18 PM David Sanders <shang.xiao.sand...@gmail.com> wrote: > Hi folks, > > We've had check constraints for a while now and they're awesome. > > I'd like to propose an alternative way to declare check constraints: at > the field level. This sounds like it's duplicating the feature but there > are some advantages that make this distinct from declaring at the > model-level from the meta: > > - Colocality: the check rules are close to the field they're concerned > with > - Reusability: Allows for bundling with custom field types > - Good for checks concerned only with the field its declared on, for > multiple fields recommended to continue to use Meta. (Kind of analogous to > unique=True vs UniqueConstraint) > > For example: > > class Product(Model): > price = DecimalField(..., check=Q(price__gte=0)) > ... > other fields > ... > > > class Meta: > constraints = [ > ... declare constraints here that are concerned with multiple > fields... > ] > > > For more complex fields you can then bundle the check for reusability: > > class PriceField(DecimalField): > def contribute_to_class(self, ...): > super().contribute_to_class(...) > self.check = Q(**{f'{self.name}__gte': 0}) > > > Some other points: > > - To be consistent with model-level check constraints they'd also need > to participate in validate_constraints(). > - (Small)PositiveIntegerField already has its own implementation of a > check constraint, enforcing values >- 0 via the private db_check() method. > I think this is an example of how bundling checks can be useful. > - I won't go into implementation alternatives but making use of this > existing db_check() method is one possibility. How participation in > validation would work would still need to be decided upon. > - See this Stupid Django Trick > > <https://github.com/shangxiao/stupid-django-tricks/tree/master/column_check_constraints> > for some experimentation with this idea. > > > Cheers, > David > > -- > You received this message because you are subscribed to the Google Groups > "Django developers (Contributions to Django itself)" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to django-developers+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-developers/CADyZw-6Odv0dpo-En3Jm2NqPhBtK7ebaGKBi4OROe1n%2BvHEE-A%40mail.gmail.com > <https://groups.google.com/d/msgid/django-developers/CADyZw-6Odv0dpo-En3Jm2NqPhBtK7ebaGKBi4OROe1n%2BvHEE-A%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAMyDDM3Tyj%3Djfo9yFiUythymjP2WHKGi6cJY%3DOKk1_XkggiMtQ%40mail.gmail.com.