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)
...
Related
I use following code:
models.py
class Profile(models.Model):
location = models.CharField(max_length=300, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
)
def __str__(self):
return self.imie
views.py
def edit(request):
if request.method == 'POST':
profile = Profile.objects.get(user = request.user)
profile_form = ProfileForm(request.POST, instance = profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, ('Your profile was successfully updated!'))
return redirect('profile')
else:
messages.error(request, ('Please correct the error below.'))
else:
profile = Profile.objects.get(user = request.user)
profile_form = ProfileForm(request.POST, instance = profile)
return render(request, 'edit.html', {
'profile_form': ProfileForm
})
forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('location')
edit.html
<div class="col-md-6 offset-md-3">
<form method="post">
{% csrf_token %}
{{ profile_form.as_p }}
<button type="submit" class="btn btn-secondary">Save changes</button>
</form>
</div>
Following code should allow the user to edit data stored in Profile model and it does exactly that, however form is loaded empty (without placeholder) and I would like it to display previous values.
Edit: where the link to edit.html is anchored
it's just a simple verions of a profile page where just plain data is displayed
{% for things in logged_in_user_data %}
<ul>
<li>Your location: {{ things.location}}</li>
</ul>
{% endfor %}
with it's views.py
def profile(request):
logged_in_user_data = Profile.objects.filter(user=request.user)
return render(request, 'profile.html', {'logged_in_user_data': logged_in_user_data})
In the case the request is not a POST request you have still written ProfileForm(request.POST, instance = profile). What does this signify? It means that this form is now a bound form and a user has submitted some data to it (which here was empty since the request was not a post request). This causes the form to be rendered empty since it is considered that the user had provided those empty values. Instead you need to not pass request.POST here:
def edit(request):
profile = Profile.objects.get(user = request.user) # Move common line here
if request.method == 'POST':
profile_form = ProfileForm(request.POST, instance = profile)
if profile_form.is_valid():
profile_form.save()
messages.success(request, ('Your profile was successfully updated!'))
return redirect('profile')
else:
messages.error(request, ('Please correct the error below.'))
else:
profile_form = ProfileForm(instance=profile) # No `request.POST` here
return render(request, 'edit.html', {
# Typo noted as per comment by #A67John
'profile_form': profile_form
})
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 registration form and am adding a user profile to add another field.
after the registration form is filled and submitted the form details are not submitted
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Assigned_Group = models.CharField(max_length=500)
def __str__(self):
return self.user.username
views.py
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
profile_form = UserProfileForm(request.POST)
if form.is_valid() and profile_form.is_valid():
user = form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.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('index')
else:
form = RegistrationForm()
profile_form = UserProfileForm()
context = {'form': form, 'profile_form':profile_form}
return render(request, 'registration/register.html', context )
def index(request):
if request.user.is_authenticated:
username = request.user.username
else:
username = 'not logged in'
context = {'username':username}
return render(request, 'index.html', context)
urls.py
path('Register/', views.register, name='register'),
in your html page in body you have to insert {% csrf_token %} like:
<html>
<body>
{% csrf_token %}
</body>
Inside your html form you will need to have inserted {% csrf_token %}.
See the django docs on CSRF for more information or if you are using AJAX.
For example your html will then look something like.
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit">
</form>
Side note from the django docs (which is important).
In the corresponding view functions, ensure that RequestContext is used to render the response so that {% csrf_token %} will work properly. If you’re using the render() function, generic views, or contrib apps, you are covered already since these all use RequestContext.
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 use UserCreationForm to render registration form in Django.
class RegisterForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields
The registration view is defined as follows:
def register(request):
form = RegisterForm()
if request.method == 'POST':
form = RegisterForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
context = {'form': form}
return render(request, 'registration/register.html', context)
And the template for this:
{% if form.errors %}
<p>Some Errors occured</p>
{% endif %}
<form action="{% url 'register' %}" method="POST">
{% csrf_token %} {{ form.as_p }}
<input type="submit" value="Register">
</form>
When I submit invalid data, it does not show <p>Some Errors occured</p>, but throws
Exception Type: ValueError
Exception Value:
The view myapp.views.register didn't return an HttpResponse object. It returned None instead.
which means I have to return HttpResponsein the 2nd if/else statement. The other forms work fine and show form.error messages, except this one. What is the problem? Thanks.
form = RegisterForm(request.POST or None, request.FILES or None)
first of all you dont wanna an empty field in your register form so you dont wanna user or None . second you are using request.FILES while you have no FileField in your form . i fixed your form
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
form = RegisterForm()
return render(request, 'registration/register.html',{'form': form})
You need to move the last line back one indent, so it is run both in the case that the request is not a POST and also when it is a POST but the form is not valid.