To complete registration, I want users to complete secondary form. However secondary form is not submitting. I think user is not getting authenticated in the registration and then the secondary form is not submitting. The login() seems to not work.
# the form in this view that's not submitting
def agreements(request):
if request.method == "POST":
form = AgreementsForm(request.POST)
if form.is_valid():
user = request.user
agree = form.save(commit=False)
agree.save()
else:
raise ValidationError("Form is not valid. Try Again.")
else:
form = AgreementsForm()
return render(request, 'agree.html', {'form': form})
Here is the forms.py for the agreements:
class AgreementsForm(forms.ModelForm):
non_ent=forms.BooleanField(label='kdmkl kdldsk')
agreement1=forms.BooleanField(label='dmklsd. lkdfmld')
class Meta:
model = Agreements
fields = ('non_ent', 'agreement1')
def save(self, commit=True):
agree = super(AgreementsForm, self).save(commit=False)
agree.non_ent = self.cleaned_data['non_ent']
agree.agreement1 = self.cleaned_data['agreement1']
if commit:
agree.save()
return agree
Here is the initial registration view:
# register view which submits, but I think it's not authenticating the user
def registration(request):
if request.method == "POST":
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = True
user.save()
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
return redirect('agreements_page')
else:
raise ValidationError("Form is not valid. Try Again.")
else:
form = CustomUserCreationForm()
return render(request, 'register.html', {'form': form})
Agreements Model:
class Agreements(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,blank=True, null=True)
non_ent = models.BooleanField(default=False, blank=True, null=True)
agreement1 = models.BooleanField(default=False, blank=True, null=True)
date = models.DateTimeField(default=datetime.now, blank=True, null=True)
def __str__(self):
return f'{self.user} ({self.date})'
You need to authenticate user first to login :
def registration(request):
if request.method == "POST":
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = True
user.save()
# authenticate user first
user = authenticate(request,username=form.cleaned_data['username'],password=form.cleaned_data['password'])
if user:
login(request, user)
return redirect('agreements_page')
Then in your secondary form you can save request.user like this .
I hope you have a OneToOne relation with user in your Agreement model.
form = AgreementsForm(request.POST)
if form.is_valid():
agree = form.save(commit=False)
agree.user = request.user
agree.save()
Related
My UserImg Model has a user field that has editable=False.
I want this field to be automatically filled in with the user name when the user is saved from web page.
model.py
def upload_myimg_path(instance, filename):
return 'documents/{0}/{1}'.format(instance.created_by.username, filename)
class UserImg(models.Model):
user = models.ForeignKey(User, verbose_name=_('Created by'), on_delete=models.CASCADE, editable=False, null=True, blank=True)
name = models.CharField(max_length=100, default='')
image = models.ImageField(upload_to=upload_myimg_path, verbose_name=_('File'))
def __str__(self):
return str(self.user)
forms.py
class UserImgForm(forms.ModelForm):
class Meta:
model = UserImg
fields = '__all__'
views.py
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('/accounts/users')
else:
return redirect('/accounts/')
else:
form = UserImgForm
return render(request, 'accounts/user_form.html', {'form': form})
Update your view function to include current logged in user and make use of #login_required decorator to ensure that only logged in users can access this view :
from django.contrib.auth.decorators import login_required
#login_required
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit=False) # <-- commit=False does not save to database
obj.user = request.user # <-- this allows you to specify the user for your post
obj.save()
return redirect('/accounts/users')
# if the form did not validated, stay on the same page to display errors to your user
else:
form = UserImgForm()
return render(request, 'accounts/user_form.html', {'form': form})
correct answer commit=False allows you to modify the resulting object before it is actually saved to the database. It`s works for me.
Thank you very much for your help
from django.contrib.auth.decorators import login_required
#login_required
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST, request.FILES)
if form.is_valid():
link = form.save(commit=False)
link.user = request.user
link.save()
return redirect('/accounts/users')
# if the form did not validated, stay on the same page to display errors to your user
else:
form = UserImgForm()
return render(request, 'accounts/user_form.html', {'form': form})
I tried phrasing this question recently and got totally confused. I've extended the default user model with this in my models.py:
class Biography(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
biography = models.TextField(max_length=500, blank=True,default='Details')
I've included this in the forms.py:
class EditProfileForm(forms.Form):
first_name = forms.CharField(label='First Name')
last_name = forms.CharField(label='Last Name')
biography = forms.CharField(label='Biography', widget=Textarea(attrs={'rows': 5}))
I have a view to edit the profile and want to add "biography" to it, but have absolutely no clue where to start. Here's the view:
def edit_profile(request):
user = request.user
products = Product.objects.filter(user=user)
form = EditProfileForm(request.POST or None, initial={'first_name':user.first_name, 'last_name':user.last_name})
if request.method == 'POST':
if form.is_valid():
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user.save()
return render(request, 'profile.html', {'user':user, 'products':products})
context = {"form": form}
return render(request, "edit_profile.html", context)
I tried to replicate what is already there with this:
def edit_profile(request):
user = request.user
products = Product.objects.filter(user=user)
biography = Biography(user=user)
form = EditProfileForm(request.POST or None, initial={'first_name':user.first_name, 'last_name':user.last_name, 'biography':user.biography})
if request.method == 'POST':
if form.is_valid():
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user.biography = request.POST['biography']
user.save()
return render(request, 'profile.html', {'user':user, 'products':products})
context = {"form": form}
return render(request, "edit_profile.html", context)
I definitely missed the point somehow. The last time I asked this question I was somewhat chastised for not knowing how to solve it. In all honesty I'm really new to Django and am amazed I got this far, but I'm stuck. I 'think' I need to create an instance but am not sure how.
What you should do differently:
Create Biography instance if it does not exist, or get from db.
Instantiate separate forms for different request methods
Use cleaned_data as input validation is one of the main purposes of forms
Always redirect after POST
Save User and Biography instances separately
And you don't need related products in form view. If only you are not going to somehow update them here.
For example:
def edit_profile(request):
user = request.user
biography, created = Biography.objects.get_or_create(user=user)
form = EditProfileForm(initial={
'first_name': user.first_name,
'last_name': user.last_name,
'biography': biography.biography
})
if request.method == 'POST':
form = EditProfileForm(data=request.POST)
if form.is_valid():
user.first_name = form.cleaned_data['first_name'] # use cleaned_data
user.last_name = form.cleaned_data['last_name']
biography.biography = form.cleaned_data['biography']
biography.save() # save Biography object
user.save() # save User object
return redirect(biography) # always redirect after successful POST. In this case Biography must have get_absolute_url() method
context = {'form': form}
return render(request, 'edit_profile.html', context)
Read more in documentation.
user.biography is an instance of Biography model, so what you should do here is get that instance and edit its attributes, like this:
bio = user.biography
bio.biography = request.POST['biography']
bio.save()
I have extended the user model with an extra field - biography. It appears in the admin panel as a new section. Here's a picture:
Here's the new model:
class Biography(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
biography = models.TextField(max_length=500, blank=True)
Here's the profile view:
def profile(request, username):
user = get_object_or_404(User, username=username)
products = Product.objects.filter(user=user)
if not request.user == user:
return render(request, 'no.html')
else:
return render(request, 'profile.html', {'user':user,'products': products})
I'm using a form to edit the profile - here's the view:
def edit_profile(request):
user = request.user
products = Product.objects.filter(user=user)
form = EditProfileForm(request.POST or None, initial={'first_name':user.first_name, 'last_name':user.last_name, 'biography':user.biography})
if request.method == 'POST':
if form.is_valid():
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user.biography = request.POST['biography']
user.save()
return render(request, 'profile.html', {'user':user, 'products':products})
context = {"form": form}
return render(request, "edit_profile.html", context)
...and here's the form:
class EditProfileForm(forms.Form):
first_name = forms.CharField(label='First Name')
last_name = forms.CharField(label='Last Name')
biography = forms.CharField(label='Biography', widget=Textarea(attrs={'rows': 5}))
Here's a screenshot of the error message:
I'm mixing something up but I can't figure out what. Doesn't help that I'm new to this ...still trying!
As the error message says:
"User.Biography" must be a "Biography" instance.
In your edit_profile definition, you have the following assignment:
user.biography = request.POST['biography']
request.POST['biography'] is not a valid instance of Biography. So, you have to create a valid Biography instance, according to your Biography model, with the request.POST['biography'].
After that, you can assign your valid instance to user.biography.
I hope it had been useful for you.
Hi have changed my view from this:
How to make User able to create own account with OneToOne link to Profile - Django
For some reason the profile_form is not saving the 'user' information to the database. I have checked the information in the print(profile_form.user) data and does show the username in the terminal. It is not however saving this foreign key to the database, it just leaves it Null.
To this:
Views.py
class IndexView(View):
template_name = 'homepage.html'
form = UserCreationForm
profile_form = ProfileForm
def post(self, request):
user_form = self.form(request.POST)
profile_form = self.profile_form(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
profile_form.save(commit=False)
profile_form.user = user
print(profile_form.user)
print(profile_form)
profile_form.save()
return render(request, self.template_name)
else:
return render(request, self.template_name, {'user_form': self.form,
'profile_form': self.profile_form})
def get(self, request):
if self.request.user.is_authenticated():
return render(request, self.template_name)
else:
return render(request, self.template_name, {'user_form': self.form, 'profile_form': self.profile_form})
Forms.py
class ProfileForm(ModelForm):
"""
A form used to create the profile details of a user.
"""
class Meta:
model = Profile
fields = ['organisation', 'occupation', 'location', 'bio']
Models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
organisation = models.CharField(max_length=100, blank=True)
occupation = models.CharField(max_length=100, blank=True)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
The user is an attribute of the instance, not the form.
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
print(profile.user)
profile.save()
I am using Django 1.5. I am a custom User model like this:
class User(AbstractBaseUser):
#id = models.IntegerField(primary_key=True)
#identifier = models.CharField(max_length=40, unique=True, db_index=True)
username = models.CharField(max_length=90, unique=True, db_index=True)
create_time = models.DateTimeField(null=True, blank=True)
update_time = models.DateTimeField(null=True, blank=True)
email = models.CharField(max_length=225)
#password = models.CharField(max_length=120)
external = models.IntegerField(null=True, blank=True)
deleted = models.IntegerField(null=True, blank=True)
purged = models.IntegerField(null=True, blank=True)
form_values_id = models.IntegerField(null=True, blank=True)
disk_usage = models.DecimalField(null=True, max_digits=16, decimal_places=0, blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
class Meta:
db_table = u'galaxy_user'
I have a custom authentication:
class AuthBackend:
def authenticate(self, username=None, password=None):
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'username': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Even after entering the correct username and password check_password() always returning false so that I can't login. I tried that in terminal too:
user.check_password(password)
is always returning False.
#views.py:
def login_backend(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
state = "Username or Password Incorrect!"
if user is not None:
login(request, user)
return HttpResponseRedirect('/overview/')
else:
return render_to_response('login_backend.html', {'state':state}, context_instance=RequestContext(request))
else:
return render_to_response('login_backend.html', context_instance=RequestContext(request))
The problem is that when you create your CustomUser, you save the password in open-way(without hashing). Can you give me your RegistrationForm code?
In my case:
# forms/register.py
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
class Meta:
model = CustomUser
fields = ['username', 'password', 'email']
Register-handler:
# views.py
def register(request):
"""
User registration view.
"""
if request.method == 'POST':
form = RegistrationForm(data=request.POST)
if form.is_valid():
user = form.save() # Save your password as a simple String
return redirect('/')
else:
form = RegistrationForm()
return render(request, 'news/register.html', {'form': form})
So when you try to login:
if user.check_password(password):
return user
check_password always returns False.
Solution:
To set password properly, you should redefine save() method in RegistrationForm:
# forms/register.py
class RegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
class Meta:
model = CustomUser
fields = ['username', 'password', 'email']
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(user.password) # set password properly before commit
if commit:
user.save()
return user
Or simply change handler:
def register(request):
"""
User registration view.
"""
if request.method == 'POST':
form = RegistrationForm(data=request.POST)
if form.is_valid():
user = form.save(commit=False)
user.set_password(request.POST["password"])
user.save()
return redirect('/')
else:
form = RegistrationForm()
return render(request, 'news/register.html', {'form': form})