-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
relations: add relations-ng to 0.17.3
- Loading branch information
Showing
20 changed files
with
788 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.contrib import admin | ||
|
||
from .models import Relation | ||
|
||
admin.site.register(Relation) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class ApisRelations2Config(AppConfig): | ||
default_auto_field = "django.db.models.AutoField" | ||
name = "apis_core.relations" | ||
|
||
def ready(self): | ||
from . import signals |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
from django.forms import ModelForm | ||
from django.urls import reverse | ||
from django.shortcuts import get_object_or_404 | ||
from django.contrib.contenttypes.models import ContentType | ||
|
||
|
||
from crispy_forms.layout import Submit, Layout, Div, HTML | ||
from crispy_forms.helper import FormHelper | ||
|
||
|
||
class RelationForm(ModelForm): | ||
def __init__( | ||
self, | ||
frominstance=None, | ||
tocontenttype=None, | ||
inverted=False, | ||
embedded=True, | ||
*args, | ||
**kwargs, | ||
): | ||
super().__init__(*args, **kwargs) | ||
|
||
subj, obj = "subj", "obj" | ||
if inverted: | ||
subj = "obj" | ||
obj = "subj" | ||
|
||
if frominstance: | ||
self.fields[subj].disabled = True | ||
self.fields[subj].initial = frominstance | ||
self.fields[subj].label = ContentType.objects.get_for_model( | ||
frominstance | ||
).name | ||
|
||
if tocontenttype: | ||
self.fields[obj].queryset = tocontenttype.model_class().objects.all() | ||
self.fields[obj].label = tocontenttype.name | ||
|
||
self.helper = FormHelper(self) | ||
|
||
relcontenttype = ContentType.objects.get_for_model(self._meta.model) | ||
|
||
args = [ | ||
relcontenttype.pk, | ||
] | ||
if frominstance: | ||
args.append(ContentType.objects.get_for_model(frominstance).pk) | ||
args.append(frominstance.pk) | ||
if tocontenttype: | ||
args.append(tocontenttype.pk) | ||
hx_post = reverse("apis:relation", args=args) | ||
if inverted: | ||
hx_post = reverse("apis:relationinverted", args=args) | ||
|
||
hx_post += "?partial" | ||
|
||
if embedded: | ||
self.helper.attrs = { | ||
"hx-post": hx_post, | ||
"hx-swap": "outerHTML", | ||
} | ||
|
||
# layout stuff: | ||
div = Div( | ||
Div("subj", css_class="col-md-6"), | ||
Div("obj", css_class="col-md-6"), | ||
css_class="row", | ||
) | ||
if inverted: | ||
div = Div( | ||
Div("obj", css_class="col-md-6"), | ||
Div("subj", css_class="col-md-6"), | ||
css_class="row", | ||
) | ||
|
||
# we have to explicetly add the rest of the fields | ||
fields = {k: v for k, v in self.fields.items() if k not in ["obj", "subj"]} | ||
|
||
self.helper.layout = Layout( | ||
HTML(f"<h3>{self._meta.model.__name__}</h3>"), | ||
div, | ||
*fields, | ||
) | ||
self.helper.add_input(Submit("submit", "Submit", css_class="btn-primary")) |
10 changes: 10 additions & 0 deletions
10
apis_core/relations/management/commands/converttemptriples.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from django.core.management.base import BaseCommand | ||
from apis_core.apis_relations.models import TempTriple | ||
|
||
|
||
class Command(BaseCommand): | ||
help = "Create relations based on all existing TempTriples" | ||
|
||
def handle(self, *args, **options): | ||
for tt in TempTriple.objects.all(): | ||
tt.save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Generated by Django 4.1.13 on 2023-12-18 06:09 | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
("apis_metainfo", "0006_delete_text"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="Relation", | ||
fields=[ | ||
( | ||
"id", | ||
models.AutoField( | ||
auto_created=True, | ||
primary_key=True, | ||
serialize=False, | ||
verbose_name="ID", | ||
), | ||
), | ||
( | ||
"obj", | ||
models.ForeignKey( | ||
null=True, | ||
on_delete=django.db.models.deletion.SET_NULL, | ||
related_name="relations_as_obj", | ||
to="apis_metainfo.rootobject", | ||
), | ||
), | ||
( | ||
"subj", | ||
models.ForeignKey( | ||
null=True, | ||
on_delete=django.db.models.deletion.SET_NULL, | ||
related_name="relations_as_subj", | ||
to="apis_metainfo.rootobject", | ||
), | ||
), | ||
], | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
from apis_core.apis_metainfo.models import RootObject | ||
from django.db import models | ||
from django.db.models.base import ModelBase | ||
from django.core.exceptions import ValidationError | ||
from model_utils.managers import InheritanceManager | ||
|
||
|
||
# This ModelBase is simply there to check if the needed attributes | ||
# are set in the Relation child classes. | ||
class RelationModelBase(ModelBase): | ||
def __new__(metacls, name, bases, attrs): | ||
if name == "Relation": | ||
return super().__new__(metacls, name, bases, attrs) | ||
else: | ||
new_class = super().__new__(metacls, name, bases, attrs) | ||
if not hasattr(new_class, "subj_model"): | ||
raise ValueError( | ||
"%s inherits from Relation and must therefore specify subj_model" | ||
% name | ||
) | ||
if not hasattr(new_class, "obj_model"): | ||
raise ValueError( | ||
"%s inherits from Relation and must therefore specify obj_model" | ||
% name | ||
) | ||
|
||
return new_class | ||
|
||
|
||
class Relation(models.Model, metaclass=RelationModelBase): | ||
subj = models.ForeignKey( | ||
RootObject, | ||
on_delete=models.SET_NULL, | ||
null=True, | ||
related_name="relations_as_subj", | ||
) | ||
obj = models.ForeignKey( | ||
RootObject, | ||
on_delete=models.SET_NULL, | ||
null=True, | ||
related_name="relations_as_obj", | ||
) | ||
|
||
objects = InheritanceManager() | ||
|
||
def save(self, *args, **kwargs): | ||
if self.subj: | ||
subj = RootObject.objects_inheritance.get_subclass(id=self.subj.id) | ||
if not type(subj) in self.subj_list(): | ||
raise ValidationError( | ||
f"{self.subj} is not of any type in {self.subj_model}" | ||
) | ||
if self.obj: | ||
obj = RootObject.objects_inheritance.get_subclass(id=self.obj.id) | ||
if not type(obj) in self.obj_list(): | ||
raise ValidationError( | ||
f"{self.obj} is not of any type in {self.obj_model}" | ||
) | ||
super().save(*args, **kwargs) | ||
|
||
@property | ||
def subj_to_obj_text(self): | ||
if hasattr(self, "name"): | ||
return f"{self.subj} {self.name} {self.obj}" | ||
return f"{self.subj} relation to {self.obj}" | ||
|
||
@property | ||
def obj_to_subj_text(self): | ||
if hasattr(self, "reverse_name"): | ||
return f"{self.subj} {self.reverse_name} {self.obj}" | ||
return f"{self.obj} relation to {self.subj}" | ||
|
||
def __str__(self): | ||
return self.subj_to_obj_text | ||
|
||
@classmethod | ||
def is_subj(cls, something): | ||
return something in cls.subj_list() | ||
|
||
@classmethod | ||
def is_obj(cls, something): | ||
return something in cls.obj_list() | ||
|
||
@classmethod | ||
def subj_list(cls): | ||
return cls.subj_model if isinstance(cls.subj_model, list) else [cls.subj_model] | ||
|
||
@classmethod | ||
def obj_list(cls): | ||
return cls.obj_model if isinstance(cls.obj_model, list) else [cls.obj_model] | ||
|
||
def clean(self): | ||
if self.subj: | ||
subj = RootObject.objects_inheritance.get_subclass(id=self.subj.id) | ||
if not type(subj) in self.subj_list(): | ||
raise ValidationError( | ||
f"{self.subj} is not of any type in {self.subj_model}" | ||
) | ||
if self.obj: | ||
obj = RootObject.objects_inheritance.get_subclass(id=self.obj.id) | ||
if not type(obj) in self.obj_list(): | ||
raise ValidationError( | ||
f"{self.obj} is not of any type in {self.obj_model}" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from django.db.models.signals import post_save | ||
from django.dispatch import receiver | ||
from apis_core.apis_relations.models import TempTriple | ||
from django.apps import apps | ||
|
||
|
||
def find_relationtype(tt: TempTriple): | ||
obj_model = type(tt.obj) | ||
subj_model = type(tt.subj) | ||
name = tt.prop.name_forward | ||
reverse = tt.prop.name_reverse | ||
for model in apps.get_models(): | ||
if ( | ||
getattr(model, "obj_model", None) == obj_model | ||
and getattr(model, "subj_model", None) == subj_model | ||
and getattr(model, "temptriple_name", None) == name | ||
and getattr(model, "temptriple_name_reverse", None) == reverse | ||
): | ||
print(f"TempTriple {tt.pk} matches with {model}") | ||
return model | ||
print("Found none.") | ||
return None | ||
|
||
|
||
# this function is a helper function that adds a relation for every legacy temptriple that is created or updated | ||
@receiver(post_save, sender=TempTriple) | ||
def addrelation(sender, instance, created, **kwargs): | ||
model = find_relationtype(instance) | ||
if model is not None: | ||
rel, created = model.objects.get_or_create( | ||
subj=instance.subj, obj=instance.obj, metadata={"temptriple": instance.pk} | ||
) | ||
for field in getattr(model, "temptriple_field_list", []): | ||
setattr(rel, field, getattr(instance, field, None)) | ||
for field, newfield in getattr(model, "temptriple_field_mapping", {}).items(): | ||
setattr(rel, newfield, getattr(instance, field, None)) | ||
rel.save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
tr.htmx-swapping td { | ||
opacity: 0; | ||
transition: opacity 1s ease-out; | ||
color: red; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import django_tables2 as tables | ||
|
||
from django.contrib.contenttypes.models import ContentType | ||
|
||
from .models import Relation | ||
|
||
|
||
class RelationTable(tables.Table): | ||
|
||
id = tables.TemplateColumn( | ||
"<a href='{% url 'apis:relationupdate' record.id %}'>{{ record.id }}</a>" | ||
) | ||
|
||
description = tables.TemplateColumn("{{ record }}") | ||
edit = tables.TemplateColumn( | ||
"<a href='{% url 'apis:relationupdate' record.id %}'>Edit</a>" | ||
) | ||
delete = tables.TemplateColumn(template_name="tables/delete.html") | ||
|
||
class Meta: | ||
model = Relation | ||
fields = ["id", "description", "edit"] | ||
sequence = tuple(fields) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{% extends basetemplate %} | ||
{% load relations %} | ||
|
||
{% block content %} | ||
|
||
{% if model or object %} | ||
<h1 class="text-center">{{ model.name }}{{ object }}</h1> | ||
{% else %} | ||
{% relations_links %} | ||
{% endif %} | ||
|
||
{% if table %} | ||
{% load render_table from django_tables2 %} | ||
{% render_table table %} | ||
{% endif %} | ||
|
||
{% if form %} | ||
{{ form.errors }} | ||
{{ form.non_field_errors }} | ||
{% load crispy_forms_tags %} | ||
{% crispy form %} | ||
{% endif %} | ||
|
||
{% endblock content %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{% if table %} | ||
{% load render_table from django_tables2 %} | ||
{% render_table table %} | ||
{% endif %} | ||
|
||
{% if form %} | ||
{% load crispy_forms_tags %} | ||
{% crispy form %} | ||
{% endif %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<a href='{% url 'apis:relationdelete' record.id %}?next={{ request.GET.next|default:request.path }}' | ||
hx-delete='{% url 'apis:relationdelete' record.id %}?status_only' | ||
hx-target='closest tr' | ||
hx-confirm='Are your sure you want to delete {{ record }}?' | ||
hx-swap="outerHTML swap:1s">Delete</a> |
Oops, something went wrong.