Django non persistent model field - python

I have a Django Model where I create an random password for the user.
Manager.py:
class UserManager(BaseUserManager):
def create_user(self, password=None):
user = self.model()
if password:
user.set_password(password)
else:
user.set_password(user.generate_password())
user.save()
return user
I then want to send out an email to the user with their temporary password after the model is saved.
#receiver(post_save, sender=User)
def registration_email(sender, instance, created, **kwargs):
if created:
pass
My problem is that the password is hashed (which is good) so I cannot do the following in the post_save function... instance.password. So is there a way I can have a non persistent model field to read from (just on this first save) i.e. instance.tempcleartext. Or is there a better way?

To answer your question as-is, you can grab a reference to the password before you set it:
self.temp_pw = user.generate_password()
user.set_password(self.temp_pw)
And then you have access to the password as self.temp_pw but it will be a volatile property, not one that gets saved to the db.
HOWEVER, I would strongly recommend against doing this and particularly against sending passwords by email. It is far better to provide a password reset feature, IMO.

Related

Creating a custom super user as part of a class Im taking

I'm currently taking a custom rest API class that is teaching me to build my own custom REST APIs for authentication, as well as creating custom user models.
Im running into a slight problem with the following code base:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.models import BaseUserManager
# Create your models here.
class UserProfileManager(BaseUserManager):
""" Manager for User Profiles"""
def create_user(self, email, name, password=None):
""" Create a new user profile"""
if not email:
raise ValueError('Users must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, name=name)
""" user.set_password(password) encrypts the passwords as a hash """
user.set_password(password)
""" This allows you to specify which database to use for the user accounts. Django Supports multiple Databases!!! 8D """
user.save(using=self._db)
return user
def create_superusr(self, email, name, password):
""" Create and save a new superuser with given details """
user = self.create_user(email, name, password)
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class UserProfile(AbstractBaseUser, PermissionsMixin):
""" Database model for users in system """
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserProfileManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def get_full_name(self):
""" Retrieve Full Name of User"""
return self.name
def get_short_name(self):
""" Retrieve short name of User"""
return self.name
def __str__(self):
"""Return String representation of our User """
return self.email
The primary issue is in the UserProfileManager section, the issue according to the error output is with the create_superuser section.
The error message is the following:
AttributeError: 'UserProfileManager' object has no attribute 'create_superuser'
I've checked to ensure that in my settings.py file to ensure that using the custom model, as well as Ive checked to confirm that the makemigrations and migrations commands have been run. Ive also tested by deleting the init files, as well as the database and rebuilding them.
Ive also tested to ensure that superuser works, and django admin portal is enabled, all of which without the custom user profile works fine, but with it it breaks, so I know my issue should have something to do with the section of code above, but I cant find anything. Ive checked with the official django docs, but Im at a loss at this point.
I found my error. E for Error, as in the e that was missing in def create_superusEr.
Im good now! This site is awesome! Sometimes just asking the question helps to answer it.

Adding a new field along with username and password in django's login form

I want to edit the login form provided by django and don't want to build a new one because of the security issues. I have looked at other solutions like How to use another field for logging in with Django Allauth? it's a good example but it assigns email id based on mobile number. However I want to add another field that isn't particularly to authenticate just for input based on which redirection is done. I am quite confused about my approach and whether or not it is possible to do so. Kindly suggest. Thanks.
You can do that in your forms.py file by doing this.
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password'}))
yourfield = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'yourfield'}))
def clean(self, *args, **kwargs):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
#user_qs = User.objects.filter(username=username)
#if user_qs.count() == 1:
# user = user_qs.first()
if username and password:
user = authenticate(username=username, password=password)
if not user:
raise forms.ValidationError("This user does not exist")
if not user.check_password(password):
raise forms.ValidationError("Incorrect password")
if not user.is_active:
raise forms.ValidationError("This user is no longer active")
return super(UserLoginForm, self).clean(*args, **kwargs)
Apologies if I've misunderstood your question, but here is how I've added extra fields to user registration it which seems pretty straightforward. I've included some extra related methods just to be verbose:
../forms.py:
class CustomRegistrationForm(RegistrationForm):
"""
Form for registering a new user account.
Subclasses should feel free to add any additional validation they
need, but should avoid defining a ``save()`` method -- the actual
saving of collected user data is delegated to the active
registration backend.
"""
username = forms.RegexField(regex=r'^[\w.#+-]+$',
max_length=30,
label="Username",
error_messages={'invalid': "This value may contain only letters, numbers and #/./+/-/_ characters."})
email = forms.EmailField(label="E-mail")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
extra_field = forms.CharField([field options])
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The two password fields didn't match.")
return self.cleaned_data
Then, simply set your register URL to use the proper form class:
../urls.py:
url(r'^accounts/register/$', RegistrationView.as_view(form_class=accounts.forms.CustomRegistrationForm), name='registration_register'),
Is this field not part of your standard model, or does your input need to do some extra work? You can set a signal to make some extra magic happen when the user is registered:
from forms import CustomRegistrationForm
def user_created(sender, user, request, **kwargs):
form = CustomRegistrationForm(request.POST)
user_account = get_user_account(user)
user_account.persona = form.data['persona_tier']
user_account.save()
from registration.signals import user_registered
user_registered.connect(user_created)
FYI I'm using django-registration-redux backend but this approach should help get you close regardless.

