allow uuid_format add more tests and update docs
This commit is contained in:
@ -251,11 +251,21 @@ You can use either `length` and `precision` parameters or `max_digits` and `deci
|
||||
|
||||
### UUID
|
||||
|
||||
`UUID()` has no required parameters.
|
||||
`UUID(uuid_format: str = 'hex')` has no required parameters.
|
||||
|
||||
* Sqlalchemy column: `ormar.UUID` based on `sqlalchemy.CHAR` field
|
||||
* Sqlalchemy column: `ormar.UUID` based on `sqlalchemy.CHAR(36)` or `sqlalchemy.CHAR(32)` field (for string or hex format respectively)
|
||||
* Type (used for pydantic): `uuid.UUID`
|
||||
|
||||
`uuid_format` parameters allow 'hex'(default) or 'string' values.
|
||||
|
||||
Depending on the format either 32 or 36 char is used in the database.
|
||||
|
||||
Sample:
|
||||
* 'hex' format value = "c616ab438cce49dbbf4380d109251dce" (CHAR(32))
|
||||
* 'string' value = "c616ab43-8cce-49db-bf43-80d109251dce" (CHAR(36))
|
||||
|
||||
When loaded it's always python UUID so you can compare it and compare two formats values between each other.
|
||||
|
||||
[relations]: ./relations.md
|
||||
[queries]: ./queries.md
|
||||
[pydantic]: https://pydantic-docs.helpmanual.io/usage/types/#constrained-types
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
# 0.6.0
|
||||
# 0.5.4
|
||||
|
||||
* **Breaking** Changed `UUID` field that was trimmed to 32 chars (without dashes) instead of 36 (with dashes)
|
||||
to more in line with other libraries.
|
||||
* Allow to pass `uuid_format` (allowed 'hex'(default) or 'string') to `UUID` field to change the format in which it's saved.
|
||||
By default field is saved in hex format (trimmed to 32 chars (without dashes)), but you can pass
|
||||
format='string' to use 36 (with dashes) instead to adjust to existing db or other libraries.
|
||||
Sample:
|
||||
hex value = c616ab438cce49dbbf4380d109251dce
|
||||
string value = c616ab43-8cce-49db-bf43-80d109251dce
|
||||
|
||||
# 0.5.3
|
||||
|
||||
|
||||
@ -318,6 +318,21 @@ class Decimal(ModelFieldFactory, decimal.Decimal):
|
||||
class UUID(ModelFieldFactory, uuid.UUID):
|
||||
_type = uuid.UUID
|
||||
|
||||
def __new__( # type: ignore # noqa CFQ002
|
||||
cls, *, uuid_format: str = "hex", **kwargs: Any
|
||||
) -> Type[BaseField]:
|
||||
kwargs = {
|
||||
**kwargs,
|
||||
**{
|
||||
k: v
|
||||
for k, v in locals().items()
|
||||
if k not in ["cls", "__class__", "kwargs"]
|
||||
},
|
||||
}
|
||||
|
||||
return super().__new__(cls, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_column_type(cls, **kwargs: Any) -> Any:
|
||||
return sqlalchemy_uuid.UUID()
|
||||
uuid_format = kwargs.get("uuid_format", "hex")
|
||||
return sqlalchemy_uuid.UUID(uuid_format=uuid_format)
|
||||
|
||||
@ -15,6 +15,10 @@ class UUID(TypeDecorator): # pragma nocover
|
||||
|
||||
impl = CHAR
|
||||
|
||||
def __init__(self, *args: Any, uuid_format: str = "hex", **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.uuid_format = uuid_format
|
||||
|
||||
def _cast_to_uuid(self, value: Union[str, int, bytes]) -> uuid.UUID:
|
||||
if not isinstance(value, uuid.UUID):
|
||||
if isinstance(value, bytes):
|
||||
@ -28,7 +32,11 @@ class UUID(TypeDecorator): # pragma nocover
|
||||
return ret_value
|
||||
|
||||
def load_dialect_impl(self, dialect: DefaultDialect) -> Any:
|
||||
return dialect.type_descriptor(CHAR(36))
|
||||
return (
|
||||
dialect.type_descriptor(CHAR(36))
|
||||
if self.uuid_format == "string"
|
||||
else dialect.type_descriptor(CHAR(32))
|
||||
)
|
||||
|
||||
def process_bind_param(
|
||||
self, value: Union[str, int, bytes, uuid.UUID, None], dialect: DefaultDialect
|
||||
@ -37,7 +45,7 @@ class UUID(TypeDecorator): # pragma nocover
|
||||
return value
|
||||
if not isinstance(value, uuid.UUID):
|
||||
value = self._cast_to_uuid(value)
|
||||
return str(value)
|
||||
return str(value) if self.uuid_format == "string" else "%.32x" % value.int
|
||||
|
||||
def process_result_value(
|
||||
self, value: Optional[str], dialect: DefaultDialect
|
||||
|
||||
@ -36,6 +36,16 @@ class UUIDSample(ormar.Model):
|
||||
test_text: str = ormar.Text()
|
||||
|
||||
|
||||
class UUIDSample2(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "uuids2"
|
||||
metadata = metadata
|
||||
database = database
|
||||
|
||||
id: uuid.UUID = ormar.UUID(primary_key=True, default=uuid.uuid4, uuid_format='string')
|
||||
test_text: str = ormar.Text()
|
||||
|
||||
|
||||
class User(ormar.Model):
|
||||
class Meta:
|
||||
tablename = "users"
|
||||
@ -150,6 +160,14 @@ async def test_uuid_column():
|
||||
assert item2.id == item3.id
|
||||
assert isinstance(item3.id, uuid.UUID)
|
||||
|
||||
u3 = await UUIDSample2(**u1.dict()).save()
|
||||
|
||||
u1_2 = await UUIDSample.objects.get(pk=u3.id)
|
||||
assert u1_2 == u1
|
||||
|
||||
u4 = await UUIDSample2.objects.get(pk=u3.id)
|
||||
assert u3 == u4
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_crud():
|
||||
@ -303,7 +321,7 @@ async def test_model_limit_with_filter():
|
||||
await User.objects.create(name="Tom")
|
||||
|
||||
assert (
|
||||
len(await User.objects.limit(2).filter(name__iexact="Tom").all()) == 2
|
||||
len(await User.objects.limit(2).filter(name__iexact="Tom").all()) == 2
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user