Home > database >  How do you change the primary key sent to an update view in django?
How do you change the primary key sent to an update view in django?

Time:12-04

I want to change the primary key being sent to the update view from the template. Let me explain. Here is my template:

<a href="{% url 'new_url' model_instance.pk %}">
    {{ model_instance.username }}
</a>

This model_instance is an instance in a for loop of the context variable model_instances in a list view. This primary key of the model_instance will then be sent to the following view:

class UserUpdateView(generic.UpdateView):
    template_name = "leads/update.html"
    queryset = User.objects.all()
    context_object_name = "user"
    form_class = UserUpdateForm

    def get_success_url(self):
        return reverse("some-url")

However, the problem is that the primary key I am sending to UserUpdateView is the primary key for the model_instance model, not the User model. Moreover, there is no link like one-to-one relationships between the two models. However, there is a similarity. Both of the model_instance and user each have a username field that are the same.

In other words, I need to first retrieve the model_instance.username, and then query the User model to find the user instance with the same username I want to update. At the moment, the UserUpdateView is simply receiving the primary key for a model_instance in the template, which is not what I want. I hope you guys can help me with this issue, and please leave any questions you have. Thank you.

CodePudding user response:

It's not intuitive enough but yes it is possible. It's also good to mention that you define a queryset attribute in the view, if you want update only one object then it's not necessary. You can override the get_object method to do this :

class UserUpdateView(generic.UpdateView):
    template_name = "leads/update.html"
    # queryset = User.objects.all()
    context_object_name = "user"
    form_class = UserUpdateForm

    def get_success_url(self):
        return reverse("some-url")
    
    def get_object(self):
        # Here w'll retrieve the correct object to update
        
        # First we retrieve the username of the model_instance
        model_instance = ModelInstance.objects.get(pk=self.kwargs['pk'])
        username = model_instance.username  # Retrieve the username
        
        # After, retrieve the user with username=model_instance.username
        # Normally, the username must be unique per model_instance and per user. If not an error can be trowed.
        user = User.objects.get(username=username)
        # If username is not unique, try this approach
        # user = User.objects.filter(username=username).first()

        # Return the user object
        return user

This template link :

<a href="{% url 'new_url' model_instance.pk %}">
    {{ model_instance.username }}
</a>

will now point out the user to update, not the model_instance.

More about get_object

CodePudding user response:

Since model_instance and user have the same username, you could pass in the model_instance.username when generating the url and change your UpdateView to specify slug_field = "username". You would also have to change your urlconfig to use "slug" instead of "pk" or add slug_url_kwarg = "pk" .

<a href="{% url 'new_url' model_instance.username %}">
    {{ model_instance.username }}
</a>
class UserUpdateView(generic.UpdateView):
    template_name = "leads/update.html"
    queryset = User.objects.all()
    context_object_name = "user"
    form_class = UserUpdateForm
    slug_field = "username"
    slug_url_kwarg = "pk"

    def get_success_url(self):
        return reverse("some-url")
  • Related