I am creating a website using Django. Somehow I cannot register as a user as I always get the following error message:
UnboundLocalError at /register/
local variable 'context' referenced before assignment
views.py
Register a new user
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
pform = UserProfileForm(request.POST)
if form.is_valid() and pform. is_valid():
user = form.save()
profile = pform.save(commit=False)
profile.user = user
profile.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to login')
return redirect('login')
else:
context = {
'form': UserRegisterForm,
'p_form': UserProfileForm
}
return render(request, 'users/register.html', context)
Creating a profile
#login_required
def profile(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if u_form.is_valid() and p_form. is_valid():
u_form.save()
p_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('profile')
elif request.method == 'DELETE':
return redirect('startup-home')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'users/profile.html', context)
register.html
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Join Today</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">Already have an Account? <a class="ml-2" href="{% url 'login' %}">Sign In</a></small>
</div>
</div>
{% endblock content %}
Does anyone have an idea why my context is false or won't be accepted ?
UPDATE:
Because you are passing context in else statement so that's why it won't accepting.
Change this:
else:
context = {
'form': UserRegisterForm,
'p_form': UserProfileForm
}
To this:
context = {
'form': form,
'p_form': p_form
}
And your views look like this:
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
p_form = UserProfileForm(request.POST)
if form.is_valid() and p_form.is_valid():
user = form.save()
profile = pform.save(commit=False)
profile.user = user
profile.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to login')
return redirect('login')
else:
form = UserRegisterForm()
p_form = UserProfileForm() #Here you made mistake
context = {
'form': form,
'p_form': p_form
}
return render(request, 'users/register.html', context)
Here:
context = {
'form': UserRegisterForm,
'p_form': UserProfileForm
}
you are returning the actual classes, not an instance of the classes, which would be your forms.
Also, you are not actually setting context in the first part of the if, so that needs moving outside the conditional entirely.
You need to return what you've defined:
else:
form = UserRegisterForm()
pform = UserProfileForm()
context = {
'form': form,
'p_form': pform,
}
Note that the difference is in the brackets ...
UserProfileForm is just the class object.
UserProfileForm() calls the class to get an instance of the class.
Related
I created a profile form in models.py for and form.py to update it but all thing got updated except profile picture
views.py
views.py
#login_required
def update_profile(request):
if request.method == 'POST':
profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, "Your profile updated.")
else:
status_code = 400
message = 'Please correct the error below.'
messages.error(request, "Please use correct information")
else:
profile_form = ProfileForm(instance=request.user.profile)
return render(request, 'profile.html', {
'profile_form': profile_form
})
forms.py
models.py
First of, you need to include request.FILES where you initialize your form in the POST request like this:
profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
Then in your html you need to add enctype="multipart/form-data" attribute to your form:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<button type="submit" value="Submit"></button>
</form>
try using forward slash at the end of upload_to path like this: upload_to='profile_pics/'
I have a form and every time the form is updated a message is displayed "Your profile has been updated". This message is shown even if no changes has been performed in the form.
How can i prevent the form to show message only when changes has been performed?
views.py
#login_required(login_url='login')
def profilePage(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, 'Your account {} has been updated'.format(request.user.username))
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'members/profile.html', context)
forms.py
class ProfileUpdateForm(forms.ModelForm):
phone_number = PhoneNumberField(label=False, widget=forms.TextInput(attrs={'placeholder': 'Phone Number'}))
image = forms.ImageField(label=False)
class Meta:
model = Profile
fields = ['phone_number', 'image', ]
Message used in template
{% if messages %}
<div class="prof-sucmessages">
{% for message in messages %}
<div class="alert-profile alert-{{ message.tags }} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
Thank you for help!
You can use the form.has_changed() method to see if anything changed which you could use like this:
if not u_form.has_changed() and not p_form.has_changed():
# Don't perform the save operations and don't show a message
# Return an empty successful message instead
return HttpResponse(status=204)
In your view this could become:
def profilePage(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if not u_form.has_changed() and not p_form.has_changed():
# Don't perform the save operations and don't show a message
# Return an empty successful message instead
return HttpResponse(status=204)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, 'Your account {} has been updated'.format(request.user.username))
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'members/profile.html', context)
if u_form.has_changed() or p_form.has_changed():
// Don't perform the save operations and don't show a message
// Return an empty successful message instead
return HttpResponse(status=204)
I have a problem:
In my function register() I use FormRegistration of Django and my custom ProfilForm, but I cannot display the different errors (username not unique, passwords do not match, ...).
views.py
def register(request):
if request.method == 'POST':
form = UserCreate(request.POST)
form2 = ProfilForm(request.POST)
if form.is_valid() and form2.is_valid():
user = form.save()
form2 = form2.save(commit=False)
form2.user = user
form2.skill = form2.cleaned_data.get('skill')
form2.board = form2.cleaned_data.get('board')
form2.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('/accueil')
else:
form = UserCreate()
form2 = ProfilForm()
return render(
request,
'registration/register.html',
{'form2': form2},
{'form': form})
This is my template register.html for displaying errors :
{% if form.errors %}
<div class="alert alert-danger">
<p><strong>Error !</strong> <p>There was a problem while trying to register, check your fields.</p></p>
</div>
{% endif %}
{% if form.errors %}
<div class="alert alert-danger">
<p><strong>Error !</strong> <p>{{ form.username.errors|striptags }}</p></p>
</div>
{% endif %}
Any suggestions?
There are a few issues:
The line form2 = form2.save(commit=False) does not look right; you should assign the output of save() to another variable, but right now you are just overriding form2.
The last return statement should only get one dict for context:
Change you code
return render(
request,
'registration/register.html',
{'form2': form2},
{'form': form})
to
return render(
request,
'registration/register.html',
{'form2': form2, 'form': form})
i can't figure our why i can't override the post . when i post the form i go to "/" directory and nothing post . i already know knows that the forms works fine because i have it working as a fbv
my view
class ProfileUpdateView(LoginRequiredMixin, View):
template_name = "accounts/update.html"
def get_object(self):
user = get_object_or_404(User, username=self.kwargs.get("username"))
return user
def get(self, request, *args, **kwargs):
user = get_object_or_404(User, username=self.kwargs.get("username"))
user_form = UserForm(instance=user)
if user.is_client:
print("client get is working")
profile = Client.objects.get(id=user.clients.id)
profile_form = ClientForm(instance=profile)
if user.is_artisan:
profile = Artisan.objects.get(id=user.artisans.id)
profile_form = ArtisanForm(instance=profile)
return render(
request,
self.template_name,
{"user_form": user_form, "profile_form": profile_form},
)
def post(self, request, *args, **kwargs):
print("post is working")
if user.is_client:
print("client post is working")
profile_form = ClientForm(
request.POST, request.FILES, instance=profile
)
user_form = UserForm(request.POST, request.FILES, instance=user)
if user.is_artisan:
profile_form = ArtisanForm(
request.POST, request.FILES, instance=profile
)
user_form = UserForm(request.POST, request.FILES, instance=user)
if profile_form.is_valid() and user_form.is_valid():
print("form validation is working")
created_profile = profile_form.save(commit=False)
user_form.save()
created_profile.save()
reverse("accounts:profile", kwargs={"username": self.user.username})
return render(
request,
self.template_name,
{"user_form": user_form, "profile_form": profile_form},
)
template
<form action="." method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
<p> client form</p>
------------------------------------------------
{{ profile_form.as_p }}
<button class="btn btn-primary btn-round" type="submit">update</button>
</form>
Your form action is set to ".", i.e. "this directory".
Instead just leave it out to POST to the current URL.
<form method="POST" enctype="multipart/form-data">
I would like to use a model form on the django.auth user, but I want to be able to pass in the PK to the model to manage other users, not the logged in user.
Is there a way to do this or do I need to create a regular form?
Django admin site is not appropriate for my use case.
Something like (which doesn't work of course...):
View
def edit_user(request,pk):
if request.method == 'POST':
user_form = UserEditForm(queryset=User.objects.get(pk=pk),
data=request.POST)
if user_form.is_valid():
user_form.save()
messages.success(request, 'User updated successfully')
else:
messages.error(request, 'Error updating your profile')
else:
user_form = UserEditForm(queryset=User.objects.get(pk=pk))
return render(request, 'edit_user.html', {'user_form': user_form })
UserEdit Form
class UserEditForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
Template:
% block content %}
<h1>Edit User:</h1>
<p> </p>
<form action="." method="post" enctype="multipart/form-data">
{{ user_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Save changes" class="btn btn-primary"> Manage</p>
</form>
{% endblock %}
Example URL: profile/edit-user/3/
I want the form populated with the PK of the user (the 3 in this case) NOT like my edit your own profile which passes in instance=request.user:
View for profile
def user_profile(request):
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,
data=request.POST)
profile_form = UserProfileEditForm(instance=request.user.profile,
data=request.POST,
files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, 'Profile updated successfully')
else:
messages.error(request, 'Error updating your profile')
else:
user_form = UserEditForm(instance=request.user)
profile_form = UserProfileEditForm(instance=request.user.profile)
return render(request, 'profile_edit.html', {'user_form': user_form,
'profile_form': profile_form})
Still very new to django...
Thanks for your help.
BCBB
You just need to get the user you want and then pass it in to the form as the instance argument, exactly as you did with the logged in user.
def edit_user(request, pk):
user = User.objects.get(pk=pk)
if request.method == 'POST':
user_form = UserEditForm(instance=user,
data=request.POST)
...
else:
user_form = UserEditForm(instance=user)
...