¡@

Home 

OpenStack Study: fields.py

OpenStack Index

**** CubicPower OpenStack Study ****

# 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.

from django.core.exceptions import ValidationError # noqa

from django.forms import forms

from django.forms import widgets

from django.utils.encoding import force_unicode

from django.utils.functional import Promise # noqa

from django.utils.html import conditional_escape

from django.utils.html import escape

from django.utils.translation import ugettext_lazy as _

import netaddr

import re

ip_allowed_symbols_re = re.compile(r'^[a-fA-F0-9:/\.]+$')

IPv4 = 1

IPv6 = 2

**** CubicPower OpenStack Study ****

class IPField(forms.Field):

"""Form field for entering IP/range values, with validation.

Supports IPv4/IPv6 in the format:

.. xxx.xxx.xxx.xxx

.. xxx.xxx.xxx.xxx/zz

.. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff

.. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/zz

and all compressed forms. Also the short forms

are supported:

xxx/yy

xxx.xxx/yy

.. attribute:: version

Specifies which IP version to validate,

valid values are 1 (fields.IPv4), 2 (fields.IPv6) or

both - 3 (fields.IPv4 | fields.IPv6).

Defaults to IPv4 (1)

.. attribute:: mask

Boolean flag to validate subnet masks along with IP address.

E.g: 10.0.0.1/32

.. attribute:: mask_range_from

Subnet range limitation, e.g. 16

That means the input mask will be checked to be in the range

16:max_value. Useful to limit the subnet ranges

to A/B/C-class networks.

"""

invalid_format_message = _("Incorrect format for IP address")

invalid_version_message = _("Invalid version for IP address")

invalid_mask_message = _("Invalid subnet mask")

max_v4_mask = 32

max_v6_mask = 128

**** CubicPower OpenStack Study ****

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

        self.mask = kwargs.pop("mask", None)

        self.min_mask = kwargs.pop("mask_range_from", 0)

        self.version = kwargs.pop('version', IPv4)

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

**** CubicPower OpenStack Study ****

    def validate(self, value):

        super(IPField, self).validate(value)

        if not value and not self.required:

            return

        try:

            if self.mask:

                self.ip = netaddr.IPNetwork(value)

            else:

                self.ip = netaddr.IPAddress(value)

        except Exception:

            raise ValidationError(self.invalid_format_message)

        if not any([self.version & IPv4 > 0 and self.ip.version == 4,

                    self.version & IPv6 > 0 and self.ip.version == 6]):

            raise ValidationError(self.invalid_version_message)

        if self.mask:

            if self.ip.version == 4 and \

                    not self.min_mask <= self.ip.prefixlen <= self.max_v4_mask:

                raise ValidationError(self.invalid_mask_message)

            if self.ip.version == 6 and \

                    not self.min_mask <= self.ip.prefixlen <= self.max_v6_mask:

                raise ValidationError(self.invalid_mask_message)

**** CubicPower OpenStack Study ****

    def clean(self, value):

        super(IPField, self).clean(value)

        return str(getattr(self, "ip", ""))

**** CubicPower OpenStack Study ****

class MultiIPField(IPField):

"""Extends IPField to allow comma-separated lists of addresses."""

**** CubicPower OpenStack Study ****

    def validate(self, value):

        self.addresses = []

        if value:

            addresses = value.split(',')

            for ip in addresses:

                super(MultiIPField, self).validate(ip)

                self.addresses.append(ip)

        else:

            super(MultiIPField, self).validate(value)

**** CubicPower OpenStack Study ****

    def clean(self, value):

        super(MultiIPField, self).clean(value)

        return str(','.join(getattr(self, "addresses", [])))

**** CubicPower OpenStack Study ****

class SelectWidget(widgets.Select):

"""Customizable select widget, that allows to render

data-xxx attributes from choices.

.. attribute:: data_attrs

Specifies object properties to serialize as

data-xxx attribute. If passed ('id', ),

this will be rendered as:

where 123 is the value of choice_value.id

.. attribute:: transform

A callable used to render the display value

from the option object.

"""

**** CubicPower OpenStack Study ****

    def __init__(self, attrs=None, choices=(), data_attrs=(), transform=None):

        self.data_attrs = data_attrs

        self.transform = transform

        super(SelectWidget, self).__init__(attrs, choices)

**** CubicPower OpenStack Study ****

    def render_option(self, selected_choices, option_value, option_label):

        option_value = force_unicode(option_value)

        other_html = (option_value in selected_choices) and \

                         u' selected="selected"' or ''

        if not isinstance(option_label, (basestring, Promise)):

            for data_attr in self.data_attrs:

                data_value = conditional_escape(

                    force_unicode(getattr(option_label,

                                          data_attr, "")))

                other_html += ' data-%s="%s"' % (data_attr, data_value)

            if self.transform:

                option_label = self.transform(option_label)

        return u'%s' % (

            escape(option_value), other_html,

            conditional_escape(force_unicode(option_label)))