I'm using Django 2.0 and trying to allow users to input a link to their website in a django ModelForm. I would like for my URLField to validate urls even when they have no scheme prefix.
I have read this solution: django urlfield http prefix. I'm wondering if there is a way to achieve this without writing my own custom regex in a RegexValidator. It doesn't seem like a very DRY solution to repeat all of the regex logic that is built into the URLValidator.
I want to do something like the below:
website = models.CharField(max_length=400, blank=True, null=True, validators=[URLValidator(schemes=['', 'http', 'https', 'ftp', 'ftps'])])
This obviously doesn't work because of the way the URLValidator's call method validates against the given schemes.
def __call__(self, value):
# Check first if the scheme is valid
scheme = value.split('://')[0].lower()
if scheme not in self.schemes:
raise ValidationError(self.message, code=self.code)
Adding an empty string to the schemes list doesn't work because splitting the url in this way returns the entire URL (as a user typically does not include :// if that user is not including a scheme prefix).
Now, I could subclass URLField and overwrite the entire call method in order to change the way that it handles schemes, but the call method includes all of the regex so this seems to be no more DRY than simply copying the URLField regex into my own RegexValidator.
Is there a cleaner or more "Djangonic" way to achieve this?
You could subclass the URLValidator
and prefix schemeless values with http://
before calling super()
. This avoids any duplication of code from URLValidator
.
from django.core.validators import URLValidator
class OptionalSchemeURLValidator(URLValidator):
def __call__(self, value):
if '://' not in value:
# Validate as if it were http://
value = 'http://' + value
super(OptionalSchemeURLValidator, self).__call__(value)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With