Skip to content

Commit e71c794

Browse files
committed
[Fixes #11494] Implement relations between resources - fix formatting
1 parent 7006a1c commit e71c794

File tree

7 files changed

+91
-80
lines changed

7 files changed

+91
-80
lines changed

geonode/base/api/serializers.py

+13-12
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
SpatialRepresentationType,
5555
ThesaurusKeyword,
5656
ThesaurusKeywordLabel,
57-
ExtraMetadata, LinkedResource,
57+
ExtraMetadata,
58+
LinkedResource,
5859
)
5960
from geonode.documents.models import Document
6061
from geonode.geoapps.models import GeoApp
@@ -788,9 +789,7 @@ class Meta:
788789

789790

790791
class SimpleResourceSerializer(DynamicModelSerializer):
791-
warnings.warn('SimpleResourceSerializer is deprecated',
792-
DeprecationWarning,
793-
stacklevel=2)
792+
warnings.warn("SimpleResourceSerializer is deprecated", DeprecationWarning, stacklevel=2)
794793

795794
class Meta:
796795
name = "linked_resources"
@@ -808,7 +807,7 @@ def to_representation(self, instance: LinkedResource):
808807

809808

810809
class LinkedResourceSerializer(DynamicModelSerializer):
811-
def __init__(self, *kargs, serialize_source: bool = False, **kwargs):
810+
def __init__(self, *kargs, serialize_source: bool = False, **kwargs):
812811
super().__init__(*kargs, **kwargs)
813812
self.serialize_target = not serialize_source
814813

@@ -820,11 +819,13 @@ class Meta:
820819
def to_representation(self, instance: LinkedResource):
821820
data = super().to_representation(instance)
822821
item: ResourceBase = instance.target if self.serialize_target else instance.source
823-
data.update({
824-
"pk": item.pk,
825-
"title": item.title,
826-
"resource_type": item.resource_type,
827-
"detail_url": item.detail_url,
828-
"thumbnail_url": item.thumbnail_url,
829-
})
822+
data.update(
823+
{
824+
"pk": item.pk,
825+
"title": item.title,
826+
"resource_type": item.resource_type,
827+
"detail_url": item.detail_url,
828+
"thumbnail_url": item.thumbnail_url,
829+
}
830+
)
830831
return data

geonode/base/api/tests.py

