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.
Related
I have a very strange error, this is my serializer class
class user_ser(ModelSerializer):
class Meta:
model = User
fields = '__all__'
depth = 1
whenever I send an API request to update user data, i got default values for is_staff and is_superuser
in the image below I send only email and password
example :
look what I got :(
this is the validated_data for the update method is :
I did not add is_staff or anything else to the request body, so why is that happening.
That's normal behavior; is_staff and is_superuser are default fields in Django used for authorization of admin users. You can view them as columns in the DB.
The real problem comes from using fields = '__all__' in the Meta class.
This is an anti-pattern since you can expose fields you didn't intend to expose. You should explicitly display fields that you intend to use.
Explicit is better than implicit.
for example I have a django model as
class User(models.Model):
email = models.EmailField(required=True, unique=True)
Isnt it redundant and against DRY principle to validate again in the ModelSerializer as following?
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
def validate_email(self, email):
try:
User.objects.get(email=email)
raise serializers.ValidationError("Email address already used")
except User.DoesNotExist:
return email
The validate_email method feels kind of against the DRY PRINCIPLE and wrong in this context since we have to access Database to validate in this method.
please correct me.
You don't have to validate the data again in the serializer if you have validation already in model level. In your case, the difference is the error message that you'll get from the API.
By default, DRF return {'field_name':['This field must be unique']} response in case of unique validation fail
Quoting #dirkgroten's comment
Note that to override the generic error message, you don't need to re-validate either. Just use the extra_kwargs attribute on the serializer as explained here
I have a simple ForeignKey relationship between two models:
class Ticket(models.Model):
description = models.CharField(max_length=1000)
created_by = models.ForeignKey(User, related_name="created_ticket")
class User(models.Model):
username = models.CharField(max_length=64, unique=True, primary_key=True)
email = models.CharField(max_length=255)
I have a serialiser for each, with the user serialized within the ticket as a nested serialiser. What I would ideally like is
in an update view of Tickets on the Browsable API, being able to choose from a dropdown list of extant users, and
when entering a username and an e-mail, the application should check if users exist with those parameters, and if so, assign them to the ticket, and if not, raise a validation error (the validation part I got working, the rest... not so much).
So far, I've tried to follow overriding the update/create methods, but when I enter a code, the application always tries to create a new object, then complains that an object with the same username (the pkey) already exists. I have tried getting some sense out of the documentation on the subject, but with not much luck.
EDIT: My update method is
def update(self, instance, validated_data):
usr_data = validated_data.pop('created_by')
instance.created_by_id = usr_data.id
return instance
I know that superusers and regular users are both just django's User objects, but how can I write a custom user class that requires some fields for plain users and doesn't require those fields for superusers?
No structure in the database is tricky. JSONFields for example may prove to be extremely hard to tame when the app grows.
I would go and try to make it "simple" - more maintainable (I imagine if you need to do stuff like that you may want to extend the model in the future). If this is a new project you can easily change the default user model. But that may or may not help you with your case.
You can always make two models:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class Mortal(AbstractBaseUser):
is_superuser = False
username = models.CharField(max_length=256)
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
class Admin(AbstractBaseUser):
is_superuser = True
username = models.CharField(max_length=256)
and then make your own authentication backend:
class MyBackend(object):
"""
Danger! A backend to authenticate only via username
"""
def authenticate(self, username=None):
try:
return Mortal.objects.get(username=username)
except Mortal.DoesNotExist:
try:
return Admin.objects.get(username=username)
except Admin.DoesNotExist:
return None
You can have a profile class (say UserProfile) with foreign key to the user that is to be created only when user signs up using the website's registration form. That way, superuser which is created on admin site or through command line wouldn't need an extra profile instance attached to it.
In django/django/contrib/auth/forms.py how to override the default method
and include the same in the users module ?
So my intention is that i want to change the username field length to 64 characters but this would not be correct to do this in django directories,because whenever new version is downloaded this file has to changed....
What exactly shoudl be changed to do this
class AuthenticationForm(forms.Form):
"""
Base class for authenticating users. Extend this to get a form that accepts
username/password logins.
"""
username = forms.CharField(label=_("Username"), max_length=30)
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
#Deniz Dogan: You also have to convince login view to use the custom form:
login(request, authentication_form=MyAuthenticationForm)
If I understand you correctly, you may be able to change it by sub-classing AuthenticationForm into e.g. MyAuthenticationForm:
class MyAuthenticationForm(AuthenticationForm):
username = forms.CharField(label=_("Username"), max_length=64)
This way, you would keep the validators from AuthenticationForm, but still let the username be 64 characters long.