Faça seus ModelForms saberem se eles são parte de um CreateView ou UpdateView

Mesmo que geralmente sejam parte de um View, os do Django Form, por padrão, não estão cientes do contexto no qual estão sendo usados. Isso faz todo o sentido, em harmonia com o princípio do acoplamento fraco : a Formprecisa cuidar da validação dos dados, bem como da renderização (via Widgets) e nada mais.

No entanto, muitas vezes é o caso em que preciso de um ModelFormpara agir de maneira um pouco diferente, quer seja mencionado como parte de um CreateViewou de um UpdateView. Vejamos um exemplo rápido – digamos que estamos criando um modelo (digamos, um Appointment) que tem uma ForeignKeyrelação com um User– e queremos apenas ter usuários ativos mostrados em nosso ModelChoiceField. Porém, quando você está editando um existente Appointmentque pertence a um usuário inativo , obviamente você precisa ter esse usuário no queryset também, ou o formulário não será validado. O que nós fazemos?

Uma maneira de implementar comportamentos diferentes para formulários é apenas usar formulários diferentes ; ainda outro – para fazer o construtor do formulário aceitar um is_createviewargumento de palavra chave e adicioná-lo ao dictque é retornado por um CreateView get_form_kwargs. Ambas as formas exigem que você escreva mais código do que o necessário, especialmente quando você pode simplesmente fazer:

class AppointmentForm(ModelForm):
def __init__(self, *args, **kwargs):
if self.instance.pk is None: # it's a CreateView
self.fields['user'].queryset = ... # active users
else: # it's an UpdateView:
self.fields['user'].queryset = ... # active users + self.instance.user

instanceé um atributo de classe (muito útil) de ModelForms, que contém uma instância de sua classe de modelo (ou seja Appointment). No contexto de a CreateView, instanceainda não é salvo no banco de dados, portanto pké None. Simples assim!