+42-29
Original file line numberDiff line numberDiff line change
@@ -2625,14 +2625,19 @@ def test_linked_resource_for_document(self):
26252625
self.assertEqual(response.status_code, 200)
26262626
payload = response.json()
26272627
self.assert_linkedres_size(payload, "resources", 2)
2628-
self.assert_linkedres_contains(payload, "resources", (
2629-
{"pk":self.map.id, "title": ">>> " + self.map.title},
2630-
{"pk":self.dataset.id, "title": ">>> " + self.dataset.title})
2628+
self.assert_linkedres_contains(
2629+
payload,
2630+
"resources",
2631+
(
2632+
{"pk": self.map.id, "title": ">>> " + self.map.title},
2633+
{"pk": self.dataset.id, "title": ">>> " + self.dataset.title},
2634+
),
26312635
)
26322636
self.assert_linkedres_size(payload, "linked_to", 2)
2633-
self.assert_linkedres_contains(payload, "linked_to", (
2634-
{"pk":self.map.id, "title": self.map.title},
2635-
{"pk":self.dataset.id, "title": self.dataset.title})
2637+
self.assert_linkedres_contains(
2638+
payload,
2639+
"linked_to",
2640+
({"pk": self.map.id, "title": self.map.title}, {"pk": self.dataset.id, "title": self.dataset.title}),
26362641
)
26372642
self.assert_linkedres_size(payload, "linked_by", 0)
26382643
finally:
@@ -2682,18 +2687,20 @@ def test_linked_resource_for_maps_mixed(self):
26822687

26832688
payload = response.json()
26842689
self.assert_linkedres_size(payload, "resources", 2)
2685-
self.assert_linkedres_contains(payload, "resources", (
2686-
{"pk":self.doc.id, "title": "<<< " + self.doc.title},
2687-
{"pk":self.dataset.id, "title": ">>> " + self.dataset.title},)
2690+
self.assert_linkedres_contains(
2691+
payload,
2692+
"resources",
2693+
(
2694+
{"pk": self.doc.id, "title": "<<< " + self.doc.title},
2695+
{"pk": self.dataset.id, "title": ">>> " + self.dataset.title},
2696+
),
26882697
)
26892698
self.assert_linkedres_size(payload, "linked_to", 1)
2690-
self.assert_linkedres_contains(payload, "linked_to", (
2691-
{"pk":self.dataset.id, "title": self.dataset.title},)
2699+
self.assert_linkedres_contains(
2700+
payload, "linked_to", ({"pk": self.dataset.id, "title": self.dataset.title},)
26922701
)
26932702
self.assert_linkedres_size(payload, "linked_by", 1)
2694-
self.assert_linkedres_contains(payload, "linked_by", (
2695-
{"pk":self.doc.id, "title": self.doc.title},)
2696-
)
2703+
self.assert_linkedres_contains(payload, "linked_by", ({"pk": self.doc.id, "title": self.doc.title},))
26972704

26982705
finally:
26992706
if _d:
@@ -2721,12 +2728,12 @@ def test_linked_resources_for_maps(self):
27212728

27222729
payload = response.json()
27232730
self.assert_linkedres_size(payload, "resources", 1)
2724-
self.assert_linkedres_contains(payload, "resources", (
2725-
{"pk":self.dataset.id, "title": ">>> " + self.dataset.title},)
2731+
self.assert_linkedres_contains(
2732+
payload, "resources", ({"pk": self.dataset.id, "title": ">>> " + self.dataset.title},)
27262733
)
27272734
self.assert_linkedres_size(payload, "linked_to", 1)
2728-
self.assert_linkedres_contains(payload, "linked_to", (
2729-
{"pk":self.dataset.id, "title": self.dataset.title},)
2735+
self.assert_linkedres_contains(
2736+
payload, "linked_to", ({"pk": self.dataset.id, "title": self.dataset.title},)
27302737
)
27312738
self.assert_linkedres_size(payload, "linked_by", 0)
27322739

@@ -2754,14 +2761,12 @@ def test_linked_resource_for_dataset(self):
27542761

27552762
payload = response.json()
27562763
self.assert_linkedres_size(payload, "resources", 1)
2757-
self.assert_linkedres_contains(payload, "resources", (
2758-
{"pk":self.map.id, "title": "<<< " + self.map.title},)
2764+
self.assert_linkedres_contains(
2765+
payload, "resources", ({"pk": self.map.id, "title": "<<< " + self.map.title},)
27592766
)
27602767
self.assert_linkedres_size(payload, "linked_to", 0)
27612768
self.assert_linkedres_size(payload, "linked_by", 1)
2762-
self.assert_linkedres_contains(payload, "linked_by", (
2763-
{"pk":self.map.id, "title": self.map.title},)
2764-
)
2769+
self.assert_linkedres_contains(payload, "linked_by", ({"pk": self.map.id, "title": self.map.title},))
27652770

27662771
finally:
27672772
if _m:
@@ -2787,15 +2792,23 @@ def test_linked_resource_for_datasets_mixed(self):
27872792
self.assertEqual(response.status_code, 200)
27882793
payload = response.json()
27892794
self.assert_linkedres_size(payload, "resources", 2)
2790-
self.assert_linkedres_contains(payload, "resources", (
2791-
{"pk":self.doc.id, "title": "<<< " + self.doc.title},
2792-
{"pk":self.map.id, "title": "<<< " + self.map.title},)
2795+
self.assert_linkedres_contains(
2796+
payload,
2797+
"resources",
2798+
(
2799+
{"pk": self.doc.id, "title": "<<< " + self.doc.title},
2800+
{"pk": self.map.id, "title": "<<< " + self.map.title},
2801+
),
27932802
)
27942803
self.assert_linkedres_size(payload, "linked_to", 0)
27952804
self.assert_linkedres_size(payload, "linked_by", 2)
2796-
self.assert_linkedres_contains(payload, "linked_by", (
2797-
{"pk":self.map.id, "title": self.map.title},
2798-
{"pk":self.doc.id, "title": self.doc.title},)
2805+
self.assert_linkedres_contains(
2806+
payload,
2807+
"linked_by",
2808+
(
2809+
{"pk": self.map.id, "title": self.map.title},
2810+
{"pk": self.doc.id, "title": self.doc.title},
2811+
),
27992812
)
28002813

28012814
finally:

geonode/base/api/views.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@
109109
TopicCategorySerializer,
110110
RegionSerializer,
111111
ThesaurusKeywordSerializer,
112-
ExtraMetadataSerializer, LinkedResourceSerializer,
112+
ExtraMetadataSerializer,
113+
LinkedResourceSerializer,
113114
)
114115
from .pagination import GeoNodeApiPagination
115116
from geonode.base.utils import validate_extra_metadata
@@ -1506,36 +1507,36 @@ def base_linked_resources(instance, user, params):
15061507
# linked_resources = LinkedResource.get_linked_resources(source=instance).filter(target__in=resources)
15071508
# linked_by = LinkedResource.get_linked_resources(target=instance).filter(source__in=resources)
15081509

1509-
linked_resources = [lres for lres in instance.get_linked_resources()
1510-
if lres.target.id in visible_ids]
1511-
linked_by = [lres for lres in instance.get_linked_resources(as_target=True)
1512-
if lres.source.id in visible_ids]
1510+
linked_resources = [lres for lres in instance.get_linked_resources() if lres.target.id in visible_ids]
1511+
linked_by = [lres for lres in instance.get_linked_resources(as_target=True) if lres.source.id in visible_ids]
15131512

15141513
warnings = {
1515-
'DEPRECATION': "'resources' field is deprecated, please use 'linked_to'",
1514+
"DEPRECATION": "'resources' field is deprecated, please use 'linked_to'",
15161515
}
15171516

15181517
if "page_size" in params or "page" in params:
1519-
warnings['PAGINATION'] = "Pagination is not supported on this call"
1518+
warnings["PAGINATION"] = "Pagination is not supported on this call"
15201519

15211520
# "resources" will be deprecated, so next block is temporary
15221521
# "resources" at the moment it's the only element rendered, so we want to add there both the linked_resources and the linked_by
15231522
# we want to tell them apart, so we're adding an attr to store this info, that will be used in the SimpleResourceSerializer
15241523
resources = []
15251524
for lres in linked_resources:
15261525
res = lres.target
1527-
setattr(res, 'is_target', True)
1526+
setattr(res, "is_target", True)
15281527
resources.append(res)
15291528
for lres in linked_by:
15301529
res = lres.source
1531-
setattr(res, 'is_target', False)
1530+
setattr(res, "is_target", False)
15321531
resources.append(res)
15331532

15341533
ret = {
15351534
"WARNINGS": warnings,
15361535
"resources": SimpleResourceSerializer(resources, embed=True, many=True).data, # deprecated
15371536
"linked_to": LinkedResourceSerializer(linked_resources, embed=True, many=True).data,
1538-
"linked_by": LinkedResourceSerializer(instance=linked_by, serialize_source=True, embed=True, many=True).data,
1537+
"linked_by": LinkedResourceSerializer(
1538+
instance=linked_by, serialize_source=True, embed=True, many=True
1539+
).data,
15391540
}
15401541

15411542
return Response(ret)

geonode/base/forms.py

+6-14
Original file line numberDiff line numberDiff line change
@@ -347,18 +347,19 @@ def _get_thesauro_title_label(item, lang):
347347

348348

349349
class LinkedResourceForm(forms.ModelForm):
350-
351350
linked_resources = forms.MultipleChoiceField(label=_("Link to"), required=False)
352351

353352
def __init__(self, *args, **kwargs):
354353
super().__init__(*args, **kwargs)
355354
self.fields["linked_resources"].choices = LinkedResourceForm.generate_link_choices()
356-
self.fields["linked_resources"].initial = LinkedResourceForm.generate_link_values(resources=LinkedResource.get_targets(self.instance))
355+
self.fields["linked_resources"].initial = LinkedResourceForm.generate_link_values(
356+
resources=LinkedResource.get_targets(self.instance)
357+
)
357358

358359
@staticmethod
359360
def generate_link_choices(resources=None):
360361
if resources is None:
361-
resources = ResourceBase.objects.all().order_by('title')
362+
resources = ResourceBase.objects.all().order_by("title")
362363

363364
choices = []
364365
for obj in resources:
@@ -375,11 +376,7 @@ def save_linked_resources(self, links_field="linked_resources"):
375376
# create and fetch desired links
376377
target_ids = []
377378
for res_id in self.cleaned_data[links_field]:
378-
linked, _ = LinkedResource.objects.get_or_create(
379-
source=self.instance,
380-
target_id=res_id,
381-
internal=False
382-
)
379+
linked, _ = LinkedResource.objects.get_or_create(source=self.instance, target_id=res_id, internal=False)
383380
target_ids.append(res_id)
384381

385382
# matches = re.match(r"type:(\d+)-id:(\d+)", link)
@@ -396,11 +393,7 @@ def save_linked_resources(self, links_field="linked_resources"):
396393
# DocumentResourceLink.objects.filter(document_id=self.instance.id).exclude(
397394
# pk__in=[i.pk for i in instances]
398395
# ).delete()
399-
(LinkedResource.objects
400-
.filter(source_id=self.instance.id)
401-
.exclude(target_id__in=target_ids)
402-
.delete()
403-
)
396+
(LinkedResource.objects.filter(source_id=self.instance.id).exclude(target_id__in=target_ids).delete())
404397

405398

406399
class ResourceBaseDateTimePicker(DateTimePicker):
@@ -696,4 +689,3 @@ class Meta:
696689

697690
class ThesaurusImportForm(forms.Form):
698691
rdf_file = forms.FileField()
699-

geonode/base/models.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -1732,8 +1732,11 @@ def get_linked_resources(self, as_target: bool = False):
17321732
This is implemented as a method so that derived classes can override it (for instance, Maps may add
17331733
related datasets)
17341734
"""
1735-
return LinkedResource.get_linked_resources(target=self) if as_target \
1735+
return (
1736+
LinkedResource.get_linked_resources(target=self)
1737+
if as_target
17361738
else LinkedResource.get_linked_resources(source=self)
1739+
)
17371740

17381741

17391742
class LinkManager(models.Manager):
@@ -1759,29 +1762,29 @@ def ows(self):
17591762

17601763

17611764
class LinkedResource(models.Model):
1762-
source = models.ForeignKey(ResourceBase, related_name="linked_to",
1763-
blank=False, null=False, on_delete=models.CASCADE)
1764-
target = models.ForeignKey(ResourceBase, related_name="linked_by",
1765-
blank=True, null=False, on_delete=models.CASCADE)
1765+
source = models.ForeignKey(
1766+
ResourceBase, related_name="linked_to", blank=False, null=False, on_delete=models.CASCADE
1767+
)
1768+
target = models.ForeignKey(ResourceBase, related_name="linked_by", blank=True, null=False, on_delete=models.CASCADE)
17661769
internal = models.BooleanField(null=False, default=False)
17671770

17681771
@classmethod
17691772
def get_linked_resources(cls, source: ResourceBase = None, target: ResourceBase = None, is_internal: bool = None):
17701773
if source is None and target is None:
1771-
raise ValueError('Both source and target filters missing')
1774+
raise ValueError("Both source and target filters missing")
17721775

17731776
qs = LinkedResource.objects
17741777
if source:
1775-
qs = qs.filter(source=source).select_related('target')
1778+
qs = qs.filter(source=source).select_related("target")
17761779
if target:
1777-
qs = qs.filter(target=target).select_related('source')
1780+
qs = qs.filter(target=target).select_related("source")
17781781
if is_internal is not None:
17791782
qs = qs.filter(internal=is_internal)
17801783
return qs
17811784

17821785
@classmethod
17831786
def get_targets(cls, source: ResourceBase, is_internal: bool = None):
1784-
sub = LinkedResource.objects.filter(source=source).values('target_id')
1787+
sub = LinkedResource.objects.filter(source=source).values("target_id")
17851788
if is_internal is not None:
17861789
sub = sub.filter(internal=is_internal)
17871790
return ResourceBase.objects.filter(id__in=sub)

geonode/layers/models.py

+1
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ def get_linked_resources(self, as_target: bool = False):
323323

324324
if as_target:
325325
from geonode.maps.models import Map
326+
326327
# create LinkedResources on the fly to report MapLayer relationship
327328
res = (LinkedResource(source=map, target=self, internal=True) for map in self.maps)
328329
ret = itertools.chain(ret, res)

geonode/resource/manager.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -513,13 +513,13 @@ def copy(
513513
defaults.pop("name")
514514
_resource.save()
515515
for lr in LinkedResource.get_linked_resources(source=instance.pk, is_internal=False):
516-
LinkedResource.object.get_or_create(source_id=_resource.pk,
517-
target_id=lr.target.pk,
518-
internal=False)
516+
LinkedResource.object.get_or_create(
517+
source_id=_resource.pk, target_id=lr.target.pk, internal=False
518+
)
519519
for lr in LinkedResource.get_linked_resources(target=instance.pk, is_internal=False):
520-
LinkedResource.object.get_or_create(source_id=lr.source.pk,
521-
target_id=_resource.pk,
522-
internal=False)
520+
LinkedResource.object.get_or_create(
521+
source_id=lr.source.pk, target_id=_resource.pk, internal=False
522+
)
523523

524524
if isinstance(instance.get_real_instance(), Dataset):
525525
for attribute in Attribute.objects.filter(dataset=instance.get_real_instance()):

0 commit comments

Comments
 (0)