Search code examples
djangodjango-modelsdjango-viewsdjango-formsdjango-users

How to update the user profile of a different user if you are logged in as the owner?


Currently, I am logged in as an owner and I want to update the fields of customers in the database. But the form does not update or show the details as a placeholder because the user model has extended the customer model and hence, the customer model does not have its own fields. How do I get the instance of the User of the Customer in the UpdateView?/How do I update the customer?

urls.py

urlpatterns = [
path('<int:pk>/update/',CustomerUpdateView.as_view()),
]

views.py

class CustomerUpdateView(OwnerAndLoginRequiredMixin, generic.UpdateView):
    template_name = "customer_update.html"
    form_class = CustomerModelForm
    queryset = Customer.objects.all()

    def get_success_url(self):
        return "/customers"

models.py

class Customer(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.user.username

class User(AbstractUser):
    is_owner = models.BooleanField(default=True)
    is_agent = models.BooleanField(default=False)
    is_customer = models.BooleanField(default=False)

forms.py

class CustomerModelForm(forms.ModelForm):
class Meta:
    model = User
    fields = (
        'email',
        'username',
        'first_name',
        'last_name',
    )

Solution

  • So at this point, I'd have to assume a few things here... Let's say you have a ListView to render a list of customers.

    views.py file:

    class CustomerListView(OwnerAndLoginRequiredMixin, generic.ListView):
         template_name = "customer_update.html"
         queryset = Customer.objects.all()
         context_object_name = 'customers'
    

    urls.py file:

    urlpatterns = [
         ...
         path('customers/', CustomerListView.as_view(), name='customers'),
         path('update-customer/<int:pk>/', CustomerUpdateView.as_view(), name='update-customer'),
         # You can pass whatever customer related info you wish via url, I'm just using id as a simply demo.
         ...
    ]
    

    html file:

    {% for customer in customers %}
         # Displaying other related info per customer
    
         # Link to click to update a particular customer profile: passing the customer pk via url
         <a href="{% url 'update-customer' customer.pk %}"> Update {{ customer.user.username|title }} Profile </a>
    {% endfor %}
    

    Back to the views.py file:

    class CustomerUpdateView(OwnerAndLoginRequiredMixin, generic.UpdateView):
         template_name = "customer_update.html"
         form_class = CustomerModelForm
         # context_object_name = 'customer'
         # queryset = Customer.objects.all() # not needed here
    
         # You can use the get_object() on the class to grab the customer object by the pk passed via url
         def get_object(self, queryset=None):
              customer_pk = self.kwargs.get('pk', None)
    
              return get_object_or_404(Customer, pk=customer_pk)
    
         # Also, you could use the get_context_data() to set the form values before rendering on the page
         def get_context_data(self, **kwargs):
              context = super().get_context_data(**kwargs)
              
              customer = self.get_object()  # -> returns a customer object
    
              # creating a dictionary to use to initialize the form: accessing the user information on the customer
              data = {
                   'username': customer.user.username,
                   'first_name': customer.user.first_name,
                   'last_name': customer.user.last_name,
                   'email': customer.user.email,
              }
    
              form = self.form_class(initial=data, instance=customer.user) # updated here too
    
              context['form'] = form  # -> updating the class view context dictionary
              return context
    
         def get_success_url(self):
              return "/customers"
    

    Now within the customer_update.html:

    <form method="POST">
         <div>
              {{ form.username }}
    
              {{ form.email }}
    
              {{ form.first_name }}
    
              {{ form.last_name }}
         </div>
         
         <input type="submit" value="Update"/>
    </form>
    

    Ideally, that should display the customer's information in the form.

    UPDATES

    To handle and save the form submission, you can use the post() on the update-view. You can add to the CustomerUpdateView:

    # Use the post method to handle the form submission
    def post(self, request, *arg, **kwargs):
    
         # Should set the user instance on the form
         customer = self.get_object()
         form = self.form_class(request.POST, instance=customer.user)  # updated here too
         
         if form.is_valid():
              form.save()
    
              return redirect('to any path of your choice') # Redirect upon submission if necessary
         else:
              print(form.errors)  # To see the field(s) preventing the form from being submitted
    
         # Passing back the form to the template
         return render(request, self.template_name, {'form': form})