Skip to content

Commit ab14ce6

Browse files
[Fixes GeoNode#11821] GNIP 98: Django upgrade to 4.2 LTS (GeoNode#11829)
* Upgrade to django 4.2 * Upgrade to django 4.2 * Fix tests * black and flake fix * Drop support of pinax-ratings * Drop support of pinax-ratings * black and flake fix * black and flake fix * remove support to HAYSTACK_SEARCH * remove support to HAYSTACK_SEARCH * remove pinax_ratings_tags * Fix warning on lock acquire * [Fixes GeoNode#11821] rollback SKIP_PERMS_FILTER * [Fixes GeoNode#11821] fix dependencies * [Fixes GeoNode#11821] remove unused test of raitings * [Fixes GeoNode#11821] use geonode fork for dynamic rest * [Fixes GeoNode#11821] use geonode fork for dynamic rest * [Fixes GeoNode#11821] use geonode fork for dynamic rest * [Fixes GeoNode#11821] Fix setup.cfg * [Fixes GeoNode#11821] fix dependencies * [Fixes GeoNode#11821] fix dependencies * [Fixes GeoNode#11821] fix dependencies * [Fixes GeoNode#11821] fix dependencies * [Fixes GeoNode#11821] fix setup.cfg * [Fixes GeoNode#11821] fix setup.cfg * [Fixes GeoNode#11821] fix setup.cfg * [Fixes GeoNode#11821] fix setup.cfg * [Fixes GeoNode#11821] fix requirements.txt * remove default_app_config since is deprecated since django 3.2 * Define apps.py for app registration according to Django 4.2 * Define apps.py for app registration according to Django 4.2 * [Fixes GeoNode#11821] Fix tests * [Fixes GeoNode#11821] Add apps.py and fix test import * [Fixes GeoNode#11821] Add apps.py and fix test import * [Fixes GeoNode#11821] Add apps.py and fix test import * merge with master * upgrade requirement * Update setup.cfg * Update setup.cfg * Fix select autocomplete light --------- Co-authored-by: Giovanni Allegri <giohappy@gmail.com>
1 parent 4bc8e5f commit ab14ce6

File tree

194 files changed

+1197
-2081
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

194 files changed

+1197
-2081
lines changed

.env.sample

-4
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', '{hostname}']"
4949
DEFAULT_BACKEND_UPLOADER=geonode.importer
5050
TIME_ENABLED=True
5151
MOSAIC_ENABLED=False
52-
HAYSTACK_SEARCH=False
53-
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
54-
HAYSTACK_ENGINE_INDEX_NAME=haystack
55-
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200
5652

5753
# #################
5854
# nginx

.env_dev

-4
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', '*']"
4949
DEFAULT_BACKEND_UPLOADER=geonode.importer
5050
TIME_ENABLED=True
5151
MOSAIC_ENABLED=False
52-
HAYSTACK_SEARCH=False
53-
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
54-
HAYSTACK_ENGINE_INDEX_NAME=haystack
55-
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200
5652

5753
# #################
5854
# nginx

.env_local

-4
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', '*']"
4949
DEFAULT_BACKEND_UPLOADER=geonode.importer
5050
TIME_ENABLED=True
5151
MOSAIC_ENABLED=False
52-
HAYSTACK_SEARCH=False
53-
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
54-
HAYSTACK_ENGINE_INDEX_NAME=haystack
55-
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200
5652

5753
# #################
5854
# nginx

.env_test

-4
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ ALLOWED_HOSTS="['django', 'localhost', '127.0.0.1']"
4949
DEFAULT_BACKEND_UPLOADER=geonode.importer
5050
TIME_ENABLED=True
5151
MOSAIC_ENABLED=False
52-
HAYSTACK_SEARCH=False
53-
HAYSTACK_ENGINE_URL=http://elasticsearch:9200/
54-
HAYSTACK_ENGINE_INDEX_NAME=haystack
55-
HAYSTACK_SEARCH_RESULTS_PER_PAGE=200
5652

5753
# #################
5854
# nginx

docker-compose-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ services:
3232
start_period: 60s
3333
interval: 60s
3434
timeout: 10s
35-
retries: 2
35+
retries: 5
3636
environment:
3737
- IS_CELERY=False
3838
entrypoint: ["/usr/src/geonode/entrypoint.sh"]

geonode/__init__.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@
1919

2020
import os
2121

22-
__version__ = (4, 2, 0, "dev", 0)
23-
24-
25-
default_app_config = "geonode.apps.AppConfig"
22+
__version__ = (5, 0, 0, "dev", 0)
2623

2724

2825
def get_version():

geonode/api/__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,3 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
#
1818
#########################################################################
19-
default_app_config = "geonode.api.apps.GeoNodeApiAppConfig"

geonode/api/api.py

+1-12
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
from django.apps import apps
2424
from django.db.models import Q
25-
from django.conf.urls import url
2625
from django.contrib.auth import get_user_model
2726
from django.contrib.auth.models import Group
2827
from django.urls import reverse
@@ -61,7 +60,6 @@
6160
from tastypie import fields
6261
from tastypie.resources import ModelResource
6362
from tastypie.constants import ALL, ALL_WITH_RELATIONS
64-
from tastypie.utils import trailing_slash
6563

6664
from geonode.utils import check_ogc_backend
6765
from geonode.security.utils import get_visible_resources
@@ -548,16 +546,7 @@ def dehydrate(self, bundle):
548546
return bundle
549547

550548
def prepend_urls(self):
551-
if settings.HAYSTACK_SEARCH:
552-
return [
553-
url(
554-
r"^(?P<resource_name>{})/search{}$".format(self._meta.resource_name, trailing_slash()),
555-
self.wrap_view("get_search"),
556-
name="api_get_search",
557-
),
558-
]
559-
else:
560-
return []
549+
return []
561550

562551
def serialize(self, request, data, format, options=None):
563552
if options is None:

geonode/api/resourcebase_api.py

+1-256
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#
1818
#########################################################################
1919
from geonode.base.enumerations import LAYER_TYPES
20-
import re
2120
import logging
2221

2322
from django.db.models import Q
@@ -29,13 +28,7 @@
2928
from tastypie.constants import ALL, ALL_WITH_RELATIONS
3029
from tastypie.resources import ModelResource
3130
from tastypie import fields
32-
from tastypie.utils import trailing_slash
3331

34-
from guardian.shortcuts import get_objects_for_user
35-
36-
from django.conf.urls import url
37-
from django.core.paginator import Paginator, InvalidPage
38-
from django.http import Http404
3932
from django.core.exceptions import ObjectDoesNotExist
4033
from django.forms.models import model_to_dict
4134

@@ -67,9 +60,6 @@
6760
from .paginator import CrossSiteXHRPaginator
6861
from django.utils.translation import gettext as _
6962

70-
if settings.HAYSTACK_SEARCH:
71-
from haystack.query import SearchQuerySet # noqa
72-
7363
logger = logging.getLogger(__name__)
7464

7565

@@ -246,242 +236,6 @@ def filter_h_keywords(self, queryset, keywords):
246236
filtered = queryset
247237
return filtered
248238

249-
def build_haystack_filters(self, parameters):
250-
from haystack.inputs import Raw
251-
from haystack.query import SearchQuerySet, SQ # noqa
252-
253-
sqs = None
254-
255-
# Retrieve Query Params
256-
257-
# Text search
258-
query = parameters.get("q", None)
259-
260-
# Types and subtypes to filter (map, layer, vector, etc)
261-
type_facets = parameters.getlist("type__in", [])
262-
263-
# If coming from explore page, add type filter from resource_name
264-
resource_filter = self._meta.resource_name.rstrip("s")
265-
if resource_filter != "base" and resource_filter not in type_facets:
266-
type_facets.append(resource_filter)
267-
268-
# Publication date range (start,end)
269-
date_end = parameters.get("date__lte", None)
270-
date_start = parameters.get("date__gte", None)
271-
272-
# Topic category filter
273-
category = parameters.getlist("category__identifier__in")
274-
275-
# Keyword filter
276-
keywords = parameters.getlist("keywords__slug__in")
277-
278-
# Region filter
279-
regions = parameters.getlist("regions__name__in")
280-
281-
# Owner filters
282-
owner = parameters.getlist("owner__username__in")
283-
284-
# Sort order
285-
sort = parameters.get("order_by", "relevance")
286-
287-
# Geospatial Elements
288-
bbox = parameters.get("extent", None)
289-
290-
# Filter by Type and subtype
291-
if type_facets is not None:
292-
types = []
293-
subtypes = []
294-
295-
for type in type_facets:
296-
if type in {"map", "layer", "document", "user"}:
297-
# Type is one of our Major Types (not a sub type)
298-
types.append(type)
299-
elif type in LAYER_TYPES:
300-
subtypes.append(type)
301-
302-
if "vector" in subtypes and "vector_time" not in subtypes:
303-
subtypes.append("vector_time")
304-
305-
if len(subtypes) > 0:
306-
types.append("layer")
307-
sqs = SearchQuerySet().narrow(f"subtype:{','.join(map(str, subtypes))}")
308-
309-
if len(types) > 0:
310-
sqs = (SearchQuerySet() if sqs is None else sqs).narrow(f"type:{','.join(map(str, types))}")
311-
312-
# Filter by Query Params
313-
# haystack bug? if boosted fields aren't included in the
314-
# query, then the score won't be affected by the boost
315-
if query:
316-
if query.startswith('"') or query.startswith("'"):
317-
# Match exact phrase
318-
phrase = query.replace('"', "")
319-
sqs = (SearchQuerySet() if sqs is None else sqs).filter(
320-
SQ(title__exact=phrase) | SQ(description__exact=phrase) | SQ(content__exact=phrase)
321-
)
322-
else:
323-
words = [w for w in re.split(r"\W", query, flags=re.UNICODE) if w]
324-
for i, search_word in enumerate(words):
325-
if i == 0:
326-
sqs = (SearchQuerySet() if sqs is None else sqs).filter(
327-
SQ(title=Raw(search_word)) | SQ(description=Raw(search_word)) | SQ(content=Raw(search_word))
328-
)
329-
elif search_word in {"AND", "OR"}:
330-
pass
331-
elif words[i - 1] == "OR": # previous word OR this word
332-
sqs = sqs.filter_or(
333-
SQ(title=Raw(search_word)) | SQ(description=Raw(search_word)) | SQ(content=Raw(search_word))
334-
)
335-
else: # previous word AND this word
336-
sqs = sqs.filter(
337-
SQ(title=Raw(search_word)) | SQ(description=Raw(search_word)) | SQ(content=Raw(search_word))
338-
)
339-
340-
# filter by category
341-
if category:
342-
sqs = (SearchQuerySet() if sqs is None else sqs).narrow(f"category:{','.join(map(str, category))}")
343-
344-
# filter by keyword: use filter_or with keywords_exact
345-
# not using exact leads to fuzzy matching and too many results
346-
# using narrow with exact leads to zero results if multiple keywords
347-
# selected
348-
if keywords:
349-
for keyword in keywords:
350-
sqs = (SearchQuerySet() if sqs is None else sqs).filter_or(keywords_exact=keyword)
351-
352-
# filter by regions: use filter_or with regions_exact
353-
# not using exact leads to fuzzy matching and too many results
354-
# using narrow with exact leads to zero results if multiple keywords
355-
# selected
356-
if regions:
357-
for region in regions:
358-
sqs = (SearchQuerySet() if sqs is None else sqs).filter_or(regions_exact__exact=region)
359-
360-
# filter by owner
361-
if owner:
362-
sqs = (SearchQuerySet() if sqs is None else sqs).narrow(f"owner__username:{','.join(map(str, owner))}")
363-
364-
# filter by date
365-
if date_start:
366-
sqs = (SearchQuerySet() if sqs is None else sqs).filter(SQ(date__gte=date_start))
367-
368-
if date_end:
369-
sqs = (SearchQuerySet() if sqs is None else sqs).filter(SQ(date__lte=date_end))
370-
371-
# Filter by geographic bounding box
372-
if bbox:
373-
left, bottom, right, top = bbox.split(",")
374-
sqs = (SearchQuerySet() if sqs is None else sqs).exclude(
375-
SQ(bbox_top__lte=bottom)
376-
| SQ(bbox_bottom__gte=top)
377-
| SQ(bbox_left__gte=right)
378-
| SQ(bbox_right__lte=left)
379-
)
380-
381-
# Apply sort
382-
if sort.lower() == "-date":
383-
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-date")
384-
elif sort.lower() == "date":
385-
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("date")
386-
elif sort.lower() == "title":
387-
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("title_sortable")
388-
elif sort.lower() == "-title":
389-
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-title_sortable")
390-
elif sort.lower() == "-popular_count":
391-
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-popular_count")
392-
else:
393-
sqs = (SearchQuerySet() if sqs is None else sqs).order_by("-date")
394-
395-
return sqs
396-
397-
def get_search(self, request, **kwargs):
398-
self.method_check(request, allowed=["get"])
399-
self.is_authenticated(request)
400-
self.throttle_check(request)
401-
402-
# Get the list of objects that matches the filter
403-
sqs = self.build_haystack_filters(request.GET)
404-
405-
if not settings.SKIP_PERMS_FILTER:
406-
filter_set = get_objects_for_user(request.user, "base.view_resourcebase")
407-
408-
filter_set = get_visible_resources(
409-
filter_set,
410-
request.user if request else None,
411-
admin_approval_required=settings.ADMIN_MODERATE_UPLOADS,
412-
unpublished_not_visible=settings.RESOURCE_PUBLISHING,
413-
private_groups_not_visibile=settings.GROUP_PRIVATE_RESOURCES,
414-
)
415-
416-
filter_set_ids = filter_set.values_list("id")
417-
# Do the query using the filterset and the query term. Facet the
418-
# results
419-
if len(filter_set) > 0:
420-
sqs = (
421-
sqs.filter(id__in=filter_set_ids)
422-
.facet("type")
423-
.facet("subtype")
424-
.facet("owner")
425-
.facet("keywords")
426-
.facet("regions")
427-
.facet("category")
428-
)
429-
else:
430-
sqs = None
431-
else:
432-
sqs = sqs.facet("type").facet("subtype").facet("owner").facet("keywords").facet("regions").facet("category")
433-
434-
if sqs:
435-
# Build the Facet dict
436-
facets = {}
437-
for facet in sqs.facet_counts()["fields"]:
438-
facets[facet] = {}
439-
for item in sqs.facet_counts()["fields"][facet]:
440-
facets[facet][item[0]] = item[1]
441-
442-
# Paginate the results
443-
paginator = Paginator(sqs, request.GET.get("limit"))
444-
445-
try:
446-
page = paginator.page(int(request.GET.get("offset") or 0) / int(request.GET.get("limit") or 0 + 1))
447-
except InvalidPage:
448-
raise Http404("Sorry, no results on that page.")
449-
450-
if page.has_previous():
451-
previous_page = page.previous_page_number()
452-
else:
453-
previous_page = 1
454-
if page.has_next():
455-
next_page = page.next_page_number()
456-
else:
457-
next_page = 1
458-
total_count = sqs.count()
459-
objects = page.object_list
460-
else:
461-
next_page = 0
462-
previous_page = 0
463-
total_count = 0
464-
facets = {}
465-
objects = []
466-
467-
object_list = {
468-
"meta": {
469-
"limit": settings.CLIENT_RESULTS_LIMIT,
470-
"next": next_page,
471-
"offset": int(getattr(request.GET, "offset", 0)),
472-
"previous": previous_page,
473-
"total_count": total_count,
474-
"facets": facets,
475-
},
476-
"objects": [self.get_haystack_api_fields(x) for x in objects],
477-
}
478-
479-
self.log_throttled_access(request)
480-
return self.create_response(request, object_list)
481-
482-
def get_haystack_api_fields(self, haystack_object):
483-
return {k: v for k, v in haystack_object.get_stored_fields().items() if not re.search("_exact$|_sortable$", k)}
484-
485239
def get_list(self, request, **kwargs):
486240
"""
487241
Returns a serialized list of resources.
@@ -574,16 +328,7 @@ def create_response(self, request, data, response_class=HttpResponse, response_o
574328
return response_class(content=serialized, content_type=build_content_type(desired_format), **response_kwargs)
575329

576330
def prepend_urls(self):
577-
if settings.HAYSTACK_SEARCH:
578-
return [
579-
url(
580-
r"^(?P<resource_name>{})/search{}$".format(self._meta.resource_name, trailing_slash()),
581-
self.wrap_view("get_search"),
582-
name="api_get_search",
583-
),
584-
]
585-
else:
586-
return []
331+
return []
587332

588333
def hydrate_title(self, bundle):
589334
title = bundle.data.get("title", None)

0 commit comments

Comments
 (0)