apis-data-projection 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apis_data_projection-0.1.0/.github/workflows/publish.yml +51 -0
- apis_data_projection-0.1.0/.gitignore +79 -0
- apis_data_projection-0.1.0/.python-version +1 -0
- apis_data_projection-0.1.0/LICENSE +21 -0
- apis_data_projection-0.1.0/PKG-INFO +27 -0
- apis_data_projection-0.1.0/README.md +11 -0
- apis_data_projection-0.1.0/apis_data_projection/__init__.py +0 -0
- apis_data_projection-0.1.0/apis_data_projection/admin.py +43 -0
- apis_data_projection-0.1.0/apis_data_projection/apps.py +7 -0
- apis_data_projection-0.1.0/apis_data_projection/checks.py +47 -0
- apis_data_projection-0.1.0/apis_data_projection/config.py +4 -0
- apis_data_projection-0.1.0/apis_data_projection/management/commands/rebuild_projections.py +16 -0
- apis_data_projection-0.1.0/apis_data_projection/migrations/0001_initial.py +311 -0
- apis_data_projection-0.1.0/apis_data_projection/migrations/__init__.py +0 -0
- apis_data_projection-0.1.0/apis_data_projection/models.py +184 -0
- apis_data_projection-0.1.0/apis_data_projection/projection_sync.py +867 -0
- apis_data_projection-0.1.0/apis_data_projection/templates/admin/apis_data_projection/change_list.html +10 -0
- apis_data_projection-0.1.0/manage.py +16 -0
- apis_data_projection-0.1.0/pyproject.toml +21 -0
- apis_data_projection-0.1.0/sample_project/migrations/0001_initial.py +341 -0
- apis_data_projection-0.1.0/sample_project/migrations/__init__.py +0 -0
- apis_data_projection-0.1.0/sample_project/models.py +95 -0
- apis_data_projection-0.1.0/sample_project/settings.py +18 -0
- apis_data_projection-0.1.0/sample_project/urls.py +3 -0
- apis_data_projection-0.1.0/uv.lock +1210 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
build:
|
|
8
|
+
name: Build distribution
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
with:
|
|
13
|
+
persist-credentials: false
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.x"
|
|
18
|
+
- name: Install pypa/build
|
|
19
|
+
run: >-
|
|
20
|
+
python3 -m
|
|
21
|
+
pip install
|
|
22
|
+
build
|
|
23
|
+
--user
|
|
24
|
+
- name: Build a binary wheel and a source tarball
|
|
25
|
+
run: python3 -m build
|
|
26
|
+
- name: Store the distribution packages
|
|
27
|
+
uses: actions/upload-artifact@v4
|
|
28
|
+
with:
|
|
29
|
+
name: python-package-distributions
|
|
30
|
+
path: dist/
|
|
31
|
+
|
|
32
|
+
publish-to-pypi:
|
|
33
|
+
name: >-
|
|
34
|
+
Publish Python distribution to PyPI
|
|
35
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
36
|
+
needs:
|
|
37
|
+
- build
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
environment:
|
|
40
|
+
name: pypi
|
|
41
|
+
url: https://pypi.org/project/apis-data-projection/
|
|
42
|
+
permissions:
|
|
43
|
+
id-token: write
|
|
44
|
+
steps:
|
|
45
|
+
- name: Download all the dists
|
|
46
|
+
uses: actions/download-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: python-package-distributions
|
|
49
|
+
path: dist/
|
|
50
|
+
- name: Publish distribution to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
*.pyo
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
wheels/
|
|
8
|
+
*.egg-info
|
|
9
|
+
*.egg
|
|
10
|
+
.eggs/
|
|
11
|
+
MANIFEST
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
ENV/
|
|
18
|
+
.env
|
|
19
|
+
|
|
20
|
+
# Environment variables
|
|
21
|
+
.env.local
|
|
22
|
+
.env.*.local
|
|
23
|
+
|
|
24
|
+
# Distribution / packaging
|
|
25
|
+
*.tar.gz
|
|
26
|
+
*.whl
|
|
27
|
+
|
|
28
|
+
# Testing
|
|
29
|
+
.tox/
|
|
30
|
+
.nox/
|
|
31
|
+
.coverage
|
|
32
|
+
.coverage.*
|
|
33
|
+
coverage.xml
|
|
34
|
+
htmlcov/
|
|
35
|
+
.pytest_cache/
|
|
36
|
+
.hypothesis/
|
|
37
|
+
|
|
38
|
+
# Type checking
|
|
39
|
+
.mypy_cache/
|
|
40
|
+
.dmypy.json
|
|
41
|
+
.pytype/
|
|
42
|
+
.pyre/
|
|
43
|
+
|
|
44
|
+
# Linting / formatting
|
|
45
|
+
.ruff_cache/
|
|
46
|
+
|
|
47
|
+
# Django
|
|
48
|
+
*.log
|
|
49
|
+
local_settings.py
|
|
50
|
+
db.sqlite3
|
|
51
|
+
db.sqlite3-journal
|
|
52
|
+
media/
|
|
53
|
+
staticfiles/
|
|
54
|
+
static/
|
|
55
|
+
|
|
56
|
+
# Django migrations (optional — remove if you want to track migrations)
|
|
57
|
+
# */migrations/*.py
|
|
58
|
+
# !*/migrations/__init__.py
|
|
59
|
+
|
|
60
|
+
# Celery
|
|
61
|
+
celerybeat-schedule
|
|
62
|
+
celerybeat.pid
|
|
63
|
+
|
|
64
|
+
# IDE / editors
|
|
65
|
+
.idea/
|
|
66
|
+
.vscode/
|
|
67
|
+
*.swp
|
|
68
|
+
*.swo
|
|
69
|
+
*~
|
|
70
|
+
.DS_Store
|
|
71
|
+
|
|
72
|
+
# Jupyter Notebooks
|
|
73
|
+
.ipynb_checkpoints/
|
|
74
|
+
*.ipynb
|
|
75
|
+
|
|
76
|
+
# uv / pip
|
|
77
|
+
pip-log.txt
|
|
78
|
+
pip-delete-this-directory.txt
|
|
79
|
+
.uv/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Saranya Balasubramanian
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apis-data-projection
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Data projection layer for APIS
|
|
5
|
+
Project-URL: Homepage, https://github.com/gythaogg/apis-data-projection
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: data projection
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.13
|
|
13
|
+
Requires-Dist: apis-acdhch-default-settings>=2.20.0
|
|
14
|
+
Requires-Dist: apis-core-rdf>=0.64.5
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# apis-data-projection
|
|
18
|
+
|
|
19
|
+
## Aim
|
|
20
|
+
This package creates projections of APIS data models in order to
|
|
21
|
+
- support fast universal search over entities and relations
|
|
22
|
+
- create relation aware representation of entities. For eg. if there is "AA lives in XX relationship" then the representation of AA will contain "lives in XX" and the representation of XX will contain "residence of AA"
|
|
23
|
+
- to support faceting and filtering by datetime
|
|
24
|
+
- to provide an efficient relation layer for graph representations
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# apis-data-projection
|
|
2
|
+
|
|
3
|
+
## Aim
|
|
4
|
+
This package creates projections of APIS data models in order to
|
|
5
|
+
- support fast universal search over entities and relations
|
|
6
|
+
- create relation aware representation of entities. For eg. if there is "AA lives in XX relationship" then the representation of AA will contain "lives in XX" and the representation of XX will contain "residence of AA"
|
|
7
|
+
- to support faceting and filtering by datetime
|
|
8
|
+
- to provide an efficient relation layer for graph representations
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from apis_data_projection.models import RelationProjection, EntityProjection, EntityFacet
|
|
2
|
+
from django.contrib import admin, messages
|
|
3
|
+
from django.http import HttpResponseRedirect
|
|
4
|
+
from django.urls import path
|
|
5
|
+
from django.template.response import TemplateResponse
|
|
6
|
+
|
|
7
|
+
from .models import EntityProjection
|
|
8
|
+
from .projection_sync import ProjectionSyncService
|
|
9
|
+
from apis_core.entities.abc import Entity
|
|
10
|
+
from apis_core.relations.models import Relation
|
|
11
|
+
|
|
12
|
+
@admin.register(RelationProjection)
|
|
13
|
+
class RelationProjectionAdmin(admin.ModelAdmin):
|
|
14
|
+
list_display = tuple(field.name for field in RelationProjection._meta.fields)
|
|
15
|
+
|
|
16
|
+
@admin.register(EntityFacet)
|
|
17
|
+
class EntityFacetAdmin(admin.ModelAdmin):
|
|
18
|
+
list_display = tuple(field.name for field in EntityFacet._meta.fields)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@admin.register(EntityProjection)
|
|
22
|
+
class EntityProjectionAdmin(admin.ModelAdmin):
|
|
23
|
+
list_display = [field.name for field in EntityProjection._meta.fields]
|
|
24
|
+
|
|
25
|
+
def get_urls(self):
|
|
26
|
+
urls = super().get_urls()
|
|
27
|
+
custom_urls = [
|
|
28
|
+
path(
|
|
29
|
+
"rebuild-projections/",
|
|
30
|
+
self.admin_site.admin_view(self.rebuild_projections_view),
|
|
31
|
+
name="apis_data_projection_rebuild_projections",
|
|
32
|
+
),
|
|
33
|
+
]
|
|
34
|
+
return custom_urls + urls
|
|
35
|
+
|
|
36
|
+
def rebuild_projections_view(self, request):
|
|
37
|
+
service = ProjectionSyncService(
|
|
38
|
+
abstract_entity_model=Entity,
|
|
39
|
+
relation_model=Relation,
|
|
40
|
+
)
|
|
41
|
+
service.sync_all()
|
|
42
|
+
self.message_user(request, "Projection rebuild completed.", level=messages.SUCCESS)
|
|
43
|
+
return HttpResponseRedirect("../")
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.core.checks import Error, Warning, register
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _has_attr(model, attr_name: str) -> bool:
|
|
8
|
+
try:
|
|
9
|
+
model._meta.get_field(attr_name)
|
|
10
|
+
return True
|
|
11
|
+
except Exception:
|
|
12
|
+
return hasattr(model, attr_name)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@register()
|
|
16
|
+
def apis_data_projection_checks(app_configs, **kwargs):
|
|
17
|
+
errors = []
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from apis_core.entities.abc import Entity
|
|
21
|
+
except Exception as exc:
|
|
22
|
+
errors.append(
|
|
23
|
+
Error(
|
|
24
|
+
"apis_core.entities.abc.Entity could not be imported.",
|
|
25
|
+
hint="Install and configure apis_core before using apis_data_projection.",
|
|
26
|
+
id="apis_data_projection.E001",
|
|
27
|
+
obj=exc,
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
Entity = None
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
from apis_core.relations import Relation
|
|
34
|
+
except Exception as exc:
|
|
35
|
+
errors.append(
|
|
36
|
+
Error(
|
|
37
|
+
"apis_core.relations.Relation could not be imported.",
|
|
38
|
+
hint="Install and configure apis_core before using apis_data_projection.",
|
|
39
|
+
id="apis_data_projection.E002",
|
|
40
|
+
obj=exc,
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
Relation = None
|
|
44
|
+
|
|
45
|
+
if Entity is None or Relation is None:
|
|
46
|
+
return errors
|
|
47
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from django.core.management.base import BaseCommand
|
|
2
|
+
|
|
3
|
+
from apis_data_projection.projection_sync import ProjectionSyncService
|
|
4
|
+
from apis_core.entities.abc import Entity
|
|
5
|
+
from apis_core.relations.models import Relation
|
|
6
|
+
|
|
7
|
+
class Command(BaseCommand):
|
|
8
|
+
help = "Rebuild entity and relation projections."
|
|
9
|
+
|
|
10
|
+
def handle(self, *args, **options):
|
|
11
|
+
service = ProjectionSyncService(
|
|
12
|
+
abstract_entity_model=Entity,
|
|
13
|
+
relation_model=Relation,
|
|
14
|
+
)
|
|
15
|
+
service.sync_all()
|
|
16
|
+
self.stdout.write(self.style.SUCCESS("Projection rebuild completed."))
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Generated by Django 6.0.6 on 2026-06-19 09:38
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
initial = True
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
("contenttypes", "0002_remove_content_type_name"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name="EntityProjection",
|
|
18
|
+
fields=[
|
|
19
|
+
(
|
|
20
|
+
"id",
|
|
21
|
+
models.BigAutoField(
|
|
22
|
+
auto_created=True,
|
|
23
|
+
primary_key=True,
|
|
24
|
+
serialize=False,
|
|
25
|
+
verbose_name="ID",
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
("source_object_id", models.PositiveIntegerField()),
|
|
29
|
+
(
|
|
30
|
+
"entity_type",
|
|
31
|
+
models.CharField(
|
|
32
|
+
db_index=True,
|
|
33
|
+
help_text="Entity class name, e.g. Person, Place, Group.",
|
|
34
|
+
max_length=100,
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
("label", models.CharField(db_index=True, max_length=255)),
|
|
38
|
+
("uri", models.CharField(blank=True, max_length=500)),
|
|
39
|
+
("search_text", models.TextField(blank=True)),
|
|
40
|
+
("start_date", models.DateField(blank=True, null=True)),
|
|
41
|
+
("end_date", models.DateField(blank=True, null=True)),
|
|
42
|
+
(
|
|
43
|
+
"properties_json",
|
|
44
|
+
models.JSONField(
|
|
45
|
+
blank=True,
|
|
46
|
+
default=dict,
|
|
47
|
+
help_text="dict representation of the entity's properties.",
|
|
48
|
+
),
|
|
49
|
+
),
|
|
50
|
+
(
|
|
51
|
+
"relations_json",
|
|
52
|
+
models.JSONField(
|
|
53
|
+
blank=True,
|
|
54
|
+
default=dict,
|
|
55
|
+
help_text="dict representation of the entity's relations.",
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
59
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
|
60
|
+
(
|
|
61
|
+
"source_content_type",
|
|
62
|
+
models.ForeignKey(
|
|
63
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
64
|
+
related_name="apis_data_projection_entity_projections",
|
|
65
|
+
to="contenttypes.contenttype",
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
],
|
|
69
|
+
options={
|
|
70
|
+
"ordering": ["label"],
|
|
71
|
+
},
|
|
72
|
+
),
|
|
73
|
+
migrations.CreateModel(
|
|
74
|
+
name="EntityFacet",
|
|
75
|
+
fields=[
|
|
76
|
+
(
|
|
77
|
+
"id",
|
|
78
|
+
models.BigAutoField(
|
|
79
|
+
auto_created=True,
|
|
80
|
+
primary_key=True,
|
|
81
|
+
serialize=False,
|
|
82
|
+
verbose_name="ID",
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
(
|
|
86
|
+
"name",
|
|
87
|
+
models.CharField(
|
|
88
|
+
db_index=True,
|
|
89
|
+
help_text="Facet key, e.g. profession, gender, works in, place of residence.",
|
|
90
|
+
max_length=100,
|
|
91
|
+
),
|
|
92
|
+
),
|
|
93
|
+
(
|
|
94
|
+
"value",
|
|
95
|
+
models.CharField(
|
|
96
|
+
db_index=True,
|
|
97
|
+
help_text="Facet display value, e.g. Wizard, male, Ankh Morpork.",
|
|
98
|
+
max_length=255,
|
|
99
|
+
),
|
|
100
|
+
),
|
|
101
|
+
(
|
|
102
|
+
"source",
|
|
103
|
+
models.CharField(
|
|
104
|
+
blank=True,
|
|
105
|
+
help_text="Optional origin, e.g. profession, gender, relation:works in.",
|
|
106
|
+
max_length=255,
|
|
107
|
+
),
|
|
108
|
+
),
|
|
109
|
+
(
|
|
110
|
+
"kind",
|
|
111
|
+
models.CharField(
|
|
112
|
+
blank=True,
|
|
113
|
+
help_text="Optional classifier, e.g. scalar, fk, m2m, relation-derived.",
|
|
114
|
+
max_length=30,
|
|
115
|
+
),
|
|
116
|
+
),
|
|
117
|
+
(
|
|
118
|
+
"weight",
|
|
119
|
+
models.DecimalField(
|
|
120
|
+
blank=True, decimal_places=2, max_digits=6, null=True
|
|
121
|
+
),
|
|
122
|
+
),
|
|
123
|
+
(
|
|
124
|
+
"extra",
|
|
125
|
+
models.JSONField(
|
|
126
|
+
blank=True,
|
|
127
|
+
default=dict,
|
|
128
|
+
help_text="Optional extra facet metadata",
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
132
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
|
133
|
+
(
|
|
134
|
+
"entity_projection_id",
|
|
135
|
+
models.ForeignKey(
|
|
136
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
137
|
+
related_name="facets",
|
|
138
|
+
to="apis_data_projection.entityprojection",
|
|
139
|
+
),
|
|
140
|
+
),
|
|
141
|
+
],
|
|
142
|
+
options={
|
|
143
|
+
"ordering": ["name", "value"],
|
|
144
|
+
},
|
|
145
|
+
),
|
|
146
|
+
migrations.CreateModel(
|
|
147
|
+
name="RelationProjection",
|
|
148
|
+
fields=[
|
|
149
|
+
(
|
|
150
|
+
"id",
|
|
151
|
+
models.BigAutoField(
|
|
152
|
+
auto_created=True,
|
|
153
|
+
primary_key=True,
|
|
154
|
+
serialize=False,
|
|
155
|
+
verbose_name="ID",
|
|
156
|
+
),
|
|
157
|
+
),
|
|
158
|
+
("source_relation_object_id", models.PositiveIntegerField()),
|
|
159
|
+
("subj_object_id", models.PositiveIntegerField()),
|
|
160
|
+
("obj_object_id", models.PositiveIntegerField()),
|
|
161
|
+
("subj_label", models.CharField(blank=True, max_length=255)),
|
|
162
|
+
("obj_label", models.CharField(blank=True, max_length=255)),
|
|
163
|
+
("subj_entity_type", models.CharField(db_index=True, max_length=100)),
|
|
164
|
+
("obj_entity_type", models.CharField(db_index=True, max_length=100)),
|
|
165
|
+
(
|
|
166
|
+
"relation_type",
|
|
167
|
+
models.CharField(
|
|
168
|
+
db_index=True, help_text="Relation class name", max_length=100
|
|
169
|
+
),
|
|
170
|
+
),
|
|
171
|
+
("forward_label", models.CharField(db_index=True, max_length=255)),
|
|
172
|
+
(
|
|
173
|
+
"reverse_label",
|
|
174
|
+
models.CharField(blank=True, db_index=True, max_length=255),
|
|
175
|
+
),
|
|
176
|
+
("search_text", models.TextField(blank=True)),
|
|
177
|
+
("start_date", models.DateField(blank=True, null=True)),
|
|
178
|
+
("end_date", models.DateField(blank=True, null=True)),
|
|
179
|
+
(
|
|
180
|
+
"properties_json",
|
|
181
|
+
models.JSONField(
|
|
182
|
+
blank=True,
|
|
183
|
+
default=dict,
|
|
184
|
+
help_text="Optional extra relation metadata that is not a first-class column.",
|
|
185
|
+
),
|
|
186
|
+
),
|
|
187
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
188
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
|
189
|
+
(
|
|
190
|
+
"obj_content_type",
|
|
191
|
+
models.ForeignKey(
|
|
192
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
193
|
+
related_name="apis_data_projection_relation_obj",
|
|
194
|
+
to="contenttypes.contenttype",
|
|
195
|
+
),
|
|
196
|
+
),
|
|
197
|
+
(
|
|
198
|
+
"source_relation_content_type",
|
|
199
|
+
models.ForeignKey(
|
|
200
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
201
|
+
related_name="apis_data_projection_relation_projections",
|
|
202
|
+
to="contenttypes.contenttype",
|
|
203
|
+
),
|
|
204
|
+
),
|
|
205
|
+
(
|
|
206
|
+
"subj_content_type",
|
|
207
|
+
models.ForeignKey(
|
|
208
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
209
|
+
related_name="apis_data_projection_relation_subj",
|
|
210
|
+
to="contenttypes.contenttype",
|
|
211
|
+
),
|
|
212
|
+
),
|
|
213
|
+
],
|
|
214
|
+
options={
|
|
215
|
+
"ordering": ["relation_type", "subj_label", "obj_label"],
|
|
216
|
+
},
|
|
217
|
+
),
|
|
218
|
+
migrations.AddIndex(
|
|
219
|
+
model_name="entityprojection",
|
|
220
|
+
index=models.Index(
|
|
221
|
+
fields=["source_content_type", "source_object_id"],
|
|
222
|
+
name="apis_data_p_source__ae8955_idx",
|
|
223
|
+
),
|
|
224
|
+
),
|
|
225
|
+
migrations.AddIndex(
|
|
226
|
+
model_name="entityprojection",
|
|
227
|
+
index=models.Index(
|
|
228
|
+
fields=["entity_type"], name="apis_data_p_entity__a87a6d_idx"
|
|
229
|
+
),
|
|
230
|
+
),
|
|
231
|
+
migrations.AddIndex(
|
|
232
|
+
model_name="entityprojection",
|
|
233
|
+
index=models.Index(fields=["label"], name="apis_data_p_label_493c50_idx"),
|
|
234
|
+
),
|
|
235
|
+
migrations.AddConstraint(
|
|
236
|
+
model_name="entityprojection",
|
|
237
|
+
constraint=models.UniqueConstraint(
|
|
238
|
+
fields=("source_content_type", "source_object_id"),
|
|
239
|
+
name="uniq_entity_projection_source",
|
|
240
|
+
),
|
|
241
|
+
),
|
|
242
|
+
migrations.AddIndex(
|
|
243
|
+
model_name="entityfacet",
|
|
244
|
+
index=models.Index(
|
|
245
|
+
fields=["entity_projection_id"], name="apis_data_p_entity__3eec92_idx"
|
|
246
|
+
),
|
|
247
|
+
),
|
|
248
|
+
migrations.AddIndex(
|
|
249
|
+
model_name="entityfacet",
|
|
250
|
+
index=models.Index(
|
|
251
|
+
fields=["name", "value"], name="apis_data_p_name_a349f0_idx"
|
|
252
|
+
),
|
|
253
|
+
),
|
|
254
|
+
migrations.AddIndex(
|
|
255
|
+
model_name="entityfacet",
|
|
256
|
+
index=models.Index(fields=["name"], name="apis_data_p_name_bd2449_idx"),
|
|
257
|
+
),
|
|
258
|
+
migrations.AddConstraint(
|
|
259
|
+
model_name="entityfacet",
|
|
260
|
+
constraint=models.UniqueConstraint(
|
|
261
|
+
fields=("entity_projection_id", "name", "value"),
|
|
262
|
+
name="uniq_entity_facet_per_projection",
|
|
263
|
+
),
|
|
264
|
+
),
|
|
265
|
+
migrations.AddIndex(
|
|
266
|
+
model_name="relationprojection",
|
|
267
|
+
index=models.Index(
|
|
268
|
+
fields=["source_relation_content_type", "source_relation_object_id"],
|
|
269
|
+
name="apis_data_p_source__2a9bae_idx",
|
|
270
|
+
),
|
|
271
|
+
),
|
|
272
|
+
migrations.AddIndex(
|
|
273
|
+
model_name="relationprojection",
|
|
274
|
+
index=models.Index(
|
|
275
|
+
fields=["subj_content_type", "subj_object_id"],
|
|
276
|
+
name="apis_data_p_subj_co_0bd7df_idx",
|
|
277
|
+
),
|
|
278
|
+
),
|
|
279
|
+
migrations.AddIndex(
|
|
280
|
+
model_name="relationprojection",
|
|
281
|
+
index=models.Index(
|
|
282
|
+
fields=["obj_content_type", "obj_object_id"],
|
|
283
|
+
name="apis_data_p_obj_con_255e1e_idx",
|
|
284
|
+
),
|
|
285
|
+
),
|
|
286
|
+
migrations.AddIndex(
|
|
287
|
+
model_name="relationprojection",
|
|
288
|
+
index=models.Index(
|
|
289
|
+
fields=["relation_type"], name="apis_data_p_relatio_ede626_idx"
|
|
290
|
+
),
|
|
291
|
+
),
|
|
292
|
+
migrations.AddIndex(
|
|
293
|
+
model_name="relationprojection",
|
|
294
|
+
index=models.Index(
|
|
295
|
+
fields=["forward_label"], name="apis_data_p_forward_384d6d_idx"
|
|
296
|
+
),
|
|
297
|
+
),
|
|
298
|
+
migrations.AddIndex(
|
|
299
|
+
model_name="relationprojection",
|
|
300
|
+
index=models.Index(
|
|
301
|
+
fields=["reverse_label"], name="apis_data_p_reverse_5ef6f2_idx"
|
|
302
|
+
),
|
|
303
|
+
),
|
|
304
|
+
migrations.AddConstraint(
|
|
305
|
+
model_name="relationprojection",
|
|
306
|
+
constraint=models.UniqueConstraint(
|
|
307
|
+
fields=("source_relation_content_type", "source_relation_object_id"),
|
|
308
|
+
name="uniq_relation_projection_source",
|
|
309
|
+
),
|
|
310
|
+
),
|
|
311
|
+
]
|
|
File without changes
|