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.
Related
I am building a web-app where people can write projects. The projects are stored in a model and I want to use the user as the foreign key so I can show the user their projects on a webpage. Instances are entered through a form.
The code always assigns the default value (1) and and not the user. Can any of you see what's causing this bug?
Here is the code for the creation of the model in models.py:
class PersonalProject(models.Model):
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
code = models.TextField()
def __str__(self):
return self.title
Heres the code for the form view to create the project in views.py:
def newproject(request):
if User is None:
messages.error(request, "Must be signed in")
return redirect('main:dashboard')
if request.method == "POST":
form = NewProjectForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('main:dashboard')
else:
messages.error(request, "Error")
else:
form = NewProjectForm()
return render(request,
"main/newproject.html",
{"form":form})
Heres the code for the homepage view in views.py:
def dashboard(request):
messages.info(request, request.user.username)
return render(request=request,
template_name="main/dashboard.html",
context={"structuredprojects": StructuredProject.objects.all(), "personalprojects": PersonalProject.objects.filter(user__username=request.user.username)})
I really hope you can help - I've been stuck on this for a while
You can set the user of the instance wrapped in the form to request.user:
from django.contrib.auth.decorators import login_required
#login_required
def newproject(request):
if request.method == "POST":
form = NewProjectForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('main:dashboard')
else:
messages.error(request, "Error")
else:
form = NewProjectForm()
return render(request,
"main/newproject.html",
{"form":form})
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
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.
I've been trying to use Django's authentication system to login in a user. But I can't figure out how to create a User object, I've just been playing around with it so far:
def sign_in(request):
form = NameForm(request.POST)
if form.is_valid():
post = form.save()
post.save()
username = request.POST.get(post.question_text)
password = request.POST.get(post.id_text)
user = authenticate(username=username, password=password)
if user is not None:
login(request,user)
return HttpResponse('hi')
else:
return HttpResponse('bye')
else:
form = NameForm()
return render(request, 'checkin/sign_in_new.html', {'form': form})
The program keeps returning bye. I'm not sure what I need to put as the parameters for request.POST.get(), the Django docs uses 'username' and 'password' respectively. Do I need to write code to create the user first? I created one in the Django API
The user doesn't exist. Go to admin and create one first. And yes user needs to be created before you attempt to sign in.
Okay I figured it out, I just need to create the user in my code first. I just added user = User.objects.create_user('charlie', 'charlesdsmith25#gmail.com', 'smith') so now it's:
def sign_in(request):
#we need to handle all the data that was just typed, we'll add a condition for that
form = NameForm(request.POST)
if form.is_valid():
post = form.save()
post.save()
username = request.POST.get('username')
password = request.POST.get('password')
user = User.objects.create_user('charlie', 'charlesdsmith25#gmail.com', 'smith')
auth = authenticate(username=username, password=password)
if user is not None:
login(request,user)
return HttpResponse('hi')
else:
return HttpResponse('bye')
else:
form = NameForm()
return render(request, 'checkin/sign_in_new.html', {'form': form})
I have a Django form where I'm trying to save user profile details. My UserProfile has a many to many field, which I'm having trouble saving. Here is my attempted view code:
#login_required
def updateProfile(request, uid):
import pdb; pdb.set_trace()
"""
First, grab the existing user data out of the db.
If it's not there, we'll create it, then fill in the blanks from user input on post.
"""
requested_user = get_object_or_404(User, pk=uid)
user_profile = None
try:
user_profile = UserProfile.objects.get(user = requested_user)
except UserProfile.DoesNotExist:
default_skill_level = SkillLevel.objects.all()[0] # default value.
user_profile = UserProfile(user = requested_user, skill_level = default_skill_level)
user_profile.save()
if request.method == 'POST':
form = UserProfileForm(request.POST, instance = user_profile)
if form.is_valid() and (request.user.id == uid or request.user.is_superuser):
obj = form.save(commit=False) # get just the object but don't commit it yet.
obj.save() # finally save it.
obj.save_m2m() # this is failing. UserProfile has no attribute save_m2m
return index(request)
else:
print "Not authorized to do that! Implement real authorization someday."
return index(request)
else:
profile_form = UserProfileForm(instance=user_profile)
context = {
'user' : request.user,
'form' : profile_form
}
return render(request, 'booker/profile.html', context)
On a POST, once the form is validated I'm able to save the basic object but afterwards saving the many to many fields fails with the given exception. What is the right way to go about this?
Example:
...
if formset.is_valid():
items = formset.save(commit=False)
for item in items:
item.save()
formset.save_m2m()
E:
Try this:
if form.is_valid() and (request.user.id == uid or request.user.is_superuser):
obj = form.save(commit=False) # get just the object but don't commit it yet.
obj.save() # finally save it.
form.save_m2m()
The save_m2m() is only required if you have previously saved with commit=False. In your example the commit=False save does not appear to be necessary.
E.g. you could replace
obj = form.save(commit=False) # get just the object but don't commit it yet.
obj.save() # finally save it.
obj.save_m2m() # this is failing. UserProfile has no attribute save_m2m
With:
form.save()
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)