1

How can I access the object passed by the user inside a generic view class?

In template, when the user clicks the link:

<td><a href="{% url 'update_peon' pk=item.pk %}"><button class="btn btn-warning">Edit</button></a></td>

this goes to urls.py:

url(r'^update_peon/(?P<pk>\d+)$', views.UpdatePeon.as_view(), name='update_peon'),

and my view:

   class UpdatePeon(generic.UpdateView):

        login_required = True
        template_name = 'appform/Peons/peon_form.html'
        model = Person
        form_class = PersonForm
        success_url = reverse_lazy('view_peons')

I would like to access the item.attr1 or at least item.pk inside the class so I could change the model and form accordingly, something like:

   class UpdatePeon(generic.UpdateView):

        login_required = True
        template_name = 'appform/Peons/peon_form.html'

        if item['attr1'] == "Attribute1":
            model = model1
            form = model1Form
        else:
             etc

        success_url = reverse_lazy('view_peons')

I know how to do it in a normal function based class or even if I rewrite a class based view from scratch but I don't want to do that.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
Mike Vlad
  • 351
  • 1
  • 4
  • 12
  • It's not clear why you want to change the `model` *after* you have the item. The `model` is used to fetch the item. – Alasdair May 24 '18 at 08:55
  • @Alasdair well i need to change the model because: Imagine i have a `Parent` Model with name and category as fields. For each `category` i have a child model. User clicks on `edit` and i need to display for him the appropiate `child form` since all child forms are displayed in the same view. – Mike Vlad May 24 '18 at 11:46
  • It sounds like you need to override `get_object` then. There's no point setting `self.model` after you have the item, because `self.model` isn't used after that. – Alasdair May 24 '18 at 12:17

1 Answers1

2
class UpdatePeon(generic.UpdateView):
    if item['attr1'] == "Attribute1":
        model = model1
        form = model1Form
    else:
        ...

You can't put code in the class body like this. It runs when the module is loaded, before you have access to the request.

You should override a specific method. For example you can override get_form_class to change the form class used by the view. Inside the view, you can access the object being updated with self.object.

class UpdatePeon(generic.UpdateView):
    def get_form_class(self):
        if self.object.pk == 1:
            return MyForm
        else:
            return OtherForm

You may find the ccbv website useful for exploring the update view methods.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • Thx for the response! For the `model` object i should use `get_object` ? I need to dynamically change both the `model` and the `form`. – Mike Vlad May 24 '18 at 11:28
  • Your suggestion worked great but i also need to set the `model` depending on `self.object.pk`. Right now i can only choose the form_class – Mike Vlad May 24 '18 at 11:47
  • `model` is only used to fetch the object. Once `self.get_object()` has been called, there's no point in changing `self.model`. Overriding `get_object` might work. Call `self.object = super(UpdatePeon, self).get_object()` to get the parent model, then use it to replace `self.object` with the instance of the correct model. – Alasdair May 24 '18 at 12:11