Skip to content

Commit bf40e41

Browse files
authored
fix #25 (#31)
* Change AutoFiled and SmallAutoField to clickhouse Int64, so that id worker can generate value for them. * `DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'` is no longer a required configuration item.
1 parent bc82d21 commit bf40e41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2195
-125
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
### 1.1.0
2+
- Change `AutoFiled` and `SmallAutoField` to clickhouse `Int64`, so that id worker can generate value for them.
3+
This allows more compatibilities with existing apps such as `django.contrib.auth`.
4+
- `DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'` is no longer a required configuration item.
5+
16
### 1.0.3
27
- Fix reading settings in explain, pull request [#13](https://github.com/jayvynl/django-clickhouse-backend/pull/13) by [mahdi-jfri](https://github.com/mahdi-jfri).
38
- Add toYYYYMM[DD[hhmmss]] functions.

README.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Read [Documentation](https://github.com/jayvynl/django-clickhouse-backend/blob/m
2828
- In outer join, clickhouse will set missing columns to empty values (0 for number, empty string for text, unix epoch for date/datatime) instead of NULL.
2929
So Count("book") resolve to 1 in a missing LEFT OUTER JOIN match, not 0.
3030
In aggregation expression Avg("book__rating", default=2.5), default=2.5 have no effect in a missing match.
31+
- Clickhouse does not support unique constraint and foreignkey constraint. `ForeignKey`, `ManyToManyField` and `OneToOneField` can be used with clickhouse backend, but no database level constraints will be added, so there could be some consistency problems.
32+
- Clickhouse does not support transaction. If any exception occurs during migrating, then your clickhouse database will be in an untracked state. Any migration should be full tested in test environment before deployed to production environment.
3133

3234
**Requirements:**
3335

@@ -85,13 +87,9 @@ DATABASES = {
8587
'HOST': 'localhost',
8688
'USER': 'DB_USER',
8789
'PASSWORD': 'DB_PASSWORD',
88-
'TEST': {
89-
'fake_transaction': True
90-
}
9190
}
9291
}
9392
DATABASE_ROUTERS = ['dbrouters.ClickHouseRouter']
94-
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
9593
```
9694

9795
```python
@@ -143,8 +141,6 @@ automatically route your queries to the right database. In the preceding example
143141
queries from subclasses of `clickhouse_backend.models.ClickhouseModel` or custom migrations with a `clickhouse` hint key to clickhouse.
144142
All other queries are routed to the default database (postgresql).
145143

146-
`DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'` is required to working with django migration.
147-
More details will be covered in [DEFAULT_AUTO_FIELD](https://github.com/jayvynl/django-clickhouse-backend/blob/main/docs/Configurations.md#default_auto_field).
148144

149145
### Model Definition
150146

@@ -224,7 +220,7 @@ this operation will generate migration file under apps/migrations/
224220
then we mirgrate
225221

226222
```shell
227-
$ python manage.py migrate
223+
$ python manage.py migrate --database clickhouse
228224
```
229225

230226
for the first time run, this operation will generate django_migrations table with create table sql like this

clickhouse_backend/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.3
1+
1.1.0

clickhouse_backend/backend/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
2323
# If a column type is set to None, it won't be included in the output.
2424
data_types = {
2525
# Django fields.
26-
"SmallAutoField": "Int16",
27-
"AutoField": "Int32",
26+
"SmallAutoField": "Int64",
27+
"AutoField": "Int64",
2828
"BigAutoField": "Int64",
2929
"IPAddressField": "IPv4",
3030
"GenericIPAddressField": "IPv6",

clickhouse_backend/backend/operations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class DatabaseOperations(BaseDatabaseOperations):
2323
"PositiveBigIntegerField": (0, 18446744073709551615),
2424
"PositiveSmallIntegerField": (0, 65535),
2525
"PositiveIntegerField": (0, 4294967295),
26-
"SmallAutoField": (-32768, 32767),
27-
"AutoField": (-2147483648, 2147483647),
26+
"SmallAutoField": (-9223372036854775808, 9223372036854775807),
27+
"AutoField": (-9223372036854775808, 9223372036854775807),
2828
"BigAutoField": (-9223372036854775808, 9223372036854775807),
2929
# Clickhouse fields.
3030
"Int8Field": (-1 << 7, -1 ^ (-1 << 7)),

clickhouse_backend/backend/schema.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from django.db.backends.ddl_references import (
88
Expressions, IndexName, Statement, Table, Columns
99
)
10+
from django.db.models.constraints import CheckConstraint, UniqueConstraint
1011
from django.db.models.expressions import ExpressionList
1112
from django.db.models.indexes import IndexExpression
1213

@@ -82,9 +83,12 @@ def table_sql(self, model):
8283
))
8384
constraints.append(self._column_check_sql(field))
8485
for constraint in model._meta.constraints:
85-
constraints.append(
86-
constraint.constraint_sql(model, self)
87-
)
86+
if isinstance(constraint, CheckConstraint):
87+
constraints.append(
88+
constraint.constraint_sql(model, self)
89+
)
90+
if any(isinstance(c, UniqueConstraint) for c in model._meta.constraints):
91+
warnings.warn("Clickhouse does not support unique constraint.")
8892

8993
engine = self._get_engine(model)
9094
extra_parts = self._model_extra_sql(model, engine)

clickhouse_backend/compat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import django
22

3-
dj32 = (3, 2) <= django.VERSION < (4, )
3+
dj3 = (3, ) <= django.VERSION < (4, )
44
dj4 = (4, ) <= django.VERSION < (5, )
55
dj_ge4 = django.VERSION >= (4, )
66
dj_ge41 = django.VERSION >= (4, 1)

clickhouse_backend/models/sql/compiler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from django.db.models.fields import BigAutoField
1+
from django.db.models.fields import AutoFieldMixin
22
from django.db.models.sql import compiler
33

44
from clickhouse_backend import compat
@@ -64,8 +64,8 @@ def as_sql(self):
6464
insert_statement = self.connection.ops.insert_statement()
6565

6666
fields = self.query.fields
67-
# For compatible with BigAutoField, add value generated by snowflake algorithm if needed.
68-
absent_of_pk = isinstance(opts.pk, BigAutoField) and opts.pk not in fields
67+
# Generate value for AutoField when needed.
68+
absent_of_pk = isinstance(opts.pk, AutoFieldMixin) and opts.pk not in fields
6969
if absent_of_pk:
7070
fields = fields + [opts.pk]
7171
for obj in self.query.objs:
Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
from .fields import patch_jsonfield
2-
from .functions import patch_functions
1+
from .fields import *
2+
from .fields import __all__ as fields_all
3+
from .functions import *
4+
from .functions import __all__ as functions_all
5+
6+
__all__ = [
7+
"patch_all",
8+
*fields_all,
9+
*functions_all,
10+
]
311

412

513
def patch_all():
6-
patch_jsonfield()
7-
patch_functions()
14+
patch_all_functions()
15+
patch_all_fields()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from django.db import models
2+
3+
from .json import patch_jsonfield
4+
5+
__all__ = [
6+
"patch_all_fields",
7+
"patch_auto_field",
8+
"patch_jsonfield",
9+
]
10+
11+
12+
def patch_all_fields():
13+
patch_auto_field()
14+
patch_jsonfield()
15+
16+
17+
def patch_auto_field():
18+
def rel_db_type_decorator(cls):
19+
old_func = cls.rel_db_type
20+
21+
def rel_db_type(self, connection):
22+
if connection.vendor == "clickhouse":
23+
return self.db_type(connection)
24+
return old_func(self, connection)
25+
26+
cls.rel_db_type = rel_db_type
27+
return cls
28+
rel_db_type_decorator(models.AutoField)
29+
rel_db_type_decorator(models.SmallAutoField)
30+
rel_db_type_decorator(models.BigAutoField)

0 commit comments

Comments
 (0)