Repository: vitalik/django-ninja

Issue:
0.15.0 Regression with `.` in `Field(alias)`
Howdy,

While trying to upgrade from 0.13.2 to 0.15.0, I've run into a problem with query params whose fields have a `.` in their alias. We have something that looks like this:

```python
class BaseListFilter(Schema):
    sort_by: str = Field('', alias='sort.by')
```

And it's being used like:

```python
@router.get('')
def list_things(request, filters: BaseListFilter = Query(...)):
    ...
```

And `filters` in `list_things` is no longer setting `filters.sort_by` correctly after the upgrade. This is happening for all fields that have a `.` in them.

I checked out the diff between 0.13.2 and 0.15.0 and if I was a gambling man, I would say the issue is happening [here](https://github.com/vitalik/django-ninja/compare/v0.13.2...v0.15.0#diff-9afd93779940ddf63af84fcc90b23b58e71de66386e66e45774cb49026adeff8L48-L51), but that is mostly a guess. 

Although we have the ability to change the data we are getting to stop using `.` in them, it would be an enormous amount of work and coordination. Got any workarounds?

Love the lib, keep up the great work.

Discussion:

Patch:
diff --git a/ninja/signature/details.py b/ninja/signature/details.py
index 6eec553..c9b2d1b 100644
--- a/ninja/signature/details.py
+++ b/ninja/signature/details.py
@@ -25,6 +25,10 @@ FuncParam = namedtuple(
 
 
 class ViewSignature:
+    FLATTEN_PATH_SEP = (
+        "\x1e"  # ASCII Record Separator.  IE: not generally used in query names
+    )
+
     def __init__(self, path: str, view_func: Callable) -> None:
         self.view_func = view_func
         self.signature = get_typed_signature(self.view_func)
@@ -157,7 +161,7 @@ class ViewSignature:
                         raise ConfigError(
                             f"Duplicated name: '{name}' in params: '{arg_names[name]}' & '{arg.name}'"
                         )
-                    flatten_map[name] = tuple(path.split("."))
+                    flatten_map[name] = tuple(path.split(self.FLATTEN_PATH_SEP))
                     arg_names[name] = arg.name
             else:
                 name = arg.alias
@@ -173,7 +177,7 @@ class ViewSignature:
     def _model_flatten_map(self, model: TModel, prefix: str) -> Generator:
         for field in model.__fields__.values():
             field_name = field.alias
-            name = f"{prefix}.{field_name}"
+            name = f"{prefix}{self.FLATTEN_PATH_SEP}{field_name}"
             if is_pydantic_model(field.type_):
                 yield from self._model_flatten_map(field.type_, name)
             else:


Test patch:
diff --git a/tests/main.py b/tests/main.py
index 63e2540..20a9cdb 100644
--- a/tests/main.py
+++ b/tests/main.py
@@ -2,7 +2,7 @@ from uuid import UUID
 
 from django.urls import register_converter
 
-from ninja import Path, Query, Router
+from ninja import Field, Path, Query, Router, Schema
 
 router = Router()
 
@@ -225,6 +225,15 @@ def get_query_param_required_type(request, query: int = Query(...)):
     return f"foo bar {query}"
 
 
+class AliasedSchema(Schema):
+    query: str = Field(..., alias="aliased.-_~name")
+
+
+@router.get("/query/aliased-name")
+def get_query_aliased_name(request, query: AliasedSchema = Query(...)):
+    return f"foo bar {query.query}"
+
+
 class CustomPathConverter1:
     regex = "[0-9]+"
 
diff --git a/tests/test_query.py b/tests/test_query.py
index b4f91e4..d3f1f30 100644
--- a/tests/test_query.py
+++ b/tests/test_query.py
@@ -54,6 +54,7 @@ client = TestClient(router)
         ("/query/param-required/int", 422, response_missing),
         ("/query/param-required/int?query=50", 200, "foo bar 50"),
         ("/query/param-required/int?query=foo", 422, response_not_valid_int),
+        ("/query/aliased-name?aliased.-_~name=foo", 200, "foo bar foo"),
     ],
 )
 def test_get_path(path, expected_status, expected_response):