Reputation: 195
How would one go about creating a user-profile page that other users can view without being able to edit the profile unless they are the user?
The thing I'm trying to work out is how the url routing would work, is it best practice to store a user's profile on a profile/ or <user_id> page and then load in the individual user's data like recent posts using the username or id passed through the url?
Also would this be handled by the one view and template and just use {% if request.user == profile.user %} to display things like edit profile etc?
my problem is any user can edit for others there profiles when he edit url
for example my id is www.test.com/profile/44/
and other user have this id www.test.com/profile/40/
okay ,, now when i edit the link to be 40 not 44 i can access and edit the second user ! how to fix that
models.py :
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email_confirmed = models.BooleanField(default=False)
@receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
def __str__(self):
return self.user
urls.py :
from django.urls import path
from blog_app.views import ProfileView
urlpatterns = [
path('profile/<int:pk>/', ProfileView.as_view(), name='profile'),
]
forms.py :
# Profile Form
class ProfileForm(forms.ModelForm):
# constructor of the UserForm, not Meta
def __init__(self, *args, **kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].widget.attrs.update({'class':'form-control','placeholder':' Enter your username in English ','style': 'font-size:19px;text-align: center;'})
class Meta:
model = User
fields = [
'username',
'first_name',
'last_name',
'email',
]
views.py:
# Edit Profile View
class ProfileView(UpdateView):
model = User
form_class = ProfileForm
success_url = reverse_lazy('home')
template_name = 'user/commons/profile.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False # Deactivate account till it is confirmed
user.save()
current_site = get_current_site(request)
subject = 'Activate Your MySite Account'
message = render_to_string('user/emails/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
user.email_user(subject, message)
messages.success(request, ('Please Confirm your new email to change email.'))
return redirect('login')
return render(request, self.template_name, {'form': form})
html page :
<button type="button" id="submit"> <a href="{% url 'profile' user.id %}" > edit profile info </a></button>
Upvotes: 0
Views: 982
Reputation: 782
You can override the get_object()
method to always return the currently logged on user from request.user
, then you will not need to provide "pk" variable in your path.
Implement get_object()
in your view
class ProfileView(UpdateView):
model = User
form_class = ProfileForm
success_url = reverse_lazy('home')
template_name = 'user/commons/profile.html'
def get_object(self, queryset=None):
return self.request.user
Then configure the path without pk
urlpatterns = [
path('profile/me/', ProfileView.as_view(), name='profile'),
]
Note that you should use login_required()
decorator or LoginRequiredMixin
on that view to avoid anonymous users accessing this view.
Upvotes: 1