Email field required django.contrib.auth - django

I want to register a user in django-rest-auth, if all username, password and email fields are provided. (I want to implement token authentication too to obtain a JSON response from the server.)
The default email field in django.contrib.auth.User is optional. But I want to set the email filed as required to register in the database so that the user gets an HTTP error response when a POST request has been made without an email.
In the project I am registering the new user through the following code.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', User.USERNAME_FIELD, "password", 'full_name',
'is_active', 'links', )
write_only_fields = ('password',)
read_only_fields = ('id',)
def create(self, validated_data):
print("Validated Data",validated_data)
if 'email' in validated_data:
user = get_user_model().objects.create(
username=validated_data['username']
)
user.set_email(validated_data['email'])
user.set_password(validated_data['password'])
user.save()
email = EmailMessage('Hello', 'World',
to=[validated_data['email']])
email.send()
user.is_active=False
return user
else:
return None
However, the above gives:
create() did not return an object instance
How do I set the email field as a required field?

I want to register an user in django-rest-auth, if all username, password and email fields are provided.
The correct way to require a field on a serializer in Django REST framework is to set required=True when initializing the field, or using the extra_kwargs parameter to set it on automatically generated fields.
In default email field in django.contrib.auth.User is optional. But I want to set the email filed as required to register in the database so that the user gets HTTP error response when POST request has been made without a email.
This means that the automatically generated field will not be required by default, but you can still override it with required=True.
However, the above gives:
create() did not return an object instance
This is because you are not returning a User instance from the create method, just like it says on the tin. Specifically, you are returning None if the email field is not included. None is not a User instance, and DRF is warning you that you're doing something wrong.

Related

does django encode passwords in the Database?

