File: fields.py

package info (click to toggle)
django-macaddress 1.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 156 kB
  • sloc: python: 203; makefile: 7
file content (101 lines) | stat: -rw-r--r-- 3,613 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import warnings

from django.core.exceptions import ValidationError
from django.db import models
from netaddr import EUI, AddrFormatError

from . import default_dialect
from .formfields import MACAddressField as MACAddressFormField


class MACAddressField(models.Field):
    description = "A MAC address validated by netaddr.EUI"
    empty_strings_allowed = False
    dialect = None

    def __init__(self, *args, **kwargs):
        self.integer = kwargs.pop("integer", True)
        if (
            not self.integer
        ):  # If storing MAC address as string, set max_length to default (17) or use supplied kwarg value.
            kwargs["max_length"] = kwargs.get("max_length", 17)
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        """Django 1.7 migrations require this method
        https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#field-deconstruction
        """
        name, path, args, kwargs = super().deconstruct()
        kwargs["integer"] = self.integer
        return name, path, args, kwargs

    @classmethod
    def set_dialect(cls, new_dialect_clazz):
        """Setting dialect for EUI (MAC addresses) globally to this Field
        class.
        Class new_dialect_clazz should (finally) extend
        netaddr.strategy.eui48.mac_eui48.
        """
        warnings.warn(
            "The set_dialect method has been deprecated, in favor of the default_dialect utility function and "
            " settings.MACADDRESS_DEFAULT_DIALECT. See macaddress.__init__.py source or the project README for "
            "more information.",
            DeprecationWarning,
        )
        cls.dialect = new_dialect_clazz

    def get_prep_value(self, value):
        if value is None:
            return None
        if not isinstance(value, EUI):
            value = self.to_python(value)
            if self.integer:
                return int(value)
            return str(value)
        value.dialect = default_dialect(self)
        if self.integer:
            return int(value)
        return str(value)

    def get_internal_type(self):
        if self.integer:
            return "BigIntegerField"
        return "CharField"

    def from_db_value(self, value, expression, connection):
        return self.to_python(value)

    def to_python(self, value):
        if value is None:
            return value
        if isinstance(value, EUI):
            value.dialect = default_dialect(value)
            return value
        try:
            return EUI(value, version=48, dialect=default_dialect())
        except (TypeError, ValueError, AddrFormatError):
            raise ValidationError("This value must be a valid MAC address.")

    def formfield(self, **kwargs):
        defaults = {"form_class": MACAddressFormField}
        defaults.update(kwargs)
        return super().formfield(**defaults)

    def get_prep_lookup(self, lookup_type, value):
        # data is stored internally as integer so searching as string
        # yield 0 result. for example: useful for search in admin.
        if lookup_type in ("exact", "iexact", "icontains", "icontains"):
            try:
                return self.get_prep_value(value)
            except AddrFormatError:
                return None
        elif lookup_type in ("in"):
            try:
                macs = []
                for mac in value:
                    macs += [self.get_prep_value(mac)]
                return macs
            except AddrFormatError:
                return None
        else:
            raise TypeError(f"Lookup type {lookup_type!r} not supported.")