Storing password in multiple entities - Django

I'm working on Django project and I want to have two different entities in database - (default Django) User and Doctors. I want to have stored password in both entities.
def post(self, request, pk):
username = Doctor.objects.get(pk=a).email
password = Doctor.objects.get(pk=a).password
user = User.objects.create_user(username, username, password)
user.save()
return redirect('ps:index')
Atribute in forms.py for DoctorForm:
password = forms.CharField(widget=forms.PasswordInput)
But this is not working for passwords. I assume that the reason is hashing and salt. How to solve it?
Any help would be appreciated.
The password stored in database is hashed. If you want to save a new password, use user.set_password(new_password) and user.save(). Then copy the user.password to another entity.

django: create user profile for existing users automatically

I added a new UserProfile Model to my project today.
class UserProfile(models.Model):
user = models.OneToOneField(User)
...
def __unicode__(self):
return u'Profile of user: %s' % (self.user.username)
class Meta:
managed = True
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
The above code will create a user profile for each new created user.
But how to create the user profile for each existing user automatically?
Thanks
You can loop through the existing users, and call get_or_create():
for user in User.objects.all():
UserProfile.objects.get_or_create(user=user)
You could put this in a data migration if you wish, or run the code in the shell.
For existing users, it checks whether such an instance already exists, and creates one if it doesn't.
def post_save_create_or_update_profile(sender,**kwargs):
from user_profiles.utils import create_profile_for_new_user
if sender==User and kwargs['instance'].is_authenticate():
profile=None
if not kwargs['created']:
try:
profile=kwargs['instance'].get_profile()
if len(sync_profile_field(kwargs['instance'],profile)):
profile.save()
execpt ObjectDoesNotExist:
pass
if not profile:
profile=created_profile_for_new_user(kwargs['instance'])
if not kwargs['created'] and sender==get_user_profile_model():
kwargs['instance'].user.save()
to connect signal use:
post_save.connect(post_save_create_or_update_profile)
In response to your code I'll say to put a get_or_create also in a post_init listener for User.
If this "all fields null is ok" profile is just a fast example I'd put a middleware redirecting all users with no profile to the settings page asking them to fill additional data. ( probably you want to do this anyway, no one in the real world will add new data to their existing profiles if not forced or gamified into it :) )

Why is this Django form bypassing my custom manager when creating a new object?

I have a basic Django ModelForm to create a new user:
class UserCreationForm(forms.ModelForm):
class Meta:
model = User
# stuff here
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
if commit:
user.save()
return user
I also have a custom UserManager for handling the User creation function, which also creates a UserProfile and attaches it to the User:
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
"""Create a standard user."""
email = self.normalize_email(email)
user = self.model(email=email)
user.set_password(password)
user.save()
profile = UserProfile()
profile.user = user
profile.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
objects = UserManager()
However, whenever the UserCreationForm is called successfully, it creates the User, but doesn't create the UserProfile.
My question is, why is the UserCreationForm bypassing my custom UserManager? Is there some special syntax I need to give the form to tell it my model has a custom manager?
I am also using django.views.generic.CreateView as the view, so I guess I could change the post method manually to create a User and UserProfile, but I'd like to know why this is failing before coming up with some hacky fix considering it seems like a very basic operation.
Thanks

Categories