Django: исключить определенные элементы формы на основе условия - PullRequest
6 голосов
/ 21 мая 2011

У меня есть некоторые поля формы, которые я хочу включить / исключить в зависимости от того, выполняется ли определенное условие.Я знаю, как включать и исключать элементы формы, но мне трудно это делать, когда я хочу, чтобы элементы отображались в зависимости от результата функции.

Вот моя форма:

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

Что я пытаюсь сделать, так это то, что, исходя из общего количества очков, команда не сможет сменить пилота до указанного дня.Например, последняя команда в турнирной таблице может добавить / удалить драйвер в понедельник, вторая команда может добавить / удалить во вторник, и так далее ...

Итак, первая проблема - как мнеполучить экземпляр Team внутри самой формы из идентификатора, который был передан. И как мне включить / исключить, основываясь на результате draft_unlocked ().

Или, возможно, есть лучший способ сделать всеэто?

Большое спасибо всем.

Ответы [ 2 ]

6 голосов
/ 22 мая 2011

Это на самом деле довольно просто (настройки условного поля) - вот небольшой пример:

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

Итак, ключевые моменты из этого:

  • self.instance представляет связанный объект, если форма связана. Я считаю, что он передается как именованный аргумент, поэтому в kwargs, который родительский конструктор использует для создания self.instance.
  • Вы можете изменить свойства поля после вызова родительского конструктора.
  • виджеты - это способ отображения форм. HiddenInput в основном означает <input type="hidden" .../>.

Есть одно ограничение; Я могу изменить ввод, чтобы изменить значение, если я изменю отправленные данные POST / GET. Если вы не хотите, чтобы это происходило, нужно учитывать переопределение метода проверки формы (clean ()). Помните, что все в Django - это просто объекты, что означает, что вы можете на самом деле изменять объекты класса и добавлять к ним данные произвольно (хотя это не будет сохраняться). Так что в вашем __init__ вы могли бы:

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

Тогда в вашем чистом методе для указанной формы:

def clean(self):
    # validate parent. Do this first because this method
    # will transform field values into model field values.
    # i.e. 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.
2 голосов
/ 22 мая 2011

Вы можете сделать то, что вам нужно, добавив свой собственный init, где вы можете передать идентификатор при создании экземпляра класса формы:

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

Надеюсь, что это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...