Django - User creation with custom user model results in internal error - python

Ok, I know this is a silly question but I am blocked and I can't figure out what to do.
I have searched on google and stackoverflow but did not found any answer :
I tried this :
Adding custom fields to users in django
Django - Create user profile on user creation
https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
My model is the following :
class UserProfile(models.Model):
user = models.OneToOneField(User)
quota = models.IntegerField(null = True)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
And my view for user registration is the following :
def register(request):
if request.method == 'POST': # If the form has been submitted...
form = RegistrationForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
cd = form.cleaned_data
#Then we create the user
user = User.objects.create_user(cd['username'],cd["email"],cd["password1"])
user.get_profil().quota = 20
user.save()
return HttpResponseRedirect('')
else:
form = RegistrationForm() # An unbound form
return render(request, 'registration_form.html', {'form': form,})
The line that launches an InternalError is :
user = User.objects.create_user(cd['username'],cd["email"],cd["password1"])
And the error is :
InternalError at /register/
current transaction is aborted, commands ignored until end of transaction block
Thank you for your help

user = User.objects.create_user(username=form.cleaned_data['username'],
password=form.cleaned_data['password'],
email=form.cleaned_data['email'])
user.is_active = True
user.save()

Related

How I can escape from using sessions in Django?

What I'm trying to do?
I want to display 2 registration forms separately of each other on the same page. The forms are: built-in User model and my self created UserProfile. To track, on what form user is now, I use sessions. It some sort of flags for me at the moment.
Why I don't want to use sessions?
I discovered a 'bug', at least for me, that I don't know how to fix. Bug appears if user passed first registration form, and close browser/tab. Next time user opens registration page, it will show second registration form, instead of first, as expected.
Where bug happens, but now with code.
When user opens register page first time, built-in UserCreationForm will be show, because there is no session called username yet.
def get(self, request):
if request.session.get("username", None):
self.context["form"] = RegisterProfile()
else:
self.context["form"] = UserCreationForm()
I'm using CBV, so it's OK that function called get and first argument is self. Also I created context dictionary as instance variable, so I can just add new field form to it.
Next, if user fill in given form (note, that first form is built-in User's form) built-in User instance will be created and it's username will be stored in username session.
If you confused at the moment don't worry much, I leave full view code at the bottom.
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
request.session["username"] = request.POST["username"]
return redirect("register")
Now, when session username exsists, and user redirected to same view, my self-created form will be shown. As in first code example.
Now, bug happens. User can freely leave page, and when he come back, second registration form will be shown again. That's not what I want.
Full view code:
class Register(View):
context = {"title": "Register new account"}
def get(self, request):
if request.session.get("username", None):
self.context["form"] = RegisterProfile()
else:
self.context["form"] = UserCreationForm()
return render(request, "users/register.html", context=self.context)
def post(self, request):
if request.session.get("username", None):
form = RegisterProfile(request.POST, request.FILES)
if form.is_valid():
username = request.session.get("username", None)
if not username:
messages.error(request, "We are sorry, but error happend. Try again!")
return redirect("index")
user = User.objects.filter(username=username).first()
profile = UserProfile(
user=user,
nickname=request.POST["nickname"],
sex=request.POST["sex"],
age=request.POST["age"],
profile_picture=form.files["profile_picture"],
)
profile.save()
del request.session["username"]
messages.success(request, "Profile created successfully!")
return redirect("index")
else:
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
request.session["username"] = request.POST["username"]
return redirect("register")
self.context["form"] = form
return render(request, "users/register.html", context=self.context)
UPD 1:
I changed register logic a little, now full code looks like this:
class Register(View):
context = {"title": "Register user page"}
def get(self, request):
if request.session.get("user_data", None):
form = ProfileRegisterForm()
else:
form = UserCreationForm()
self.context["form"] = form
return render(request, "users/register.html", context=self.context)
def post(self, request):
if request.session.get("user_data", None):
form = ProfileRegisterForm(request.POST, request.FILES)
if form.is_valid():
user = User.objects.create_user(*request.session["user_data"])
user.save()
UserProfile.objects.create(
user=user,
nickname=request.POST["nickname"],
sex=request.POST["sex"],
age=request.POST["age"],
profile_picture=form.files["profile_picture"],
)
del request.session["user_data"]
messages.success(request, "Profile created successfully!")
return redirect("index")
else:
form = UserCreationForm(request.POST)
if form.is_valid():
request.session["user_data"] = [
request.POST["username"],
request.POST["password1"],
request.POST["password2"]
]
return redirect("register")
self.context["form"] = form
return redirect("register")
But anyway, I need place to store temporary data like username, password1 and password2. If someone knows, where I can store data like in sessions, please, answer bellow.

Adding a profile to user in django

Following this :
https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html#onetoone
I am having some trouble with this call:
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
In their example I am guessing this works as is on the signup of a new account because the Profile in their example has all fields that can be blank and null. In my case my profile I am trying to maintain here is called:
class APOUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
institution = models.ForeignKey("mainpage.InstitutionMember", on_delete=models.PROTECT)
gender = models.ForeignKey("mainpage.GenderTable", on_delete=models.PROTECT)
on_site_status = models.ForeignKey("mainpage.SiteStatus", on_delete=models.PROTECT)
refer_to_as = models.TextField(max_length = 30, blank=True) #if the above is custom
room_preference = models.ForeignKey("housing.Room", on_delete=models.PROTECT)
Which has references to ultimately what will be drop downs to select form a form (populated by another table with defaults). So do I remove the #reciever and then just have the users fill out the profile separately somehow after they signup and confirm their account?
I tried to mix my signup form with the profile form... but kept getting an anonmyous user object had no attribute object apouser in the views.py when I try to mix the signup forms and profile forms:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST, instance=request.user.apouser)
if form.is_valid() and profile_form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
profile_form.save()
current_site = get_current_site(request)
mail_subject = 'Activate your APO account.'
message = render_to_string('acc_active_email.html', {
'user': user,
'domain': current_site.domain,
'uid':urlsafe_base64_encode(force_bytes(user.pk)),
'token':account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return redirect('plsactivate')
#return HttpResponse('Please confirm your email address to complete the registration')
#form.save()
#username = form.cleaned_data.get('username')
#raw_password = form.cleaned_data.get('password1')
#user = authenticate(username=username, password=raw_password)
#login(request, user)
#return redirect('/')
else:
form = SignUpForm()
profile_form = ProfileForm(instance=request.user.apouser) #<-- error here
return render(request, 'signup.html', {'form': form, 'profile_form': profile_form})
#return render(request, 'signup.html', {'form': form})
So not sure the proper way to go about what I need. I have my regular user default with the basic stuff the default django signup comes up with. THen I have the APOUser with extra stuff (usually filled out in a profile) but not sure where/how to get users to fill that out.
On signup gives me the anonymous user error
After signup doesn't let the #reciever work because none of the APOUuser stuff is filled out?
Yes, remove the receiver - although it's not the cause of this specific problem, it will cause issues as soon as you fix that
The reason for your error is as it says: since you don't have a logged in user yet, you don't have a profile either. But you don't need one; there is no need to pass an instance argument there.
What you do need to do is to set the user on the result of saving the profile form - in just the she way as you set is_active on the result of saving the user form.
So:
if request.method == 'POST':
form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST,)
if form.is_valid() and profile_form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
...
else:
form = SignUpForm()
profile_form = ProfileForm()
...

Clear all Form Fields on Validation Error in Django

I have a simple user registration form (in forms.py):
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput
validators=[MinLengthValidator(6)])
password_repeat = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'password','password_repeat']
If someone tries to enter something and the validation fails I want the same form to be rendered again but all fields should be cleared. At the moment my view looks like this (in views.py):
def signup(request):
form = UserForm(request.POST or None)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
password_repeat = form.cleaned_data['password-repeat']
user.set_password(password)
user.save()
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
auth.login(request, user)
return redirect('/')
return render(request, 'signup.html', {'form': form})
The problem is that the form.fields['username'] field still contains the username that was entered and is thus passed to render.
I've been searching for a solution a while now but can't find it. My guess is that the solution has something to do with the clean() method that I don't seem to get.
This is an odd thing to want to do - it is the opposite of the question people normally ask, as most people want to preserve the fields and show the errors.
However, if you really want to clear the form, you should just instantiate a new one.
if form.is_valid():
...
else:
form = UserForm()
return render(request, 'signup.html', {'form': form})
To always clear a particular form field while preserving all form validation errors, you can create a custom input widget that always "forgets" its old value. For example:
from django import forms
class NonstickyTextInput(forms.TextInput):
'''Custom text input widget that's "non-sticky"
(i.e. does not remember submitted values).
'''
def get_context(self, name, value, attrs):
value = None # Clear the submitted value.
return super().get_context(name, value, attrs)
class MyForm(forms.Form):
username = forms.CharField(widget=NonstickyTextInput())
# ...
Reference: django.forms.Widget.get_context
Behavior
Suppose we are using MyForm in such a view:
from django.shortcuts import render, redirect
from myapp.forms import MyForm
def myview(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
# Do something with the submitted values...
return redirect('home_page')
else:
form = MyForm()
return render(request, 'myapp/myview.html', {'form': form})
When the form encounters any validation error and the form is re-displayed, all the usual validation error messages will be shown on the form, but the displayed username form field will be blank.

django auth framework prepopulating form incorrectly, giving random data to fields upon load

I am trying to create a portable auth system that can be plugged in apps, and each different app I reimplement it in has the same issues.
1-Sometimes the user that recently logged in gets their sn in the email address field when a new user tries to register, as below
2- Sometimes a new user registers and logs out but the form will put the old user's email address and password in the appropriate fields, when of course I want the form to be blank if the user has logged out
3- always the last password used is filled in upon reload
I just want the form to completely clear itself when reloaded
How to clear form fields after a submit in Django
I have tried all 3 solutions from a similar question, I reinstantiated the from after saving the valid one, made a copy of request.POST and used that instead, and I was already redirecting to begin with. Here is my form
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password')
in views.py
def register(request):
context = RequestContext(request)
registered = False
user_form = UserForm()
if request.method == 'POST':
pDict = request.POST.copy()
form = UserForm(pDict)
if form.is_valid():
user = form.save()
user.set_password(user.password)
user.save()
user_form = UserForm()
registered = True
username = pDict['username']
password = pDict['password']
user = authenticate(username=username, password=password)
login(request, user)
#locals isn't working? won't print user
return HttpResponseRedirect('/url/')
else:
print user_form.errors
template_name = 'accounts/register.html'
user_form = UserForm()
response = TemplateResponse(request, 'accounts/register.html', locals())
return response
thank you

Django - Update User/Account Management

I am trying to update my user account info through a form. I have the form ok which just displays a password/email field and cleans the email field. I am having a problem with my views. This is the error I get: Manager isn't accessible via User instances.
This is my views: my_account function.
def my_account(request):
user = request.user
if request.method == 'POST':
form = MyAccountForm(request.POST)
if form.is_valid():
user = user.objects.get(username=username),
password = user.set_password('password2'),
email = forms.cleaned_data['email']
user.save()
return HttpResponseRedirect('/')
else:
form = MyAccountForm()
variables = RequestContext(request, {
'form': form,
})
return render_to_response(
'my_account.html',
variables
)
where you have
user.objects.get
you want
User.objects.get
objects is the manager referred to in the error message, and user is the instance referred to (an instance of User, the actual class)

Categories

Resources