Как изменить первичный ключ, отправленный в представление обновления в django?

django #django-models #django-views #django-forms #django-templates

#django #django-модели #django-views #django-forms #django-шаблоны

Вопрос:

Я хочу изменить первичный ключ, отправляемый в представление обновления из шаблона. Позвольте мне объяснить. Вот мой шаблон:

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

Это model_instance экземпляр в цикле for контекстной переменной model_instances в представлении списка. Затем этот первичный ключ model_instance будет отправлен в следующее представление:

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

Однако проблема в том, что первичный ключ, на который я отправляю UserUpdateView , является первичным ключом для model_instance модели, а не User для модели. Более того, между двумя моделями нет связи, подобной взаимно однозначным отношениям. Однако есть сходство. Оба model_instance и user каждый имеют username одинаковое поле.

Другими словами, мне нужно сначала получить model_instance.username , а затем запросить User модель, чтобы найти user экземпляр с тем же username , который я хочу обновить. На данный момент UserUpdateView просто получает первичный ключ для a model_instance в шаблоне, чего я не хочу. Я надеюсь, что вы, ребята, сможете помочь мне с этой проблемой, и, пожалуйста, оставьте любые вопросы, которые у вас есть. Спасибо.

Ответ №1:

Это недостаточно интуитивно понятно, но да, это возможно. Также полезно упомянуть, что вы определяете queryset атрибут в представлении, если вы хотите обновить только один объект, тогда в этом нет необходимости. Вы можете переопределить get_object метод для этого :

 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
 

Эта ссылка на шаблон :

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

теперь будет указывать пользователю на обновление, а не на model_instance.

Подробнее о get_object

Комментарии:

1. Эй, ты вернулся user из-за user = User.objects.get(username=username) ? Если вы определили его как somethingelse = User.objects.get(username=username) , тогда я должен вернуться somethignelse ?

2. @code builder, да, конечно

Ответ №2:

Поскольку model_instance и user имеют одно и то же имя пользователя, вы можете передать model_instance.username при генерации URL-адреса и изменить свой UpdateView на specify slug_field = "username" . Вам также придется изменить свой urlconfig, чтобы использовать «slug» вместо «pk» или 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")