Skip to content

Commit

Permalink
feat(apis_metainfo): replace Uri.root_object with GenericForeignKey
Browse files Browse the repository at this point in the history
The `Uri` should allow to point to any model instance, not only to models
that inherit from `RootObject`. Therefore we introduce a
GenericForeignKey. The migration copies the values of existing
`root_object` pointers to the generic foreign key. The `root_object`
field is then dropped from the model.
  • Loading branch information
b1rger committed Dec 20, 2024
1 parent 516b07c commit c9b050b
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 23 deletions.
3 changes: 0 additions & 3 deletions apis_core/apis_metainfo/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,3 @@

class UriFilterSet(GenericFilterSet):
uri = django_filters.CharFilter(lookup_expr="icontains")

class Meta(GenericFilterSet.Meta):
exclude = ["root_object"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 5.1.1 on 2024-11-29 08:31

import django.db.models.deletion
from django.db import migrations, models


def copy_root_object(apps, schema_editor):
Uri = apps.get_model("apis_metainfo", "Uri")
RootObject = apps.get_model("apis_metainfo", "RootObject")
for uri in Uri.objects.all():
if uri.root_object_id:
root_object = RootObject.objects.get(pk=uri.root_object_id)
uri.content_type_id = root_object.self_contenttype_id
uri.object_id = root_object.id
uri.save()


def reverse_copy_root_object(apps, schema_editor):
Uri = apps.get_model("apis_metainfo", "Uri")
for uri in Uri.objects.all():
if uri.content_type_id and uri.object_id:
uri.root_object_id = uri.object_id
uri.save()


class Migration(migrations.Migration):
dependencies = [
("apis_metainfo", "0014_remove_uri_domain_remove_uri_loaded_and_more"),
("contenttypes", "0002_remove_content_type_name"),
]

operations = [
migrations.AddField(
model_name="uri",
name="content_type",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="contenttypes.contenttype",
),
),
migrations.AddField(
model_name="uri",
name="object_id",
field=models.PositiveIntegerField(null=True),
),
migrations.RunPython(copy_root_object, reverse_copy_root_object),
migrations.RemoveField(model_name="uri", name="root_object"),
]
17 changes: 10 additions & 7 deletions apis_core/apis_metainfo/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from urllib.parse import urlsplit

from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db import models
Expand Down Expand Up @@ -66,9 +67,9 @@ def get_queryset(self):

class Uri(GenericModel, models.Model):
uri = models.URLField(blank=True, null=True, unique=True, max_length=255)
root_object = InheritanceForeignKey(
RootObject, blank=True, null=True, on_delete=models.CASCADE
)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True)
object_id = models.PositiveIntegerField(null=True)
content_object = GenericForeignKey()

objects = UriManager()

Expand All @@ -79,9 +80,9 @@ def get_web_object(self):
result = {
"relation_pk": self.pk,
"relation_type": "uri",
"related_root_object": self.root_object.name,
"related_root_object_url": self.root_object.get_absolute_url(),
"related_root_object_class_name": self.root_object.__class__.__name__.lower(),
"related_root_object": self.content_object.name,
"related_root_object_url": self.content_object.get_absolute_url(),
"related_root_object_class_name": self.content_object.__class__.__name__.lower(),
"uri": self.uri,
}
return result
Expand All @@ -92,7 +93,7 @@ def save(self, *args, **kwargs):

def clean(self):
self.uri = clean_uri(self.uri)
if self.uri and not hasattr(self, "root_object"):
if self.uri and not hasattr(self, "content_object"):
try:
definition, attributes = rdf.get_definition_and_attributes_from_uri(
self.uri
Expand All @@ -103,6 +104,8 @@ def clean(self):
obj = ct.model_class()(**attributes)
obj.save()
self.root_object = obj
self.content_type = ContentType.objects.get_for_model(obj)
self.object_id = obj.id
else:
raise ImproperlyConfigured(
f"{self.uri}: did not find matching rdf defintion"
Expand Down
17 changes: 5 additions & 12 deletions apis_core/apis_metainfo/tables.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import django_tables2 as tables
from django.db.models import F

from apis_core.generic.tables import GenericTable

Expand All @@ -8,22 +7,16 @@

class UriTable(GenericTable):
entity = tables.TemplateColumn(
"<a href='{{ record.root_object.get_absolute_url }}'>{{ record.root_object }}</a>",
orderable=True,
"<a href='{{ record.content_object.get_absolute_url }}'>{{ record.content_object }}</a>",
orderable=False,
verbose_name="related Entity",
)
ent_type = tables.TemplateColumn(
"{{ record.root_object.self_contenttype.model }}",
content_type = tables.TemplateColumn(
"{{ record.content_type.model }}",
verbose_name="Entity Type",
)

class Meta(GenericTable.Meta):
model = Uri
fields = ["id", "uri", "entity", "ent_type"]
fields = ["id", "uri", "entity", "content_type"]
exclude = ("desc",)

def order_ent_type(self, queryset, is_descending):
queryset = queryset.annotate(
ent_type=F("root_object__self_contenttype__model")
).order_by(("-" if is_descending else "") + "ent_type")
return (queryset, True)
5 changes: 4 additions & 1 deletion apis_core/apis_metainfo/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ def list(self, request):
uri = params.pop("uri", None)
if uri:
u = get_object_or_404(Uri, uri=request.query_params.get("uri"))
r = u.root_object.get_api_detail_endpoint()
if u.content_object:
r = u.content_object.get_api_detail_endpoint()
else:
r = u.root_object.get_api_detail_endpoint()
if params:
r += "?" + QueryDict.from_keys(params).urlencode()
return HttpResponseRedirect(r)
Expand Down

0 comments on commit c9b050b

Please sign in to comment.