2011-05-21 57 views
6

我有,我想包括某种形式的领域排除某些表单元素/排除基于一定的条件是否得到满足。我知道如何包含和排除表单元素,但是当我希望元素根据函数的结果显示时,我很难做到。Django的:根据条件

这里是我的形式:

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 

我试图做到的是,根据总积分榜上,球队不应该是能够改变他们的司机,直到他们的指定日。正如,最后球队在积分榜上可以添加/删除一个驱动器上周一,倒数第二个团队可以在周二添加/删除,等等...

所以,第一个问题 - 我怎么得到表单本身内部的团队实例来自传入的ID。而且,如何根据draft_unlocked()的结果包含/排除。

或者,也许有更好的方式来做到这一切的?

非常感谢大家。

回答

6

这其实是相当简单的(条件字段设置) - 这里有一个简单的例子:从这个

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

你可以做你的需要添加自己的初始化,您可以在ID传递你的时候实例化表单类:

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 

希望能帮助你。