2012-05-08 2 views
1

У меня есть следующие модели,Как делают промежуточную таблицу инлайн * а * multiplechoice

### models.py 

class Foo(models.Model): 
    name = models.CharField(max_length=200) 

class Bar(models.Model): 
    foo = models.ForeignKey(Foo) 
    baz = models.ManyToManyField(Baz, through='Between') 

class Baz(models.Model): 
    name = models.CharField(max_length=200) 

class Between(models.Model): 
    foo = models.ForeignKey(Foo) 
    bar = models.ForeignKey(Bar) 
    CHOICES = (
     ('A', 'A'), 
     ('B', 'B'), 
     ('C', 'C'), 
     ) 
    value = models.CharField(max_length=1, choices=CHOICES) 

и у меня есть следующие формы,

### forms.py 
class FooForm(forms.ModelForm): 
    class Meta: 
     model = Foo 

class BarForm(forms.ModelForm): 
    baz = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), 
             queryset=Baz.objects.all()) 
    class Meta: 
     model = Bar 
     exclude = ('foo',) 


BarFormSet = inlineformset_factory(Foo, Bar, form=BarForm, can_delete=False) 

Теперь это прекрасно работает в том, что я могу оказать один Foo, и я получаю ряд встроенных форм для Bar. Это означает, что inline BarForm предоставляет все опции Baz как флажки.

Что я хочу для каждой записи Baz для отображения в виде набора переключателей, представляющих возможные варианты для value --- вместе с выбором «N/A» --- так, чтобы, если A, B , или C, то подразумевается отношение к Baz. Но по умолчанию не кажется, что это хороший способ сделать это с полной повторной реализацией RadioSelect или реализацией совершенно нового виджета, но я бы хотел пойти по пути наименьшего сопротивления.

Надеюсь, я проясню ситуацию.

+0

Радио кнопки не допускают множественный выбор. Они могут использоваться с простым '(Model) ChoiceField', – ilvar

+0

да, я это понимаю. но должен быть способ сделать это. Я считаю, что SuperForms.py пыталась это сделать некоторое время назад? – milkypostman

+0

Это поведение браузера. Почему вы хотите его разбить? – ilvar

ответ

0

Моим решением было создать SuperForm, который позволяет создавать подформы. Общее решение не совсем generic для всех, но я сделал все возможное, чтобы взять то, что я использовал, и сделать его более общим.

Вот models.py:

from django.db import models 

class Enemy(models.Model): 
    name = models.CharField(max_length=200) 
    def __unicode__(self): 
     return self.name 

class Hero(models.Model): 
    name = models.CharField(max_length=200) 
    enemy = models.ManyToManyField(Enemy, through='Relationship', blank=False, null=False) 
    def __unicode__(self): 
     return self.name 

class Relationship(models.Model): 
    hero = models.ForeignKey(Hero) 
    enemy = models.ForeignKey(Enemy) 
    ENEMY_TYPE_CHOICES = (
     ('G', 'Good'), 
     ('B', 'Bad'), 
     ('U', 'Ugly'), 
     ) 
    enemy_type = models.CharField(max_length=1, choices=ENEMY_TYPE_CHOICES) 

    def __unicode__(self): 
     return u"{0} {1} {2}".format(self.hero, self.strength, self.relationship) 

Вот что в моем forms.py:

from models import * 
from django import forms 
from django.forms.formsets import formset_factory, BaseFormSet 
from django.forms.models import inlineformset_factory, BaseModelFormSet 
from django.utils.safestring import mark_safe 


class SuperForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     self.formsets = [] 
     super(SuperForm, self).__init__(*args, **kwargs) 

    @property 
    def is_bound(self): 
     return self._is_bound or \ 
      any([subformset.is_bound for subformset in self.formsets]) 

    @is_bound.setter 
    def is_bound(self, value): 
     self._is_bound = value 

    def has_changed(self): 
     return bool(self.changed_data) or \ 
      any([subformset.has_changed() for subformset in self.formsets]) 

    def update_empty_permitted(self, subformset): 
     empty_permitted = not self.has_changed() 
     for subformset in self.formsets: 
      for form in subformset: 
       form.empty_permitted = empty_permitted 

    def is_valid(self): 
     subforms_valid = True 
     for subformset in self.formsets: 
      self.update_empty_permitted(subformset) 
      sfserrors = [err for err in subformset.errors if err] 
      if bool(sfserrors): 
       subforms_valid = False 

     return subforms_valid and super(SuperForm, self).is_valid() 

class RelationshipForm(forms.ModelForm): 
    enemy = forms.ModelChoiceField(queryset=Enemy.objects.all(), 
            widget=forms.HiddenInput(), 
            required=True) 
    enemy_type = forms.ChoiceField(label="", widget=forms.RadioSelect, 
           choices=Relationship.ENEMY_TYPE_CHOICES, 
           required=True) 
    def name(self): 
     pk = self['enemy'].value() 
     return self.fields['enemy'].queryset.get(pk=pk) 

    class Meta: 
     model = Relationship 
     exclude = ('hero', 'enemy_type',) 


RelationshipFormSet = formset_factory(RelationshipForm, extra=0, can_delete=False) 

class HeroForm(SuperForm): 
    def __init__(self, *args, **kwargs): 
     super(HeroForm, self).__init__(*args, **kwargs) 

     initial=[dict(enemy=enemy.pk) for enemy in Enemy.objects.all()] 
     self.relationship_formset = RelationshipFormSet(initial=initial, prefix=self.prefix, data=kwargs.get('data')) 
     self.formsets.append(self.relationship_formset) 

    class Meta: 
     model = Hero 
     exclude = ('enemy',) 

HeroFormSet = formset_factory(HeroForm, extra=1, can_delete=False) 

Вот views.py:

from django.views.generic import TemplateView 
from django.views.generic.edit import FormMixin 
from forms import * 

class HeroView(FormMixin, TemplateView): 
    template_name = "formfun/hero.html" 
    form_class = HeroFormSet 

    def get_context_data(self, **kwargs): 
     context = super(HeroView, self).get_context_data(**kwargs) 
     context['formset'] = HeroFormSet() 
     return context 

    def form_valid(self, form): 
     return render_to_response({'form':form, 'valid': True}) 

    def form_invalid(self, form): 
     return render_to_response({'form':form, 'valid': False}) 

А вот шаблон, как я сделать его:

{% extends "base.html" %} 
{% block title %}form fun{% endblock %} 

{% block content %} 
<form> 
    {% for form in formset %} 
    {{ form.as_p }} 
    {% for subform in form.relationship_formset %} 
    <label for="id_{{ subform.html_name }}_0" class="label50">{{ subform.name }}</label> 
    {{ subform.as_p }} 
    {% endfor %} 
    {% endfor %} 
</form> 
{% endblock content %} 
Смежные вопросы