Sure, I’ll have to trim it up but here are the relevant bits:
The model:
class Client(models.Model):
name = models.CharField(max_length=100)
...
phone_service = models.BooleanField()
phone_number = models.CharField(
max_length=10,
blank=True,
validators=[
PhoneValidator(),
],
)
...
class Meta:
ordering = ["name"]
constraints = [
models.CheckConstraint(
name="if_phone_require_number",
check=(models.Q(phone_service=False) | ~models.Q(phone_number="")),
),
models.UniqueConstraint(
fields=["name", "client_type"], name="unique_clients_per_organization"
),
]
The view:
class CreateClient(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
template_name = "clients/create_client.html"
model = models.Client
form_class = forms.ClientForm
permission_required = "clients.add_client"
raise_exception = True
success_message = "Your new client has been created. Make any changes below, \
or click the Back button below to return to the client list."
def form_valid(self, form):
response = super().form_valid(form)
if template := form.cleaned_data["template"]:
self.copy_template(template)
return response
The form:
class PhoneField(forms.CharField):
def clean(self, value):
number = re.sub(r"[^0-9]", "", value)
return super().clean(number)
class ClientForm(forms.ModelForm):
phone_number = PhoneField(required=False)
class Meta:
model = models.Client
fields = "__all__"
widgets = {"systems": FilteredSelectMultiple("Systems", is_stacked=False)}
The idea, as you can see, is the make sure that if you check the box for phone service, we require that you provide a phone number, otherwise phone can be blank. What happens in older versions of Django–and what is happening to me currently–is that unless you write custom validation, check constraints are enforced when writing to the database. So if you fail one, the database throws an error, and your user gets a 500. But my understanding of this new 4.1 feature is that these check constraints should now be validated during model validation, which means a ModelForm should raise a ValidationError if the constraint is invalidated, and I would assume an invalid form is returned to the user showing some kind of error message. So far, that’s not at all what’s happening for me, it’s like nothing’s changed. Have I somehow misunderstood what this feature does?
The only part of this that might interfere with validation is the fact that I’ve overwritten form_valid()
in the view so I can run a custom method if necessary, but I call the super()
method, so all the validation should run as normal.