代码之家  ›  专栏  ›  技术社区  ›  meder omuraliev

如何在Django管理中呈现自定义嵌套复选框树视图?

  •  2
  • meder omuraliev  · 技术社区  · 14 年前

    bugs 映射到的模型 categories . 类别可以拥有其他类别。

    class Bug( models.Model ):
        categories = models.ManyToManyField('Category')
        name = models.CharField( max_length=100 )
        slug = models.SlugField(unique=True)
        summary = models.TextField()
        summary_markdown = models.TextField(editable=False, blank=True)
        date_added = models.DateTimeField(auto_now_add=True)
        browser = models.ManyToManyField( Browser )
        poster = models.ForeignKey(User)
    
    class Category ( models.Model ):
        name = models.CharField( max_length=100 )
        slug = models.SlugField(unique=True)
        parent = models.ForeignKey( 'self', null=True, blank=True, related_name='children' )
    
        class Meta:
        ordering = ['name']
        verbose_name_plural = 'Categories'
    
        def __unicode__(self):
        return self.name
    

    类似于:

    (checkbox) CSS
       (checkbox) Display
           (checkbox) Inline-block
           (checkbox) Block
       (checkbox) Float
       (checkbox) Height
           (checkbox) Min-height
    
    1 回复  |  直到 14 年前
        1
  •  1
  •   Seitaridis    14 年前

    我也有类似的问题,但使用的布局有点不同。您需要创建一个显示类别的自定义小部件。

    from itertools import chain
    
    from django import forms
    from django.db import models
    from django.forms.widgets import CheckboxSelectMultiple
    from django.utils.encoding import force_unicode
    from django.utils.html import conditional_escape
    from django.utils.safestring import mark_safe
    
    class CustomCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
    
        items_per_row = 1 # Number of items per row      
    
        def render(self, name, value, attrs=None, choices=()):
            if value is None: value = []
            has_id = attrs and 'id' in attrs
            final_attrs = self.build_attrs(attrs, name=name)
            output = ['<table><tr>']
            # Normalize to strings
            str_values = set([force_unicode(v) for v in value])
            for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
                # If an ID attribute was given, add a numeric index as a suffix,
                # so that the checkboxes don't all have the same ID attribute.
                if has_id:
                    final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
                    label_for = ' for="%s"' % final_attrs['id']
                else:
                    label_for = ''           
                    cb = forms.CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
                    option_value = force_unicode(option_value)
                    rendered_cb = cb.render(name, option_value)
                    option_label = conditional_escape(force_unicode(option_label))
                    if i != 0 and i % self.items_per_row == 0:
                        output.append('</tr><tr>')
                    #Here you need to put you layout logic for display the checkboxes 
                    if self.choices[i][1].parent_id is None:
                        output.append('<td nowrap><label%s>%s</label></td>' % (label_for, option_label))
                    else:
                        output.append('<td nowrap><label%s>%s %s</label></td>' % (label_for, rendered_cb, option_label))
    
            output.append('</tr></table>')       
            return mark_safe('\n'.join(output))
    

    在models.py中我有:

    class MyModelForm(ModelForm):
        my_model_types = forms.MultipleChoiceField(label='My model types', widget = CustomCheckboxSelectMultiple, required=True)
    
        class Meta:
            model = MyModel                     
    
        def __init__(self, *args, **kwargs):
            super(self.__class__, self).__init__(*args, **kwargs)
            tree = Tree()
            tree.build_tree(reasons=MyModelType.objects.all())
            list = tree.as_list()    
            CHOICES = [(rt.pk, rt) for rt in list]             
            self.fields['reason_types'].choices = CHOICES