Django EmailField accepts any value (including blank) - python

Having this Django model:
class Subscriber(models.Model):
email = models.EmailField(unique=True, blank=False)
I do not face any exceptions when creating a Subscriber with empty email:
>>> Subscriber.objects.create(email='')
<Subscriber: Subscriber object>
Interesting is that for the second time it will raise the IntegrityError:
>>> Subscriber.objects.create(email='')
...
IntegrityError: column email is not unique
So it seems to validate for integrity, but neither for email format nor for blank entries. How do I have the email validated?

The parameter blank is used from the form, it's not enforced at database level
From the documentation
Field.blank If True, the field is allowed to be blank. Default is
False.
Note that this is different than null. null is purely
database-related, whereas blank is validation-related. If a field has
blank=True, form validation will allow entry of an empty value. If a
field has blank=False, the field will be required.
Indeed the validator documentation says that
Note that validators will not be run automatically when you save a model
to enforce that you have to use the full_clean() method.
The error is thrown because you are trying to insert two times the empty string and you have
the unique constraint on the field.

you got to validate your e-mail field with a built in email-validator like this
from django.core.validators import validate_email
and declare your e-mail field in this way
email = models.EmailField(unique=True, validators=[validate_email,])
this way it will validate your e-mail field with a built in regular expression

Related

Django email field invalid for international email (in non-english)

I am using django REST framework.
This is my user model extended from AbstractUser
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
I am now trying to check for multiple languages my models can work.
When I validate the user object serializer using if user_serializer.is_valid(): it gives me false.
I tried entering the user details by django admin panel but there it says Email is invalid
All other fields like models.CharField work perfectly fine with other languages. But this email field does not work.
EmailField is using EmailValidator class by default which might result in an unexpected outcome. You can simply pass a custom validator class that whitelisted the domains you want. Here is the default class you might want to extend or overwrite. There is an answer with more details in StackOverflow in case you need more details.

Why am I getting IntegrityError: NOT NULL constraint failed

IntegrityError: NOT NULL constraint failed: app_userprofile.email
The field looks like this:
email = models.CharField(max_length=100, blank=True, default=None)
I do not understand. Error happens when creating instance of the model and not setting the email field. But it's blank and it's charfield, and None if not overwritten, why is it happening?
There are two option:
set null = True which is used if you want to save null value in Database.
set blank = True which is used for form validation. You can call save form without value in that field.
In your current issue you just have to add null = True.
email = models.CharField(max_length=100, blank=True, null=True, default=None)
As noted here, using null=True in charField and TextField should be avoided. Because then your field has two options for no data. one is None another is blank string.
By the way null is by default set to False in django fields and you should set it to True in your case.

Schema - Ability to change email address (primary user id) in Django

Currently my user table looks like this - (all fields are not null)
display_name = CharField # string
email_address = EmailField (primary key) # string
password = CharField # string
However, I have decided to add additional functionality and to allow users to change their email addresses.
The flow goes like this
Does anyone have any ideas on how to do this?
Currently I am thinking of something like
display_name = CharField # string
email_address = EmailField (primary key) # string
password = CharField # string
pending_email = EmailField (unique) # string
And simply hold the new email address in pending_email before replacing the old email address in email_address
But obviously this is far from perfect (e.g. pending_email unique constraint does not cover email_address)
Ive thought about just leaving it like this and performing more selects against the database with AJAX queries to check if the desired new email address already lives in email_address before allowing it to be entered into pending_email but this seems still vulnerable to race conditions and poor user experiences on top of being not very database friendly.
The standard practice in this sort of situation is to create a separate table for email addresses. That allows users to have more than one email address at a given time and one of them can be marked as default.
This is what django-allauth's EmailAddress model looks like. In fact, unless you have a very compelling reason to write your own authentication system, I highly recommend that your swith to django allauth or any of the widely used django authentication/registration system.
class EmailAddress(models.Model):
user = models.ForeignKey(allauth_app_settings.USER_MODEL,
verbose_name=_('user'))
email = models.EmailField(unique=app_settings.UNIQUE_EMAIL,
max_length=app_settings.EMAIL_MAX_LENGTH,
verbose_name=_('e-mail address'))
verified = models.BooleanField(verbose_name=_('verified'), default=False)
primary = models.BooleanField(verbose_name=_('primary'), default=False)
objects = EmailAddressManager()

Strange behavior with Django Rest Framework

I have an API developed with Django Rest Framework. I have a model with some nullable fields, they are defined with the setting
required = False
in the serializer. When I want to update an instance of this model, with a PUT request to the api, I succeed If I send the request parameters as form data, but If I send a json with request payload, the API returns a 400 bad request, stating that my non-required parameters can not be null, as in:
"gender":["This field may not be null."]
When I inspect the requests, the one with form data (which succeeds) sends:
email=abc%40abc.com&first_name=John&gender=&id=13&image_url=http%3A%2F%&last_name=Doe
And the one with json data (which fails with a 400 error) sends:
{
"id":13,
"email":"abc#abc.com",
"first_name":"John",
"last_name":"Doe",
"image_url":"http://...",
"gender":null
}
Any ideas what could be the reason?
EDIT: Model and serializer fields for gender:
In models.py:
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, null=True, blank=True)
In serializers:
gender = serializers.CharField(required=False, source='userprofile.gender')
EDIT:
From the docs:
Note: If your <field_name> is declared on your serializer with the parameter required=False then this validation step will not take place if the field is not included.
So validation step will take place if this fields is included, but still, as it is defined as nullable in the db, it should pass the validation.
When you mark a field as required=False it means that your request data can miss that field and value.
You send this in your request:
email=abc%40abc.com&first_name=John&gender=&id=13&image_url=http%3A%2F%&last_name=Doe
So you're sending a value for gender, I guess your problem is in your models, where gender is not marked as null=True. If you remove gender from your request, this should work.
email=abc%40abc.com&first_name=John&id=13&image_url=http%3A%2F%&last_name=Doe
You can use in serializers.CharField the options default. This way must work
There is a serializer option, allow_null in Django Rest Framework. I had to set it to True for nullable fields in the serializer. It started working after that.
gender = serializers.CharField(required=False, allow_null=True, source='userprofile.gender'
Though I still do not know why I need to set this flag explicitly, as the field is already defined as nullable in the model.

Django AbstractUser Inheritence Error

I'm still pretty new to Django, and have been having a problem defining my own user model that inherits from the Abstract User in Django. However, I have users already in the databse (with only usernames and passwords) and when I try to migrate the changes, I get the error that the email field is required and doesn't have a default value.
What confuses me is that I looked it up in the docs, and at https://docs.djangoproject.com/en/1.7/ref/contrib/auth/ the email field is clearly listed as optional. Furthermore, when I try to override the email field I get an error that my field clashes with the existing one.
Why is it giving me this error, and how do I fix it?
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
additionalFields = models.IntegerField(default=0)
def __unicode__(self):
return self.username
EmailField is a text field in the database, and 'empty' text fields are saved as an empty string (''). They are not empty (NULL) on a database level, and the column is defined as NOT NULL. What you need to do is set a default of '', then the migration will work.

Categories