I am trying to create a new user from the modelform by calling the CustomerUserManager in managers.py
class CustomUserCreationForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super(CustomUserCreationForm,self).__init__(*args, **kwargs)
try:
if args[0]["email"]:
self.email= args[0]["email"]
self.password= args[0]["password1"]
except:
pass
class Meta:
model = CustomUser
fields = "__all__"
def save(self, **kwargs):
return CustomUserManager.create_user(self,email=self.email,password=self.password,name="hic")
The managers.py is
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, name,**extra_fields):
...
user = self.model(email=email,name=name, stripe_customer_id=customer.id ,**extra_fields)
user.set_password(password)
user.save()
return user
Obviously the self.model does not exist, so how can I correctly create that user from the modelform? If I import the model, I get circular error import.
here is my model.py
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
name = models.CharField(verbose_name=_("first name"), max_length=50)
stripe_customer_id = models.CharField(max_length=120)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
objects = CustomUserManager()
I'm not sure why you would want a save function in your form, rather than in your view using the model's save() function after your form data has validated...
That said, if you do want a create_user function in your manager, you would call it like
from django.contrib.auth import get_user_model
get_user_model().objects.create_user(...)
This should ensure the model is present to be referred to.
Related
I have a custom user model, I would like my CustomUser model to have a OneToOne relationship with the Person model; Since I want to first register persons and then create a username for them, since not all registered people need to have a username.
I have tried the code shown below; but what I get is the following error:
Cannot assign "1": "CustomUser.dni" must be a "Person" instance.
But, the ID number is already registered in the Person table
P.S. If anyone has a better suggestion for getting people to register first and then create a username for them when strictly necessary, I'd really appreciate it.
models.py
from .managers import CustomUserManager
# MODEL PERSON
class Person(models.Model):
dni = models.CharField('Número de DNI', max_length=8, unique=True)
...
# MODEL CUSTOMUSER
class CustomUser(AbstractBaseUser, PermissionsMixin):
dni = models.OneToOneField(Person, on_delete=models.CASCADE, unique=True)
email = models.EmailField('Correo electrónico', max_length=355, unique=True)
is_staff = models.BooleanField(default=True)
is_active = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = 'dni'
REQUIRED_FIELDS = ['email']
...
managers.py
from django.contrib.auth.models import BaseUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, dni, email, password=None):
if not dni:
raise ValueError('Debe ingresar el número de DNI.')
person = self.model(
dni=dni,
email=self.normalize_email(email),
)
person.set_password(password)
person.save(using=self._db)
return person
def create_superuser(self, dni, email, password=None):
person = self.create_user(
dni,
password=password,
email=email,
)
person.is_admin = True
person.is_superuser = True
person.save(using=self._db)
return person
settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'
views.py
from accounts.forms import RegisterForm
class RegisterView(View):
form_class = RegisterForm
initial = {'key': 'value'}
template_name = 'accounts/register.html'
def get(self, request, *args, **kwargs):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Cuenta creada para exitosamente.')
return redirect(to='/')
return render(request, self.template_name, {'form': form})
I want to register a person in the Person table.
After creating the person, you should only be able to create their username and password, from the administration site; that is, an external person cannot register on the site, because the site will have many people in the database, but only some of them will be users of the system.
I hope this image helps clarify the idea.
Process flow
What you're probably looking to do is subclass the django registration form. Then you can change the fields that are required.
I believe the password field would be required by default so a NULL value would not be valid. However, you could quite easily set the password as a randomly generated UUID and then manually change it in the admin panel.
I modified the Auth User by using AbstractUser Class.
Registered it in settings. Everything else is working
I can create an instance using the User Model
BUT
The Problem comes during the serialization.
My serializer doesn't throw any error, but any time I try and use the serializer.data I get AttributeError: 'str' object has no attribute '_meta'.
User Model
class User(AbstractUser):
# Add additional fields here
email = models.EmailField(max_length=254, unique=True)
name = models.CharField(max_length=100)
username = models.CharField(max_length=100)
password = models.CharField(max_length=100)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
first_name=None
last_name=None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'username', 'password']
objects = CustomUserManager()
def __str__(self):
return self.email
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
Custom Manager
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import gettext_lazy as _
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
User Serializer
from rest_framework import serializers
from django.conf import settings
User = settings.AUTH_USER_MODEL
class UserSerializer(serializers.ModelSerializer):
print("UserSerializer")
class Meta:
model = User
# fields = (['id', 'username', 'email', 'name'])
fields = '__all__'
View
#api_view(['POST'])
def createUser(request):
data = request.data
serializer = UserSerializer(data,many=False)
if serializer.is_valid():
print(type(serializer.data))
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I've stuck with the code for the last 7-8 hours. Even tried specifying the fields but I haven't been able to figure out why this is happening.
You should work with the get_user_model() function [Django-doc] to obtain a reference to the user model, the AUTH_USER_MODEL setting [Django-doc] is only a string to the name of that model:
from rest_framework import serializers
from django.contrib.auth import get_user_model
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = '__all__'
When a user is created on Django admin panel, objects = CustomUserManager() is not being executed. However, when I create a superuser from the CLI using python manage.py createsuperuser, objects = CustomUserManager() is executed.
Here is the model file
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
name = models.CharField(verbose_name=_("first name"), max_length=50)
stripe_customer_id = models.CharField(max_length=120)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
objects = CustomUserManager()
def __str__(self):
return self.name
Here is the customUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, name,**extra_fields):
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
customer = stripe.Customer.create(
email=email,
name=name,
)
user = self.model(email=email,name=name, stripe_customer_id=customer.id ,**extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password,name,**extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, name,**extra_fields)
Below is how I registered the admin panel.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
from django.utils.translation import gettext_lazy as _
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
....
admin.site.register(CustomUser, CustomUserAdmin)
Below is the CustomUserCreationForm
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = "__all__"
UserAdmin relies on the implementation in ModelAdmin to construct an instance, validate the form, and then save the instance, rather than calling a custom method on the model's manager.
Call chain: ModelAdmin.add_view() → ... → self._changeform_view(), which calls:
(i) form.is_valid() (of ModelForm) → ... → self._post_clean() → self.instance = construct_instance(...),
(ii) self.save_form(...) → new_object = form.save(commit=False) (of BaseModelForm) returning self.instance, and
(iii) self.save_model(..., new_object, ...) → obj.save().
You can override ModelAdmin.save_form to call the custom user manager's create_user method and replace form.instance:
class CustomUserAdmin(UserAdmin):
model = CustomUser
fieldsets = (
(None, {'fields': (model.USERNAME_FIELD, 'name', 'password')}),
) + UserAdmin.fieldsets[2:]
add_fieldsets = (
(None, {'fields': (model.USERNAME_FIELD, 'name', 'password1', 'password2')}),
)
ordering = (model.USERNAME_FIELD,)
def save_form(self, request, form, change):
if not change:
form.instance = self.model.objects.create_user(
form.cleaned_data['email'],
form.cleaned_data['password1'],
form.cleaned_data['name'],
)
return super().save_form(request, form, change)
⚠️ Notice in the usual call chain that save_form() does not call obj.save(), as ModelAdmin handles multiple formsets and m2m models, while CustomUserManager.create_user does call user.save(). It is ok to change this behaviour in UserAdmin with known scope, though you may consider splitting CustomUserManager.create_user into CustomUserManager.construct_instance and CustomUserManager.save_new_model (move stripe.Customer.create(...) and user.save() here).
As a matter of fact, your custom methods create_user (and create_superuser, which you probably overwrote as well) are not called when you create a new user from the admin panel. I'm not sure neither to understand why but I think the create_user function is just a shortcut.
Why not overriding the save() method of your CustomUser? From the Django documentation:
A classic use-case for overriding the built-in methods is if you want something to happen whenever you save an object.
Isn't exactly what you're looking for? Check the Django documentation here (to do so at the form level) and here (if you prefer change the model itself directly, no matter which form is used) for more information.
For instance, if you prefer the second option, you can add this method to CustomUser:
from django.apps.apps import get_model
from django.db import transaction
class CustomUser(AbstractUser):
# your initial code goes here ...
def save(self, *args, **kwargs):
# make the distinction between the creation and the update of the instance
if not self._state.adding:
# doesn't change the initial method if the user has already been saved in DB
return super(CustomUser, self).save(*args, **kwargs)
# guarantee of atomicity
with transaction.atomic():
# dynamic resolution to avoid a circular import, might not be necessary
customer = get_model("stripe", "Customer").create(
email=self.email,
name=self.name,
)
self.stripe_customer_id = customer.id
super(CustomUser, self).save(*args, **kwargs)
return self
Don't forget to make the distinction between the creation and the update of an instance.
I'm trying to create a profile in the DRF create function in serializer, but when save User model the next exception is triggered
ValueError: "<Usuario: Some Name>" needs to have a value for field "id" before this many-to-many relationship can be used.
This is my configuration background over python 3
Django == 1.11
DRF == Django rest framework
class CustomUserManager(BaseUserManager):
def _create_user(self, firstname, lastname, password, **extra_fields):
now = timezone.now()
if not firstname:
raise ValueError(u'The firstname is required.')
user = self.model(
firstname=firstname,
lastname=lastname,
last_login=now,
**extra_fields
)
user.set_password(password)
user.save()
return user
class Usuario(
AbstractBaseUser, PermissionsMixin,
TimeStampedModel, SoftDeletableModel
):
objects = CustomUserManager()
class Profile(models.Model):
user = models.OneToOneField(Usuario, related_name='profile', on_delete=models.CASCADE)
class UserSerializer(serializers.ModelSerializer):
profile = PerfilSerializer(read_only=True)
def create(self, validate_data):
user_data = validate_data
profile_data = validate_data.pop('profile')
usr = Usuario(**user_data)
usr.save()
profl = Profile(**profile_data)
profl.save()
profl.user.set(usr)
return usr
I want to get the model with the user instance and the profile created
You are on the right track, just tweak your create on the profile serializer. Try this:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
def create(self, validated_data):
user = User.objects.create(**validated_data)
Profile.objects.create(user=user)
return user
Simply use Django Signals on User save.
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
Check out this concrete tutorial, as it solves your problem.
https://simpleisbetterthancomplex.com/tutorial/2016/07/28/how-to-create-django-signals.html
Glad to help you!
I want to get information from current user in my forms.py
My Model:
class Users(models.Model):
first_name = models.CharField('First name', max_length=50)
....
user = models.OneToOneField(User, editable=False)
My view:
#login_required
def editAccount(request):
if request.method == 'POST':
form = EditAccountForm(request.user, request.POST)
if form.is_valid():
form.save()
My Form:
class EditAccountForm(forms.ModelForm):
class Meta:
model = Users
def __init__(self, user, *args, **kwargs):
self.user = user.get_profile()
I put in my settings.py AUTH_PROFILE_MODULE = "user.Users", I have this error: Deprecation Warning: The use of AUTH_PROFILE_MODULE to define user profiles has been deprecated. self.user = user.get_profile()
I'm new on django I don't see my mistake.
Thanks a lot
There is no error in your code. What you see is just a deprecation warning.
Starting Django 1.5, AUTH_PROFILE_MODULE has been deprecated in favour of custom User models.
Your code should still work though, but ideally you should read up on custom User model and start using it.
The AUTH_PROFILE_MODULE setting, and the django.contrib.auth.models.User.get_profile() was depreciated in Django 1.5 See AUTH_PROFILE_MODULE
For your code try this:
models.y
class Users(models.Model):
user = OneToOneField(User, related_name="profile")
forms.py
class EditAccountForm(forms.ModelForm):
class Meta:
model = Users
def __init__(self, user, *args, **kwargs):
self.user = user.profile
Here's the related question with answers
Another thing that you could do is simple call the model that created the user and
request for the information. IE
Your created user profile.
class User(models.Model):
username = models.OneToOneField(User, editable=False)
first_name = models.CharField("Last name", max_length=50)
last_name = models.CharField("First Name", max_length=50)
email = models.EmailField(blank=True)
def __str__(self):
return "%s" % self.username
Then in your view you could do something like
class UserProfileView(View):
def get(self, request):
self.user = request.user
#from here you can call your user model requesting for the user information.
self.userdetails = Users.objects.get(username=self.user)
if(self.userdetails):
#user exists
#you can pass this to the templates and perform actions on using loops
for details in self.userdetails:
print details.username
print details.first_name
print details.last_name
#.....