From a5f5557493446bede78adb0584c88208234f874e Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 12 May 2012 09:32:30 -0500 Subject: Use python json module directly in place of simplejson As of Python 2.6, this is a builtin module that has all the same functions and capabilities of the Django simplejson module. Additionally simplejson is deprecated in the upcoming Django 1.5 release. Signed-off-by: Dan McGee --- packages/views/search.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index a09de0a7..a89822be 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -1,4 +1,5 @@ from datetime import datetime +import json from django import forms from django.contrib.admin.widgets import AdminDateWidget @@ -6,7 +7,6 @@ from django.contrib.auth.models import User from django.db.models import Q from django.http import HttpResponse from django.views.generic import list_detail -from django.utils import simplejson from main.models import Package, Arch, Repo from main.utils import make_choice @@ -179,8 +179,7 @@ def search_json(request): container['results'] = packages container['valid'] = True - to_json = simplejson.dumps(container, ensure_ascii=False, - cls=PackageJSONEncoder) + to_json = json.dumps(container, ensure_ascii=False, cls=PackageJSONEncoder) return HttpResponse(to_json, mimetype='application/json') # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From 24b28a504cabcf077882aa95cfa0edbc6a8d4569 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 24 Jul 2012 21:01:31 -0500 Subject: Replace deprecated list_detail usage in search with class-based view We can convert the entire search view to a generic class-based ListView. This is still one of the more disgusting views in the application and has a ton of logic scattered buckshot across several methods, but this commit is not meant to address all of that in one go. This is the last of the deprecated pieces I know of we are still using in the codebase, so we should be relatively safe in the long run now for an upgrade to the eventual next major Django release. Signed-off-by: Dan McGee --- packages/views/search.py | 77 ++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 38 deletions(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index a89822be..9750894a 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -6,7 +6,7 @@ from django.contrib.admin.widgets import AdminDateWidget from django.contrib.auth.models import User from django.db.models import Q from django.http import HttpResponse -from django.views.generic import list_detail +from django.views.generic import ListView from main.models import Package, Arch, Repo from main.utils import make_choice @@ -33,6 +33,7 @@ class LimitTypedChoiceField(forms.TypedChoiceField): except (ValueError, TypeError): return False + class PackageSearchForm(forms.Form): repo = forms.MultipleChoiceField(required=False) arch = forms.MultipleChoiceField(required=False) @@ -69,6 +70,7 @@ class PackageSearchForm(forms.Form): [('', 'All'), ('unknown', 'Unknown')] + \ [(m.username, m.get_full_name()) for m in maints] + def parse_form(form, packages): if form.cleaned_data['repo']: packages = packages.filter( @@ -117,48 +119,47 @@ def parse_form(form, packages): return packages -def search(request, page=None): - limit = 50 - sort = None - packages = Package.objects.normal() - if request.GET: - form = PackageSearchForm(data=request.GET) - if form.is_valid(): - packages = parse_form(form, packages) - asked_limit = form.cleaned_data['limit'] +class SearchListView(ListView): + template_name = "packages/search.html" + + sort_fields = ("arch", "repo", "pkgname", "pkgbase", "compressed_size", + "installed_size", "build_date", "last_update", "flag_date") + allowed_sort = list(sort_fields) + ["-" + s for s in sort_fields] + + def get(self, request, *args, **kwargs): + self.form = PackageSearchForm(data=request.GET) + return super(SearchListView, self).get(request, *args, **kwargs) + + def get_queryset(self): + packages = Package.objects.normal() + if self.form.is_valid(): + packages = parse_form(self.form, packages) + sort = self.form.cleaned_data['sort'] + if sort in self.allowed_sort: + packages = packages.order_by(sort) + else: + packages = packages.order_by('pkgname') + return packages + + # Form had errors so don't return any results + return Package.objects.none() + + def get_paginate_by(self, queryset): + limit = 50 + if self.form.is_valid(): + asked_limit = self.form.cleaned_data['limit'] if asked_limit and asked_limit < 0: limit = None elif asked_limit: limit = asked_limit - sort = form.cleaned_data['sort'] - else: - # Form had errors, don't return any results, just the busted form - packages = Package.objects.none() - else: - form = PackageSearchForm() - - current_query = request.GET.urlencode() - page_dict = { - 'search_form': form, - 'current_query': current_query - } - allowed_sort = ["arch", "repo", "pkgname", "pkgbase", - "compressed_size", "installed_size", - "build_date", "last_update", "flag_date"] - allowed_sort += ["-" + s for s in allowed_sort] - if sort in allowed_sort: - packages = packages.order_by(sort) - page_dict['sort'] = sort - else: - packages = packages.order_by('pkgname') - - return list_detail.object_list(request, packages, - template_name="packages/search.html", - page=page, - paginate_by=limit, - template_object_name="package", - extra_context=page_dict) + return limit + + def get_context_data(self, **kwargs): + context = super(SearchListView, self).get_context_data(**kwargs) + context['current_query'] = self.request.GET.urlencode() + context['search_form'] = self.form + return context def search_json(request): -- cgit v1.2.3-2-g168b From 4ad43fd8165834b26914ff8ba0666ce96267205b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 31 Jul 2012 00:25:19 -0500 Subject: Fix broken hidden input sort field on search form Signed-off-by: Dan McGee --- packages/views/search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index 9750894a..497d9bca 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -40,7 +40,7 @@ class PackageSearchForm(forms.Form): name = forms.CharField(required=False) desc = forms.CharField(required=False) q = forms.CharField(required=False) - sort = forms.CharField(required=False) + sort = forms.CharField(required=False, widget=forms.HiddenInput()) maintainer = forms.ChoiceField(required=False) packager = forms.ChoiceField(required=False) last_update = forms.DateField(required=False, widget=AdminDateWidget(), -- cgit v1.2.3-2-g168b From 7a0e6620c9c8782fbef37db15afc3ccebc642d19 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 25 Sep 2012 18:22:16 -0500 Subject: Don't show staging in package search repo listing This is temporary or at least a quick way to ensure regular users aren't confused by staging packages; later updates should re-enable display of this for logged in developers and trusted users. Signed-off-by: Dan McGee --- packages/views/search.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index 497d9bca..1fbe5694 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -56,8 +56,9 @@ class PackageSearchForm(forms.Form): def __init__(self, *args, **kwargs): super(PackageSearchForm, self).__init__(*args, **kwargs) + repos = Repo.objects.filter(staging=False) self.fields['repo'].choices = make_choice( - [repo.name for repo in Repo.objects.all()]) + [repo.name for repo in repos]) self.fields['arch'].choices = make_choice( [arch.name for arch in Arch.objects.all()]) self.fields['q'].widget.attrs.update({"size": "30"}) -- cgit v1.2.3-2-g168b From 44dc458a2b8ca500acda72b437a720dd4f57bedf Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 30 Sep 2012 01:40:25 -0500 Subject: Hide staging packages in search results This is for users that aren't logged in; developers will still see them. Signed-off-by: Dan McGee --- packages/views/search.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index 1fbe5694..99bf703a 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -55,8 +55,11 @@ class PackageSearchForm(forms.Form): initial=50) def __init__(self, *args, **kwargs): + show_staging = kwargs.pop('show_staging', False) super(PackageSearchForm, self).__init__(*args, **kwargs) - repos = Repo.objects.filter(staging=False) + repos = Repo.objects.all() + if not show_staging: + repos = repos.filter(staging=False) self.fields['repo'].choices = make_choice( [repo.name for repo in repos]) self.fields['arch'].choices = make_choice( @@ -129,11 +132,14 @@ class SearchListView(ListView): allowed_sort = list(sort_fields) + ["-" + s for s in sort_fields] def get(self, request, *args, **kwargs): - self.form = PackageSearchForm(data=request.GET) + self.form = PackageSearchForm(data=request.GET, + show_staging=self.request.user.is_authenticated()) return super(SearchListView, self).get(request, *args, **kwargs) def get_queryset(self): packages = Package.objects.normal() + if not self.request.user.is_authenticated(): + packages = packages.filter(repo__staging=False) if self.form.is_valid(): packages = parse_form(self.form, packages) sort = self.form.cleaned_data['sort'] @@ -174,9 +180,12 @@ def search_json(request): } if request.GET: - form = PackageSearchForm(data=request.GET) + form = PackageSearchForm(data=request.GET, + show_staging=request.user.is_authenticated()) if form.is_valid(): packages = Package.objects.normal() + if not request.user.is_authenticated(): + packages = packages.filter(repo__staging=False) packages = parse_form(form, packages)[:limit] container['results'] = packages container['valid'] = True -- cgit v1.2.3-2-g168b From feabc12d384a448614dbc8a9a51cd39ee63b4a83 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 30 Sep 2012 10:11:19 -0500 Subject: =?UTF-8?q?Fix=20usage=20of=20na=C3=AFve=20datetime=20object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Dan McGee --- packages/views/search.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index 99bf703a..f7b8ed1d 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -1,5 +1,6 @@ from datetime import datetime import json +from pytz import utc from django import forms from django.contrib.admin.widgets import AdminDateWidget @@ -105,8 +106,9 @@ def parse_form(form, packages): if form.cleaned_data['last_update']: lu = form.cleaned_data['last_update'] - packages = packages.filter(last_update__gte= - datetime(lu.year, lu.month, lu.day, 0, 0)) + cutoff = datetime(lu.year, lu.month, lu.day, 0, 0) + cutoff = cutoff.replace(tzinfo=utc) + packages = packages.filter(last_update__gte=cutoff) if form.cleaned_data['name']: name = form.cleaned_data['name'] -- cgit v1.2.3-2-g168b From 2bfdcec869ed4fceb11b9e0a2777fa53d46fb336 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 12 Jan 2013 16:47:20 -0600 Subject: Make packages JSON search more performant We were peppering the database with a bunch of queries here; using prefetch_related and attach_maintainers can cut down the count significantly. Signed-off-by: Dan McGee --- packages/views/search.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index f7b8ed1d..f6e670df 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -12,7 +12,7 @@ from django.views.generic import ListView from main.models import Package, Arch, Repo from main.utils import make_choice from ..models import PackageRelation -from ..utils import PackageJSONEncoder +from ..utils import attach_maintainers, PackageJSONEncoder def coerce_limit_value(value): @@ -185,10 +185,14 @@ def search_json(request): form = PackageSearchForm(data=request.GET, show_staging=request.user.is_authenticated()) if form.is_valid(): - packages = Package.objects.normal() + packages = Package.objects.select_related('arch', 'repo', + 'packager') if not request.user.is_authenticated(): packages = packages.filter(repo__staging=False) packages = parse_form(form, packages)[:limit] + packages = packages.prefetch_related('groups', 'licenses', + 'conflicts', 'provides', 'replaces', 'depends') + attach_maintainers(packages) container['results'] = packages container['valid'] = True -- cgit v1.2.3-2-g168b From 66850026ca934e5a09238e9033c541cdc5085a42 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 13 Jan 2013 22:34:33 -0600 Subject: Use content_type and not mimetype on HttpResponse() Bug #16519 in Django deprecates mimetype, so update our code accordingly. Signed-off-by: Dan McGee --- packages/views/search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index f6e670df..0f313ccb 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -197,6 +197,6 @@ def search_json(request): container['valid'] = True to_json = json.dumps(container, ensure_ascii=False, cls=PackageJSONEncoder) - return HttpResponse(to_json, mimetype='application/json') + return HttpResponse(to_json, content_type='application/json') # vim: set ts=4 sw=4 et: -- cgit v1.2.3-2-g168b From e65c7805547484cad1be55dfa20355ef18b857be Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 8 Feb 2013 21:09:47 -0600 Subject: Remove package seach by 'Last Updated After' It is a lot easier to just sort the list rather than mess with this particular field, which didn't even allow you to specify a range or direction to search in. Signed-off-by: Dan McGee --- packages/views/search.py | 9 --------- 1 file changed, 9 deletions(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index 0f313ccb..9cb5f38d 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -3,7 +3,6 @@ import json from pytz import utc from django import forms -from django.contrib.admin.widgets import AdminDateWidget from django.contrib.auth.models import User from django.db.models import Q from django.http import HttpResponse @@ -44,8 +43,6 @@ class PackageSearchForm(forms.Form): sort = forms.CharField(required=False, widget=forms.HiddenInput()) maintainer = forms.ChoiceField(required=False) packager = forms.ChoiceField(required=False) - last_update = forms.DateField(required=False, widget=AdminDateWidget(), - label='Last Updated After') flagged = forms.ChoiceField( choices=[('', 'All')] + make_choice(['Flagged', 'Not Flagged']), required=False) @@ -104,12 +101,6 @@ def parse_form(form, packages): elif form.cleaned_data['flagged'] == 'Not Flagged': packages = packages.filter(flag_date__isnull=True) - if form.cleaned_data['last_update']: - lu = form.cleaned_data['last_update'] - cutoff = datetime(lu.year, lu.month, lu.day, 0, 0) - cutoff = cutoff.replace(tzinfo=utc) - packages = packages.filter(last_update__gte=cutoff) - if form.cleaned_data['name']: name = form.cleaned_data['name'] packages = packages.filter(pkgname=name) -- cgit v1.2.3-2-g168b From e3837b5a872b6203b7ae338bc8075b339e031627 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 16 Feb 2013 15:23:49 -0600 Subject: Remove configurable pagination for package search Switch it to a hardcoded value of 100 for all searches instead. It didn't make much sense having a page number be part of the URL and a limit value being part of the query string. Signed-off-by: Dan McGee --- packages/views/search.py | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index 9cb5f38d..9ca299f6 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -1,6 +1,4 @@ -from datetime import datetime import json -from pytz import utc from django import forms from django.contrib.auth.models import User @@ -14,26 +12,6 @@ from ..models import PackageRelation from ..utils import attach_maintainers, PackageJSONEncoder -def coerce_limit_value(value): - if not value: - return None - if value == 'all': - # negative value indicates show all results - return -1 - value = int(value) - if value < 0: - raise ValueError - return value - -class LimitTypedChoiceField(forms.TypedChoiceField): - def valid_value(self, value): - try: - coerce_limit_value(value) - return True - except (ValueError, TypeError): - return False - - class PackageSearchForm(forms.Form): repo = forms.MultipleChoiceField(required=False) arch = forms.MultipleChoiceField(required=False) @@ -46,11 +24,6 @@ class PackageSearchForm(forms.Form): flagged = forms.ChoiceField( choices=[('', 'All')] + make_choice(['Flagged', 'Not Flagged']), required=False) - limit = LimitTypedChoiceField( - choices=make_choice([50, 100, 250]) + [('all', 'All')], - coerce=coerce_limit_value, - required=False, - initial=50) def __init__(self, *args, **kwargs): show_staging = kwargs.pop('show_staging', False) @@ -119,6 +92,7 @@ def parse_form(form, packages): class SearchListView(ListView): template_name = "packages/search.html" + paginate_by = 100 sort_fields = ("arch", "repo", "pkgname", "pkgbase", "compressed_size", "installed_size", "build_date", "last_update", "flag_date") @@ -145,16 +119,6 @@ class SearchListView(ListView): # Form had errors so don't return any results return Package.objects.none() - def get_paginate_by(self, queryset): - limit = 50 - if self.form.is_valid(): - asked_limit = self.form.cleaned_data['limit'] - if asked_limit and asked_limit < 0: - limit = None - elif asked_limit: - limit = asked_limit - return limit - def get_context_data(self, **kwargs): context = super(SearchListView, self).get_context_data(**kwargs) context['current_query'] = self.request.GET.urlencode() -- cgit v1.2.3-2-g168b From 0491bdb2452e496b0a243e7abb3d15ef3fd71743 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 20 Feb 2013 00:19:12 -0600 Subject: Fix some fallout with moving page to query params Signed-off-by: Dan McGee --- packages/views/search.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'packages/views/search.py') diff --git a/packages/views/search.py b/packages/views/search.py index 9ca299f6..0362602e 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -121,7 +121,9 @@ class SearchListView(ListView): def get_context_data(self, **kwargs): context = super(SearchListView, self).get_context_data(**kwargs) - context['current_query'] = self.request.GET.urlencode() + query_params = self.request.GET.copy() + query_params.pop('page', None) + context['current_query'] = query_params.urlencode() context['search_form'] = self.form return context -- cgit v1.2.3-2-g168b