File: hstore_field.py

package info (click to toggle)
python-django-postgres-extra 2.0.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,096 kB
  • sloc: python: 9,057; makefile: 17; sh: 7; sql: 1
file content (78 lines) | stat: -rw-r--r-- 2,324 bytes parent folder | download | duplicates (3)
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
from typing import List, Optional, Tuple, Union

from django.contrib.postgres.fields import HStoreField as DjangoHStoreField
from django.db.models.expressions import Expression
from django.db.models.fields import Field


class HStoreField(DjangoHStoreField):
    """Improved version of Django's :see:HStoreField that adds support for
    database-level constraints.

    Notes:
        - For the implementation of uniqueness, see the
          custom database back-end.
    """

    def __init__(
        self,
        *args,
        uniqueness: Optional[List[Union[str, Tuple[str, ...]]]] = None,
        required: Optional[List[str]] = None,
        **kwargs
    ):
        """Initializes a new instance of :see:HStoreField.

        Arguments:
            uniqueness:
                List of keys to enforce as unique. Use tuples
                to enforce multiple keys together to be unique.

            required:
                List of keys that should be enforced as required.
        """

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

        self.uniqueness = uniqueness
        self.required = required

    def get_prep_value(self, value):
        """Override the base class so it doesn't cast all values to strings.

        psqlextra supports expressions in hstore fields, so casting all
        values to strings is a bad idea.
        """

        value = Field.get_prep_value(self, value)

        if isinstance(value, dict):
            prep_value = {}
            for key, val in value.items():
                if isinstance(val, Expression):
                    prep_value[key] = val
                elif val is not None:
                    prep_value[key] = str(val)
                else:
                    prep_value[key] = val

            value = prep_value

        if isinstance(value, list):
            value = [str(item) for item in value]

        return value

    def deconstruct(self):
        """Gets the values to pass to :see:__init__ when re-creating this
        object."""

        name, path, args, kwargs = super(HStoreField, self).deconstruct()

        if self.uniqueness is not None:
            kwargs["uniqueness"] = self.uniqueness

        if self.required is not None:
            kwargs["required"] = self.required

        return name, path, args, kwargs