django: excluye ciertos elementos de formulario basados ​​en una condición

Tengo algunos campos de formulario que deseo incluir / excluir en función de si se cumple o no una determinada condición. Sé cómo incluir y excluir elementos de formulario, pero tengo dificultades para hacerlo cuando quiero que se muestren elementos en función del resultado de una función.

Aquí está mi formulario:

class ProfileForm(ModelForm): # this_team = get Team instance from team.id passed in # how? def draft_unlocked(self): teams = Team.objects.order_by('total_points') count = 0 for team in teams: if team.pk == this_team.pk: break count += 1 now = datetime.datetime.now().weekday() if now >= count: # show driver_one, driver_two, driver_three else: # do not show driver_one, driver_two, driver_three class Meta: model = Team 

Lo que estoy tratando de lograr es que, en base a las posiciones del total de puntos, un equipo no debería poder cambiar su controlador hasta el día especificado. Al igual que en, el último equipo en la clasificación puede agregar / soltar un piloto el lunes, segundo al último equipo puede agregar / soltar el martes, y así sucesivamente …

Entonces, el primer problema: ¿cómo puedo obtener la instancia del Equipo dentro del formulario desde el ID que se pasó? Y, ¿cómo puedo incluir / excluir en función del resultado de draft_unlocked ()?

¿O tal vez hay una mejor manera de hacer todo esto?

Muchas gracias a todos.

En realidad, esto es bastante sencillo (configuración de campo condicional); aquí hay un ejemplo rápido:

 from django.forms import Modelform from django.forms.widgets import HiddenInput class SomeForm(ModelForm): def __init__(self, *args, **kwargs): # call constructor to set up the fields. If you don't do this # first you can't modify fields. super(SomeForm, self).__init__(*args, **kwargs) try: # make somefunc return something True # if you can change the driver. # might make sense in a model? canchangedriver = self.instance.somefunc() except AttributeError: # unbound form, what do you want to do here? canchangedriver = True # for example? # if the driver can't be changed, use a input=hidden # input field. if not canchangedriver: self.fields["Drivers"].widget = HiddenInput() class Meta: model = SomeModel 

Entonces, puntos clave de esto:

  • self.instance representa el objeto enlazado, si el formulario está enlazado. Creo que se pasa como un argumento con nombre, por lo tanto, en kwargs , que el constructor principal utiliza para crear una self.instance .
  • Puede modificar las propiedades del campo después de haber llamado al constructor principal.
  • Los widgets son como se muestran los formularios. HiddenInput básicamente significa .

Hay una limitación; Puedo alterar la entrada para cambiar un valor si modifico los datos POST / GET enviados. Si no desea que esto suceda, algo a tener en cuenta es anular el método de validación (limpiar ()) del formulario. Recuerde, todo en Django son solo objetos, lo que significa que puede modificar los objetos de clase y agregarles datos al azar (aunque no se conservará). Así que en tu __init__ podrías:

 self.instance.olddrivers = instance.drivers.all() 

Luego en su método limpio para dicha forma:

 def clean(self): # validate parent. Do this first because this method # will transform field values into model field values. # ie instance will reflect the form changes. super(SomeForm, self).clean() # can we modify drivers? canchangedriver = self.instance.somefunc() # either we can change the driver, or if not, we require # that the two lists are, when sorted, equal (to allow for # potential non equal ordering of identical elements). # Wrapped code here for niceness if (canchangedriver or (sorted(self.instance.drivers.all()) == sorted(self.instance.olddrivers))): return True else: raise ValidationError() # customise this to your liking. 

Puedes hacer lo que necesites agregando tu propio init donde puedes pasar la identificación cuando creas una instancia de la clase de formulario:

 class ProfileForm(ModelForm): def __init__(self, team_id, *args, **kwargs): super(ProfileForm, self).__init__(*args, **kwargs) this_team = Team.objects.get(pk=team_id) teams = Team.objects.order_by('total_points') count = 0 for team in teams: if team.pk == this_team.pk: break count += 1 now = datetime.datetime.now().weekday() if now >= count: # show driver_one, driver_two, driver_three else: # do not show driver_one, driver_two, driver_three class Meta: model = Team #views.py def my_view(request, team_id): profile_form = ProfileForm(team_id, request.POST or None) #more code here 

Espero que te ayude.