how to validate wehther the URL given is from a specific domain or not in django

Viewed 487

I have a model:

class Profile(models.Model):
    social_github = models.URLField(blank=True, null=True)
    social_twitter = models.URLField(blank=True, null=True)
    social_linkedin = models.URLField(blank=True, null=True)
    social_youtube = models.URLField(blank=True, null=True)

I want to validate the URL to their respective domain for example, the user should only be able to submit the URL of the GitHub domain in the Github field and if the user submits the URL with other domains he should get an error

2 Answers

You can define a validator with the urlparse(…) function:

from django.core.exceptions import ValidationError

from urllib.parse import urlparse

def validate_hostname(*hostnames):
    hostnames = set(hostnames)
    def validator(value):
        try:
            result = urlparse(value)
            if result.hostname not in hostnames:
                raise ValidationError(f'The hostname {result.hostname} is not allowed.')
        except ValueError:
            raise ValidationError('invalid url')
    return validator

Then we can use this as validator:

class Profile(models.Model):
    social_github = models.URLField(
        blank=True,
        null=True,
        validators=[validate_hostname('github.com', 'www.github.com')]
    )
    social_twitter = models.URLField(
        blank=True,
        null=True,
        validators=[validate_hostname('twitter.com', 'www.twitter.com')]
    )
    # ⋮

In your class, you can write your own cleaning-functions for each field, by the name def clean_<field> e.g clean_social_githubdocs [here][1]

It takes as input only self where you can extract the data from each field e.g data_github = self.cleaned_data["social_github"].

Then you would need to validate that the domain is what you expect - which can be done in different ways, e.g by just looking at what is between www and the first "." (which of course is a very naive approach) or check if "github" is in the url (or a better approach). Doing the latter would result in the following:

from django.core.exceptions import ValidationError
class Profile(models.Model):
    social_github = models.URLField(blank=True, null=True)
    social_twitter = models.URLField(blank=True, null=True)
    social_linkedin = models.URLField(blank=True, null=True)
    social_youtube = models.URLField(blank=True, null=True)
    
   def clean_social_github(self):
       data = self.cleaned_data["social_github"]
       if "github" not in data: #"github" is not in the url
            raise ValidationError(("Wups! Input only URLs from github),code ="invalid")
       return data #No problem in the url (What you return here, overwrites what is in self.cleaned_data["social_github"], so we just return the url which was input)
              


  [1]: https://docs.djangoproject.com/en/3.2/ref/forms/validation/
Related