With this blog post, I will get started with the code. The code for the project can be found in the repository:
Besides the
usual Django project setup, for now the environment variables such as
SECRET_KEY have been defined in a file env.py file which is importing in settings.py
file. The variables that need to be defined are specified in env_example.py
file. There are definitely more elegant ways to do this, but that can come
later when I am about to deploy a first version.
Though I
intend to only collect the email of a user as required info, I thought it best
to define a custom user model rather than use the User model that is present in
django.contrib.auth.models. This is done with:
class User(AbstractUser): '''User model for authentication and authorization''' def save(self, *args, **kwargs): '''Username validation during save to db''' try: validate_email(self.username) except: raise ValidationError('Username must be a valid email') else: super().save(*args, **kwargs) def clean_fields(self, exclude=None): '''Ensure that username is a valid email in Admin dashboard.''' try: validate_email(self.username) except: raise ValidationError('Username must be a valid email')
The custom User model being defined imports AbstractUser model from django.contrib.auth.models. This provides all the working features of the in-built User model without creating a database table. For now, all I wish to do is enforce the requirement that the username should be a valid email. For that, I overrode two methods – clean_fields and save. The clean_fields method works when a form is filled such as in the Admin dashboard. Since this will be a REST API, users will be created using User.objects.create() method, and this method does not call the clean_fields model method. So, it is necessary to override the save() model method as well. Having only the save() method and omitting the clean_fields() method is possible, but when using the Admin dashboard, this will result in an exception that breaks the server rather than a nice error message in the form field.
I wrote a test for this right away in the tests.py file:
def test_username_only_email(): '''Test that the username can only be a valid email''' # Passing test with valid email user1 = User(username='someuser@domain.com') user1.set_password('somepasswordfortest') user1.save() users_in_db = User.objects.all().count() assert users_in_db == 1 # Failing test with normal text instead of email with pytest.raises(Exception): user2 = User(username='someuser') user2.set_password('someotherpassword') user2.save() users_in_db = User.objects.all().count() assert users_in_db == 1
The test creates a user with the username being a valid email and verifies that there is now one user created in the database. The test then tries to create a user with a username not being an email address and verifies that an exception is raised.
No comments:
Post a Comment