I created a user with a password password123 but in the database the password field look like this pbkdf2_sha256$260000$rJZWVrYXlokRG8fGMS1fek$S7Dm9soflUsy0Q74CJP8sB60tgfRWuRPdqj5XL0DBV0=
the problem: is when I create new user via rest framework i got the poassword feidl look like passsword123
so how should i created new user in order to keep the django password encoding functionality
also how to deactivate this password encoding functionality
Django uses encryption middlewares to encrypt passwords (since the database sees passwords as VarChar fields, so Django's model sees them as plain text unless it is told otherwise). If you want the Django User model to use encryption, you must call
user_obj.set_password(passwd_text)
With this line of code, you tell Django to run encryption algorithms. For example, in your case, you can first use the serializer's extra_kwargs to exclude passwords from database-readable data, then create the user.
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['email', 'username', 'password']
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
password = validated_data.pop("password")
user = User(**validated_data)
user.set_password(password)
user.save()
return user
if you want to read more on Django users and passwords read these docs
user model doc and
encryption types and password management doc
you need to override create method in User Create Serializer:
class UserCreateSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
return user
class Meta:
model = User
fields = "__all__" # or your specific fields
extra_kwargs = {
"password": {"write_only": True},
}
Now your user password will be saved as hashed password in database.
re. question 2.
Django does not store the password, only hashed value of the password, which it uses for comparison when the user logs in.
It is not possible to reverse engineer the password from this hash (well, mathematically it is possible, but you don't have the resources to run that process). Nor should it be.
If you wanted a password field that wasn't hashed, you would use just a string field. But... DON'T DO THIS! It is massively insecure.
There is no need for you to know the user's password.
As for question 1, I'm not sure why you're not seeing it hashed - you will need to post some code.

Required field in Django model not mandatory?

I have the following Django model:
class Customer(models.Model):
email = models.EmailField(unique=True)
In my testcase, I instantiate it without an e-mail.
class CustomerTestCase(TestCase):
def test_that_customer_can_be_created_with_minimum_data(self):
customer = Customer.objects.create()
print(customer.__dict__)
I expect it to raise an error, but it creates a record with an empty field email. The same thing happens if I explicitly say null=False and blank=False. Instead, it just prints the empty email.
{'email': ''}
What am I missing?
You're missing the fact that validation is not run on save - see the validation docs:
Note that validators will not be run automatically when you save a model, but if you are using a ModelForm, it will run your validators on any fields that are included in your form.
As that doc implies, usually validation is carried out in the context of a form.

User without username with allauth, rest_auth and facebook

I have a setup with django-rest-framework, rest-auth, allauth and facebook Oauth2. My problem here is that when I created an user using the facebook endpoint, the social user was created, the django user was also created but both have no username. Should I configure this somewhere?
The username field is no longer present, because it was deprecated with Graph API v2.0 one year ago...
See
https://developers.facebook.com/docs/apps/changelog#v2_0_graph_api
/me/username is no longer available.
Check if you're using the newest versions of your libraries.
you can set custom username by overriding DefaultSocialAccountAdapter
i just removed # from email and replaced by _ to generate username
#in setting added this
SOCIALACCOUNT_ADAPTER = 'trip2.users.adapter.SocialAdapter'
# and then override the Adapter
class SocialAdapter(DefaultSocialAccountAdapter):
def populate_user(self,
request,
sociallogin,
data):
"""
Hook that can be used to further populate the user instance.
For convenience, we populate several common fields.
Note that the user instance being populated represents a
suggested User instance that represents the social user that is
in the process of being logged in.
The User instance need not be completely valid and conflict
free. For example, verifying whether or not the username
already exists, is not a responsibility.
"""
username = data.get('username')
first_name = data.get('first_name')
last_name = data.get('last_name')
email = data.get('email')
name = data.get('name')
user = sociallogin.user
emailtouname = email.split('#')[0] + "_" + email.split('#')[1].split('.')[0]
user_email(user, valid_email_or_none(email) or '')
name_parts = (name or '').partition(' ')
user_field(user, 'first_name', first_name or name_parts[0])
user_field(user, 'last_name', last_name or name_parts[2])
user_username(user, username or emailtouname)
return user
You can pass a 'username' key along with other data retrieved via Facebook API. Or you can dig into allauth/socialaccount/adapter.py populate_user() method and customize the 'username' field (I simply make it equal to user email)

Suppressing SAVE of object in POST - Django Rest Framework

This is related to the question : Assymetric nature of GET and POST in a Django REST framework Serializer . I've put it as a fresh question, instead of putting more questions in that thread, accordingly to SO guidelines
I am writing a Viewset and a ModelSerializer for the User model to provide a /user endpoint
GET - returns list and information about all users, in the standard DRF way
POST - all I want the client to post is the facebook access_token (hence have put all other fields as read_only in serializer. The pre_save() in ViewSet is wired to use this access token and it uses django-facebook to pull data from facebook api (using access token) and automatically create a new user with that information. Since this new user is created automatically, I want to suppress the normal DRF flow during POST and not create another user via DRF. How do i do this?
views.py
from open_facebook import OpenFacebook
from django_facebook.api import FacebookUserConverter
from django_facebook.connect import connect_user
class UserViewSet(viewsets.ModelViewSet):
queryset = models.User.objects.all()
serializer_class = UserSerializer
def pre_save(self, obj):
access_token = obj.access_token
facebook = OpenFacebook(access_token)
conv = FacebookUserConverter(facebook)
action, user = connect_user(self.request, access_token)
# this creates an entire new row, just as required, in the variable "user", so all I want to do is suppress any other row creation in the standard POST method. connect_user fills in data like first_name, last_name, etc from facebook already, and that is exactly what I need to do.
conv.get_and_store_friends(user)
obj = user
user.delete()
# I am trying to do that by copying user to obj and deleting user, but at the end of it i
print obj.username
serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
"""
User Serializer
"""
class Meta:
model = models.User
fields = ('id', 'username', 'first_name', 'last_name', 'activities', 'image_url', 'url', 'access_token')
read_only_fields = ('username', 'first_name', 'last_name', 'image_url', 'activities') #todo: find out a shortcut to invert selection
# show activities with user details rather than separately to remove an extra server call
depth = 1
using the create() function of ModelViewSet worked, instead of pre_save - to suppress saving the object

How to use email instead of username for user authentication? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Accepting email address as username in Django
The authentication model provided along with Django is based on
username.
What to do to change the authentication based on email instead of
username?
To be more specific:
With username authentication, to login user we do the following:
user = authenticate(name,password)
.......
login(request,user)
What to write for the above statements if we are authenticating
using email?
For form:
I am planning to write my own form which shows the fields
email, password and the validation.
Is this the correct approach?
I found this snippet when reading a duplicate question to this one. Also check this code:
class UserForm( forms.ModelForm ):
class Meta:
model= User
exclude= ('email',)
username = forms.EmailField(max_length=64,
help_text = "The person's email address.")
def clean_email( self ):
email= self.cleaned_data['username']
return email
class UserAdmin( admin.ModelAdmin ):
form= UserForm
list_display = ( 'email', 'first_name', 'last_name', 'is_staff' )
list_filter = ( 'is_staff', )
search_fields = ( 'email', )
admin.site.unregister( User )
admin.site.register( User, UserAdmin )
Neither answer is originally mine. Up vote on the other thread to the owners for the karma boost. I just copied them here to make this thread as complete as possible.
Check out this snippet, and read the comments for updates.
For the form, why not just inherit from (or directly use) the auth login form. See django/contrib/auth/forms.py
Please see the below link which illustrates the way in which we should solve the problem.
http://groups.google.com/group/django-users/browse_thread/thread/c943ede66e6807c
Sounds like you can just mask the username with the word "email" and all the usernames will just have the email show up instead.
Unless I missed something, the solution should be really simple; just make a normal form with a text field and a password field. When the HTTP request method is POST, try to fetch the user with the given e-mail address. If such a user doesn't exist, you have an error. If the user does exist, try to authenticate the user and log her in.