¡@

Home 

OpenStack Study: formset.py

OpenStack Index

**** CubicPower OpenStack Study ****

# vim: tabstop=4 shiftwidth=4 softtabstop=4

#

# Licensed under the Apache License, Version 2.0 (the "License"); you may

# not use this file except in compliance with the License. You may obtain

# a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

# License for the specific language governing permissions and limitations

# under the License.

import itertools

import logging

import sys

from django import template

from django.template import loader

from django.utils import datastructures

from horizon.tables import base as horizon_tables

LOG = logging.getLogger(__name__)

**** CubicPower OpenStack Study ****

class FormsetCell(horizon_tables.Cell):

"""A DataTable cell that knows about its field from the formset."""

**** CubicPower OpenStack Study ****

    def __init__(self, *args, **kwargs):

        super(FormsetCell, self).__init__(*args, **kwargs)

        try:

            self.field = (self.row.form or {})[self.column.name]

        except KeyError:

            self.field = None

        else:

            if self.field.errors:

                self.attrs['class'] = (self.attrs.get('class', '') +

                    ' error control-group')

                self.attrs['title'] = ' '.join(

                    unicode(error) for error in self.field.errors)

**** CubicPower OpenStack Study ****

class FormsetRow(horizon_tables.Row):

"""A DataTable row that knows about its form from the formset."""

template_path = 'horizon/common/_formset_table_row.html'

**** CubicPower OpenStack Study ****

    def __init__(self, column, datum, form):

        self.form = form

        super(FormsetRow, self).__init__(column, datum)

        if self.cells == []:

            # We need to be able to handle empty rows, because there may

            # be extra empty forms in a formset. The original DataTable breaks

            # on this, because it sets self.cells to [], but later expects a

            # SortedDict. We just fill self.cells with empty Cells.

            cells = []

            for column in self.table.columns.values():

                cell = self.table._meta.cell_class(None, column, self)

                cells.append((column.name or column.auto, cell))

            self.cells = datastructures.SortedDict(cells)

**** CubicPower OpenStack Study ****

    def render(self):

        return loader.render_to_string(self.template_path,

            {"row": self, "form": self.form})

**** CubicPower OpenStack Study ****

class FormsetDataTableMixin(object):

"""A mixin for DataTable to support Django Formsets.

This works the same as the ``FormsetDataTable`` below, but can be used

to add to existing DataTable subclasses.

"""

formset_class = None

**** CubicPower OpenStack Study ****

    def __init__(self, *args, **kwargs):

        super(FormsetDataTableMixin, self).__init__(*args, **kwargs)

        self._formset = None

        # Override Meta settings, because we need custom Form and Cell classes,

        # and also our own template.

        self._meta.row_class = FormsetRow

        self._meta.cell_class = FormsetCell

        self._meta.template = 'horizon/common/_formset_table.html'

**** CubicPower OpenStack Study ****

    def get_required_columns(self):

        """Lists names of columns that have required fields."""

        required_columns = []

        if self.formset_class:

            empty_form = self.get_formset().empty_form

            for column in self.columns.values():

                field = empty_form.fields.get(column.name)

                if field and field.required:

                    required_columns.append(column.name)

        return required_columns

**** CubicPower OpenStack Study ****

    def _get_formset_data(self):

        """Formats the self.filtered_data in a way suitable for a formset."""

        data = []

        for datum in self.filtered_data:

            form_data = {}

            for column in self.columns.values():

                value = column.get_data(datum)

                form_data[column.name] = value

            form_data['id'] = self.get_object_id(datum)

            data.append(form_data)

        return data

**** CubicPower OpenStack Study ****

    def get_formset(self):

        """Provide the formset corresponding to this DataTable.

        Use this to validate the formset and to get the submitted data back.

        """

        if self._formset is None:

            self._formset = self.formset_class(

                self.request.POST or None,

                initial=self._get_formset_data(),

                prefix=self._meta.name)

        return self._formset

**** CubicPower OpenStack Study ****

    def get_empty_row(self):

        """Return a row with no data, for adding at the end of the table."""

        return self._meta.row_class(self, None, self.get_formset().empty_form)

**** CubicPower OpenStack Study ****

    def get_rows(self):

        """Return the row data for this table broken out by columns.

        The row objects get an additional ``form`` parameter, with the

        formset form corresponding to that row.

        """

        try:

            rows = []

            if self.formset_class is None:

                formset = []

            else:

                formset = self.get_formset()

                formset.is_valid()

            for datum, form in itertools.izip_longest(self.filtered_data,

                                                        formset):

                row = self._meta.row_class(self, datum, form)

                if self.get_object_id(datum) == self.current_item_id:

                    self.selected = True

                    row.classes.append('current_selected')

                rows.append(row)

        except Exception:

            # Exceptions can be swallowed at the template level here,

            # re-raising as a TemplateSyntaxError makes them visible.

            LOG.exception("Error while rendering table rows.")

            exc_info = sys.exc_info()

            raise template.TemplateSyntaxError, exc_info[1], exc_info[2]

        return rows

**** CubicPower OpenStack Study ****

    def get_object_id(self, datum):

        # We need to support ``None`` when there are more forms than data.

        if datum is None:

            return None

        return super(FormsetDataTableMixin, self).get_object_id(datum)

**** CubicPower OpenStack Study ****

class FormsetDataTable(FormsetDataTableMixin, horizon_tables.DataTable):

"""A DataTable with support for Django Formsets.

Note that :attr:`horizon.tables.DataTableOptions.row_class` and

:attr:`horizon.tables.DataTaleOptions.cell_class` are overwritten in this

class, so setting them in ``Meta`` has no effect.

.. attribute:: formset_class

A class made with ``django.forms.formsets.formset_factory``

containing the