SectorLabs /
django-postgres-extra
| 1 | 1 | from django.db.models import expressions, CharField |
|
|
0 ignored issues
–
show
|
|||
| 2 | |||
| 3 | |||
| 4 | 1 | class HStoreValue(expressions.Expression): |
|
| 5 | """Represents a HStore value. |
||
| 6 | |||
| 7 | The base PostgreSQL implementation Django provides, |
||
| 8 | always represents HStore values as dictionaries, |
||
| 9 | but this doesn't work if you want to use expressions |
||
| 10 | inside hstore values.""" |
||
| 11 | |||
| 12 | 1 | def __init__(self, value): |
|
| 13 | """Initializes a new instance.""" |
||
| 14 | |||
| 15 | 1 | self.value = value |
|
| 16 | |||
| 17 | 1 | def resolve_expression(self, *args, **kwargs): |
|
| 18 | """Resolves expressions inside the dictionary.""" |
||
| 19 | |||
| 20 | 1 | result = dict() |
|
| 21 | 1 | for key, value in self.value.items(): |
|
| 22 | 1 | if hasattr(value, 'resolve_expression'): |
|
| 23 | 1 | result[key] = value.resolve_expression( |
|
| 24 | *args, **kwargs) |
||
| 25 | else: |
||
| 26 | result[key] = value |
||
| 27 | |||
| 28 | 1 | return HStoreValue(result) |
|
| 29 | |||
| 30 | 1 | def as_sql(self, compiler, connection): |
|
| 31 | """Compiles the HStore value into SQL. |
||
| 32 | |||
| 33 | Compiles expressions contained in the values |
||
| 34 | of HStore entries as well. |
||
| 35 | |||
| 36 | Given a dictionary like: |
||
| 37 | |||
| 38 | dict(key1='val1', key2='val2') |
||
| 39 | |||
| 40 | The resulting SQL will be: |
||
| 41 | |||
| 42 | hstore(hstore('key1', 'val1'), hstore('key2', 'val2')) |
||
| 43 | """ |
||
| 44 | |||
| 45 | 1 | result = [] |
|
| 46 | 1 | for key, value in self.value.items(): |
|
| 47 | 1 | if hasattr(value, 'as_sql'): |
|
| 48 | 1 | sql, params = value.as_sql(compiler, connection) |
|
| 49 | 1 | result.append('hstore(\'%s\', %s)' % ( |
|
| 50 | key, sql % params)) |
||
| 51 | elif value is not None: |
||
| 52 | result.append('hstore(\'%s\', \'%s\')' % (( |
||
| 53 | key, value))) |
||
| 54 | else: |
||
| 55 | result.append('hstore(\'%s\', NULL)' % key) |
||
| 56 | |||
| 57 | 1 | return '%s' % ' || '.join(result), [] |
|
| 58 | |||
| 59 | |||
| 60 | 1 | class HStoreColumn(expressions.Col): |
|
| 61 | """HStoreColumn expression. |
||
| 62 | |||
| 63 | Generates expressions like: |
||
| 64 | |||
| 65 | [db table].[column]->'[hstore key]' |
||
| 66 | """ |
||
| 67 | |||
| 68 | 1 | contains_column_references = True |
|
| 69 | |||
| 70 | 1 | def __init__(self, alias, target, hstore_key): |
|
| 71 | """Initializes a new instance of :see:HStoreColumn. |
||
| 72 | |||
| 73 | Arguments: |
||
| 74 | alias: |
||
| 75 | The table name. |
||
| 76 | |||
| 77 | target: |
||
| 78 | The field instance. |
||
| 79 | |||
| 80 | hstore_key |
||
| 81 | The name of the hstore key to include |
||
| 82 | in the epxression. |
||
| 83 | """ |
||
| 84 | |||
| 85 | 1 | super().__init__(alias, target, output_field=target) |
|
| 86 | 1 | self.alias, self.target, self.hstore_key = alias, target, hstore_key |
|
| 87 | |||
| 88 | 1 | def __repr__(self): |
|
| 89 | """Gets a textual representation of this expresion.""" |
||
| 90 | |||
| 91 | return "{}({}, {}->'{}')".format( |
||
| 92 | self.__class__.__name__, |
||
| 93 | self.alias, |
||
| 94 | self.target, |
||
| 95 | self.hstore_key |
||
| 96 | ) |
||
| 97 | |||
| 98 | 1 | def as_sql(self, compiler, connection): |
|
|
0 ignored issues
–
show
|
|||
| 99 | """Compiles this expression into SQL.""" |
||
| 100 | |||
| 101 | 1 | qn = compiler.quote_name_unless_alias |
|
| 102 | 1 | return "%s.%s->'%s'" % (qn(self.alias), qn(self.target.column), self.hstore_key), [] |
|
| 103 | |||
| 104 | 1 | def relabeled_clone(self, relabels): |
|
| 105 | """Gets a re-labeled clone of this expression.""" |
||
| 106 | |||
| 107 | return self.__class__( |
||
|
0 ignored issues
–
show
|
|||
| 108 | relabels.get(self.alias, self.alias), |
||
| 109 | self.target, |
||
| 110 | self.hstore_key, |
||
| 111 | self.output_field |
||
|
0 ignored issues
–
show
|
|||
| 112 | ) |
||
| 113 | |||
| 114 | |||
| 115 | 1 | class HStoreRef(expressions.F): |
|
| 116 | """Inline reference to a HStore key. |
||
| 117 | |||
| 118 | Allows selecting individual keys in annotations. |
||
| 119 | """ |
||
| 120 | |||
| 121 | 1 | def __init__(self, name: str, key: str): |
|
| 122 | """Initializes a new instance of :see:HStoreRef. |
||
| 123 | |||
| 124 | Arguments: |
||
| 125 | name: |
||
| 126 | The name of the column/field to resolve. |
||
| 127 | |||
| 128 | key: |
||
| 129 | The name of the HStore key to select. |
||
| 130 | """ |
||
| 131 | |||
| 132 | 1 | super().__init__(name) |
|
| 133 | 1 | self.key = key |
|
| 134 | |||
| 135 | 1 | def resolve_expression(self, *args, **kwargs) -> HStoreColumn: |
|
| 136 | """Resolves the expression into a :see:HStoreColumn expression.""" |
||
| 137 | |||
| 138 | 1 | original_expression = super().resolve_expression(*args, **kwargs) |
|
| 139 | 1 | expression = HStoreColumn( |
|
| 140 | original_expression.alias, |
||
| 141 | original_expression.target, |
||
| 142 | self.key |
||
| 143 | ) |
||
| 144 | 1 | return expression |
|
| 145 | |||
| 146 | |||
| 147 | 1 | class NonGroupableFunc(expressions.Func): |
|
|
0 ignored issues
–
show
|
|||
| 148 | """A version of Django's :see:Func expression that |
||
| 149 | is _never_ included in the GROUP BY clause.""" |
||
| 150 | |||
| 151 | 1 | def get_group_by_cols(self): |
|
|
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
Loading history...
|
|||
| 152 | """Gets the columns to be included in the GROUP BY clause. |
||
| 153 | |||
| 154 | We have to override this because Django's default behavior |
||
| 155 | is to include function calls in GROUP by clauses.""" |
||
| 156 | return [] |
||
| 157 | |||
| 158 | |||
| 159 | 1 | class Min(NonGroupableFunc): |
|
| 160 | """Exposes PostgreSQL's MIN(..) func.""" |
||
| 161 | |||
| 162 | 1 | def __init__(self, expression): |
|
| 163 | super().__init__(expression, function='MIN') |
||
| 164 | |||
| 165 | |||
| 166 | 1 | class Max(NonGroupableFunc): |
|
| 167 | """Exposes PostgreSQL's Max(..) func.""" |
||
| 168 | |||
| 169 | 1 | def __init__(self, expression): |
|
| 170 | super().__init__(expression, function='Max') |
||
| 171 | |||
| 172 | |||
| 173 | 1 | class DateTimeEpochColumn(expressions.Col): |
|
|
0 ignored issues
–
show
|
|||
| 174 | """Gets the date/time column as a UNIX epoch timestamp.""" |
||
| 175 | |||
| 176 | 1 | contains_column_references = True |
|
| 177 | |||
| 178 | 1 | def as_sql(self, compiler, connection): |
|
|
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
Loading history...
|
|||
| 179 | """Compiles this expression into SQL.""" |
||
| 180 | |||
| 181 | sql, params = super().as_sql(compiler, connection) |
||
| 182 | return 'EXTRACT(epoch FROM {})'.format(sql), params |
||
| 183 | |||
| 184 | 1 | def get_group_by_cols(self): |
|
|
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
Loading history...
|
|||
| 185 | return [] |
||
| 186 | |||
| 187 | |||
| 188 | 1 | class DateTimeEpoch(expressions.F): |
|
|
0 ignored issues
–
show
|
|||
| 189 | """Gets the date/time column as a UNIX epoch timestamp.""" |
||
| 190 | |||
| 191 | 1 | contains_aggregate = False |
|
| 192 | |||
| 193 | 1 | def resolve_expression(self, *args, **kwargs): |
|
|
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
Loading history...
|
|||
| 194 | original_expression = super().resolve_expression(*args, **kwargs) |
||
| 195 | expression = DateTimeEpochColumn( |
||
| 196 | original_expression.alias, |
||
| 197 | original_expression.target, |
||
| 198 | ) |
||
| 199 | return expression |
||
| 200 | |||
| 201 | |||
| 202 | 1 | def IsNotNone(*fields, default=None): |
|
| 203 | """Selects whichever field is not None, in the specified order. |
||
| 204 | |||
| 205 | Arguments: |
||
| 206 | fields: |
||
| 207 | The fields to attempt to get a value from, |
||
| 208 | in order. |
||
| 209 | |||
| 210 | default: |
||
| 211 | The value to return in case all values are None. |
||
| 212 | |||
| 213 | Returns: |
||
| 214 | A Case-When expression that tries each field and |
||
| 215 | returns the specified default value when all of |
||
| 216 | them are None. |
||
| 217 | """ |
||
| 218 | |||
| 219 | when_clauses = [ |
||
| 220 | expressions.When( |
||
| 221 | ~expressions.Q(**{field: None}), |
||
|
0 ignored issues
–
show
Usage of
* or ** arguments should usually be done with care.
Generally, there is nothing wrong with usage of For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect. Loading history...
|
|||
| 222 | then=expressions.F(field) |
||
| 223 | ) |
||
| 224 | for field in reversed(fields) |
||
| 225 | ] |
||
| 226 | |||
| 227 | return expressions.Case( |
||
|
0 ignored issues
–
show
Usage of
* or ** arguments should usually be done with care.
Generally, there is nothing wrong with usage of For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect. Loading history...
|
|||
| 228 | *when_clauses, |
||
| 229 | default=expressions.Value(default), |
||
| 230 | output_field=CharField() |
||
| 231 | ) |
||
| 232 |
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.pyfiles in your module folders. Make sure that you place one file in each sub-folder.