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")