Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fixes #11821] GNIP 98: Django upgrade to 4.2 LTS #11829

Merged
merged 59 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
d3d7da3
Upgrade to django 4.2
mattiagiupponi Jan 10, 2024
7751d15
Upgrade to django 4.2
mattiagiupponi Jan 10, 2024
dbc4f7a
merge with master
mattiagiupponi Jan 10, 2024
4a3b348
Merge branch 'master' into ISSUE_11821
mattiagiupponi Jan 10, 2024
e15db9f
Fix tests
mattiagiupponi Jan 10, 2024
a6c77cd
Merge branch 'ISSUE_11821' of github.com:GeoNode/geonode into ISSUE_1…
mattiagiupponi Jan 10, 2024
7ab945d
Merge branch 'master' of github.com:GeoNode/geonode into ISSUE_11821
mattiagiupponi Jan 10, 2024
85fdd08
black and flake fix
mattiagiupponi Jan 10, 2024
47ebb39
Merge branch 'master' into ISSUE_11821
mattiagiupponi Jan 11, 2024
23b002b
Drop support of pinax-ratings
mattiagiupponi Jan 11, 2024
8fdd189
Drop support of pinax-ratings
mattiagiupponi Jan 11, 2024
94c6631
Merge branch 'ISSUE_11821' of github.com:GeoNode/geonode into ISSUE_1…
mattiagiupponi Jan 11, 2024
9c4e551
black and flake fix
mattiagiupponi Jan 11, 2024
ce844f1
black and flake fix
mattiagiupponi Jan 11, 2024
ce88011
remove support to HAYSTACK_SEARCH
mattiagiupponi Jan 11, 2024
7c03c01
remove support to HAYSTACK_SEARCH
mattiagiupponi Jan 11, 2024
8c4d352
remove pinax_ratings_tags
mattiagiupponi Jan 11, 2024
68c2340
Fix warning on lock acquire
mattiagiupponi Jan 11, 2024
ee83ad3
[Fixes #11821] Merge with master
mattiagiupponi Jan 12, 2024
594c164
[Fixes #11821] rollback SKIP_PERMS_FILTER
mattiagiupponi Jan 12, 2024
aedd880
[Fixes #11821] fix dependencies
mattiagiupponi Jan 12, 2024
998c8c4
[Fixes #11821] remove unused test of raitings
mattiagiupponi Jan 12, 2024
933e6e1
[Fixes #11821] use geonode fork for dynamic rest
mattiagiupponi Jan 12, 2024
41e7c17
[Fixes #11821] use geonode fork for dynamic rest
mattiagiupponi Jan 12, 2024
7fd93e5
[Fixes #11821] use geonode fork for dynamic rest
mattiagiupponi Jan 12, 2024
65e1e84
[Fixes #11821] Fix setup.cfg
mattiagiupponi Jan 12, 2024
ddd307a
[Fixes #11821] fix dependencies
mattiagiupponi Jan 12, 2024
759d742
Merge branch 'master' of github.com:GeoNode/geonode into ISSUE_11821
mattiagiupponi Jan 12, 2024
8dcf089
[Fixes #11821] fix dependencies
mattiagiupponi Jan 12, 2024
7766d6b
[Fixes #11821] fix dependencies
mattiagiupponi Jan 12, 2024
070cac6
[Fixes #11821] fix dependencies
mattiagiupponi Jan 12, 2024
b0f0539
merge with master
mattiagiupponi Jan 17, 2024
9378f9a
Merge branch 'master' into ISSUE_11821
mattiagiupponi Jan 19, 2024
80292db
Merge branch 'master' of github.com:GeoNode/geonode into ISSUE_11821
mattiagiupponi Jan 26, 2024
1475367
Merge branch 'ISSUE_11821' of github.com:GeoNode/geonode into ISSUE_1…
mattiagiupponi Jan 26, 2024
e98eaac
[Fixes #11821] fix setup.cfg
mattiagiupponi Jan 26, 2024
9029830
[Fixes #11821] fix setup.cfg
mattiagiupponi Jan 26, 2024
9df1784
[Fixes #11821] fix setup.cfg
mattiagiupponi Jan 26, 2024
034e1dc
[Fixes #11821] fix setup.cfg
mattiagiupponi Jan 26, 2024
8b183e8
[Fixes #11821] fix requirements.txt
mattiagiupponi Jan 26, 2024
5c23544
remove default_app_config since is deprecated since django 3.2
mattiagiupponi Jan 29, 2024
db2181d
Define apps.py for app registration according to Django 4.2
mattiagiupponi Jan 29, 2024
04c3886
Define apps.py for app registration according to Django 4.2
mattiagiupponi Jan 29, 2024
70703de
[Fixes #11821] Fix tests
mattiagiupponi Jan 29, 2024
b26f04d
[Fixes #11821] Add apps.py and fix test import
mattiagiupponi Jan 30, 2024
1f2a49c
[Fixes #11821] Add apps.py and fix test import
mattiagiupponi Jan 30, 2024
7bc0a24
[Fixes #11821] Add apps.py and fix test import
mattiagiupponi Jan 30, 2024
b7b4173
Merge branch 'master' into ISSUE_11821
mattiagiupponi Jan 30, 2024
3044883
merge with master
mattiagiupponi Jan 30, 2024
0f79828
Merge branch 'ISSUE_11821' of github.com:GeoNode/geonode into ISSUE_1…
mattiagiupponi Jan 30, 2024
95689e0
merge with master
mattiagiupponi Jan 30, 2024
6957fea
Merge branch 'master' into ISSUE_11821
mattiagiupponi Jan 31, 2024
41cd750
upgrade requirement
mattiagiupponi Jan 31, 2024
88d44e6
Merge branch 'master' of github.com:GeoNode/geonode into ISSUE_11821
mattiagiupponi Jan 31, 2024
dc3914c
Merge branch 'ISSUE_11821' of github.com:GeoNode/geonode into ISSUE_1…
mattiagiupponi Jan 31, 2024
576183e
Update setup.cfg
mattiagiupponi Jan 31, 2024
608c6f7
Update setup.cfg
giohappy Jan 31, 2024
e5b11c0
Fix select autocomplete light
mattiagiupponi Jan 31, 2024
315c2c1
Merge branch 'ISSUE_11821' of github.com:GeoNode/geonode into ISSUE_1…
mattiagiupponi Jan 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', '{hostname}']"
DEFAULT_BACKEND_UPLOADER=geonode.importer
TIME_ENABLED=True
MOSAIC_ENABLED=False
HAYSTACK_SEARCH=False
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
HAYSTACK_ENGINE_INDEX_NAME=haystack
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200

# #################
# nginx
Expand Down
4 changes: 0 additions & 4 deletions .env_dev
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', '*']"
DEFAULT_BACKEND_UPLOADER=geonode.importer
TIME_ENABLED=True
MOSAIC_ENABLED=False
HAYSTACK_SEARCH=False
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
HAYSTACK_ENGINE_INDEX_NAME=haystack
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200

# #################
# nginx
Expand Down
4 changes: 0 additions & 4 deletions .env_local
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', '*']"
DEFAULT_BACKEND_UPLOADER=geonode.importer
TIME_ENABLED=True
MOSAIC_ENABLED=False
HAYSTACK_SEARCH=False
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
HAYSTACK_ENGINE_INDEX_NAME=haystack
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200

# #################
# nginx
Expand Down
4 changes: 0 additions & 4 deletions .env_test
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', 'localhost', '127.0.0.1']"
DEFAULT_BACKEND_UPLOADER=geonode.importer
TIME_ENABLED=True
MOSAIC_ENABLED=False
HAYSTACK_SEARCH=False
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
HAYSTACK_ENGINE_INDEX_NAME=haystack
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200

# #################
# nginx
Expand Down
2 changes: 1 addition & 1 deletion docker-compose-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ services:
start_period: 60s
interval: 60s
timeout: 10s
retries: 2
retries: 5
environment:
- IS_CELERY=False
entrypoint: ["/usr/src/geonode/entrypoint.sh"]
Expand Down
5 changes: 1 addition & 4 deletions geonode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@

import os

__version__ = (4, 2, 0, "dev", 0)


default_app_config = "geonode.apps.AppConfig"
__version__ = (5, 0, 0, "dev", 0)


def get_version():
Expand Down
1 change: 0 additions & 1 deletion geonode/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################
default_app_config = "geonode.api.apps.GeoNodeApiAppConfig"
13 changes: 1 addition & 12 deletions geonode/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

from django.apps import apps
from django.db.models import Q
from django.conf.urls import url
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.urls import reverse
Expand Down Expand Up @@ -61,7 +60,6 @@
from tastypie import fields
from tastypie.resources import ModelResource
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.utils import trailing_slash

from geonode.utils import check_ogc_backend
from geonode.security.utils import get_visible_resources
Expand Down Expand Up @@ -548,16 +546,7 @@ def dehydrate(self, bundle):
return bundle

def prepend_urls(self):
if settings.HAYSTACK_SEARCH:
return [
url(
r"^(?P<resource_name>{})/search{}$".format(self._meta.resource_name, trailing_slash()),
self.wrap_view("get_search"),
name="api_get_search",
),
]
else:
return []
return []

def serialize(self, request, data, format, options=None):
if options is None:
Expand Down
257 changes: 1 addition & 256 deletions geonode/api/resourcebase_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#
#########################################################################
from geonode.base.enumerations import LAYER_TYPES
import re
import logging

from django.db.models import Q
Expand All @@ -29,13 +28,7 @@
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.resources import ModelResource
from tastypie import fields
from tastypie.utils import trailing_slash

from guardian.shortcuts import get_objects_for_user

from django.conf.urls import url
from django.core.paginator import Paginator, InvalidPage
from django.http import Http404
from django.core.exceptions import ObjectDoesNotExist
from django.forms.models import model_to_dict

Expand Down Expand Up @@ -67,9 +60,6 @@
from .paginator import CrossSiteXHRPaginator
from django.utils.translation import gettext as _

if settings.HAYSTACK_SEARCH:
from haystack.query import SearchQuerySet # noqa

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -246,242 +236,6 @@ def filter_h_keywords(self, queryset, keywords):
filtered = queryset
return filtered

def build_haystack_filters(self, parameters):
from haystack.inputs import Raw
from haystack.query import SearchQuerySet, SQ # noqa

sqs = None

# Retrieve Query Params

# Text search
query = parameters.get("q", None)

# Types and subtypes to filter (map, layer, vector, etc)
type_facets = parameters.getlist("type__in", [])

# If coming from explore page, add type filter from resource_name
resource_filter = self._meta.resource_name.rstrip("s")
if resource_filter != "base" and resource_filter not in type_facets:
type_facets.append(resource_filter)

# Publication date range (start,end)
date_end = parameters.get("date__lte", None)
date_start = parameters.get("date__gte", None)

# Topic category filter
category = parameters.getlist("category__identifier__in")

# Keyword filter
keywords = parameters.getlist("keywords__slug__in")

# Region filter
regions = parameters.getlist("regions__name__in")

# Owner filters
owner = parameters.getlist("owner__username__in")

# Sort order
sort = parameters.get("order_by", "relevance")

# Geospatial Elements
bbox = parameters.get("extent", None)

# Filter by Type and subtype
if type_facets is not None:
types = []
subtypes = []

for type in type_facets:
if type in {"map", "layer", "document", "user"}:
# Type is one of our Major Types (not a sub type)
types.append(type)
elif type in LAYER_TYPES:
subtypes.append(type)

if "vector" in subtypes and "vector_time" not in subtypes:
subtypes.append("vector_time")

if len(subtypes) > 0:
types.append("layer")
sqs = SearchQuerySet().narrow(f"subtype:{','.join(map(str, subtypes))}")

if len(types) > 0:
sqs = (SearchQuerySet() if sqs is None else sqs).narrow(f"type:{','.join(map(str, types))}")

# Filter by Query Params
# haystack bug? if boosted fields aren't included in the
# query, then the score won't be affected by the boost
if query:
if query.startswith('"') or query.startswith("'"):
# Match exact phrase
phrase = query.replace('"', "")
sqs = (SearchQuerySet() if sqs is None else sqs).filter(
SQ(title__exact=phrase) | SQ(description__exact=phrase) | SQ(content__exact=phrase)
)
else:
words = [w for w in re.split(r"\W", query, flags=re.UNICODE) if w]
for i, search_word in enumerate(words):
if i == 0:
sqs = (SearchQuerySet() if sqs is None else sqs).filter(
SQ(title=Raw(search_word)) | SQ(description=Raw(search_word)) | SQ(content=Raw(search_word))
)
elif search_word in {"AND", "OR"}:
pass
elif words[i - 1] == "OR": # previous word OR this word
sqs = sqs.filter_or(
SQ(title=Raw(search_word)) | SQ(description=Raw(search_word)) | SQ(content=Raw(search_word))
)
else: # previous word AND this word
sqs = sqs.filter(
SQ(title=Raw(search_word)) | SQ(description=Raw(search_word)) | SQ(content=Raw(search_word))
)

# filter by category
if category:
sqs = (SearchQuerySet() if sqs is None else sqs).narrow(f"category:{','.join(map(str, category))}")

# filter by keyword: use filter_or with keywords_exact
# not using exact leads to fuzzy matching and too many results
# using narrow with exact leads to zero results if multiple keywords
# selected
if keywords:
for keyword in keywords:
sqs = (SearchQuerySet() if sqs is None else sqs).filter_or(keywords_exact=keyword)

# filter by regions: use filter_or with regions_exact
# not using exact leads to fuzzy matching and too many results
# using narrow with exact leads to zero results if multiple keywords
# selected
if regions:
for region in regions:
sqs = (SearchQuerySet() if sqs is None else sqs).filter_or(regions_exact__exact=region)

# filter by owner
if owner:
sqs = (SearchQuerySet() if sqs is None else sqs).narrow(f"owner__username:{','.join(map(str, owner))}")

# filter by date
if date_start:
sqs = (SearchQuerySet() if sqs is None else sqs).filter(SQ(date__gte=date_start))

if date_end:
sqs = (SearchQuerySet() if sqs is None else sqs).filter(SQ(date__lte=date_end))

# Filter by geographic bounding box
if bbox:
left, bottom, right, top = bbox.split(",")
sqs = (SearchQuerySet() if sqs is None else sqs).exclude(
SQ(bbox_top__lte=bottom)
| SQ(bbox_bottom__gte=top)
| SQ(bbox_left__gte=right)
| SQ(bbox_right__lte=left)
)

# Apply sort
if sort.lower() == "-date":
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-date")
elif sort.lower() == "date":
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("date")
elif sort.lower() == "title":
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("title_sortable")
elif sort.lower() == "-title":
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-title_sortable")
elif sort.lower() == "-popular_count":
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-popular_count")
else:
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-date")

return sqs

def get_search(self, request, **kwargs):
self.method_check(request, allowed=["get"])
self.is_authenticated(request)
self.throttle_check(request)

# Get the list of objects that matches the filter
sqs = self.build_haystack_filters(request.GET)

if not settings.SKIP_PERMS_FILTER:
filter_set = get_objects_for_user(request.user, "base.view_resourcebase")

filter_set = get_visible_resources(
filter_set,
request.user if request else None,
admin_approval_required=settings.ADMIN_MODERATE_UPLOADS,
unpublished_not_visible=settings.RESOURCE_PUBLISHING,
private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES,
)

filter_set_ids = filter_set.values_list("id")
# Do the query using the filterset and the query term. Facet the
# results
if len(filter_set) > 0:
sqs = (
sqs.filter(id__in=filter_set_ids)
.facet("type")
.facet("subtype")
.facet("owner")
.facet("keywords")
.facet("regions")
.facet("category")
)
else:
sqs = None
else:
sqs = sqs.facet("type").facet("subtype").facet("owner").facet("keywords").facet("regions").facet("category")

if sqs:
# Build the Facet dict
facets = {}
for facet in sqs.facet_counts()["fields"]:
facets[facet] = {}
for item in sqs.facet_counts()["fields"][facet]:
facets[facet][item[0]] = item[1]

# Paginate the results
paginator = Paginator(sqs, request.GET.get("limit"))

try:
page = paginator.page(int(request.GET.get("offset") or 0) / int(request.GET.get("limit") or 0 + 1))
except InvalidPage:
raise Http404("Sorry, no results on that page.")

if page.has_previous():
previous_page = page.previous_page_number()
else:
previous_page = 1
if page.has_next():
next_page = page.next_page_number()
else:
next_page = 1
total_count = sqs.count()
objects = page.object_list
else:
next_page = 0
previous_page = 0
total_count = 0
facets = {}
objects = []

object_list = {
"meta": {
"limit": settings.CLIENT_RESULTS_LIMIT,
"next": next_page,
"offset": int(getattr(request.GET, "offset", 0)),
"previous": previous_page,
"total_count": total_count,
"facets": facets,
},
"objects": [self.get_haystack_api_fields(x) for x in objects],
}

self.log_throttled_access(request)
return self.create_response(request, object_list)

def get_haystack_api_fields(self, haystack_object):
return {k: v for k, v in haystack_object.get_stored_fields().items() if not re.search("_exact$|_sortable$", k)}

def get_list(self, request, **kwargs):
"""
Returns a serialized list of resources.
Expand Down Expand Up @@ -574,16 +328,7 @@ def create_response(self, request, data, response_class=HttpResponse, response_o
return response_class(content=serialized, content_type=build_content_type(desired_format), **response_kwargs)

def prepend_urls(self):
if settings.HAYSTACK_SEARCH:
return [
url(
r"^(?P<resource_name>{})/search{}$".format(self._meta.resource_name, trailing_slash()),
self.wrap_view("get_search"),
name="api_get_search",
),
]
else:
return []
return []

def hydrate_title(self, bundle):
title = bundle.data.get("title", None)
Expand Down
Loading
Loading