Merge lp:~zematynnad/ubuntu-webcatalog/duplicates_987826 into lp:ubuntu-webcatalog

Proposed by Danny Tamez
Status: Merged
Approved by: Anthony Lenton
Approved revision: 127
Merged at revision: 122
Proposed branch: lp:~zematynnad/ubuntu-webcatalog/duplicates_987826
Merge into: lp:ubuntu-webcatalog
Diff against target: 93 lines (+41/-10)
2 files modified
src/webcatalog/tests/test_views.py (+26/-5)
src/webcatalog/views.py (+15/-5)
To merge this branch: bzr merge lp:~zematynnad/ubuntu-webcatalog/duplicates_987826
Reviewer Review Type Date Requested Status
Anthony Lenton (community) Approve
Review via email: mp+107091@code.launchpad.net

Commit message

Removes duplicate apps from top rated apps widget.

Description of the change

Overview
=========
This branch is a fix for http://pad.lv/987826 where duplicate apps were showing up in the top rated apps carousel.

Details
========
The problem was that apps for the same package but for different distroseries were being returned in the query. Since django doesn't do distinct on individual fields (at least not without a patch) the duplicates have to be filtered out a different way. I just used a dictionary with the packagename as the key to avoid the duplicates.

To Test
========
$fab bootstrap test

To post a comment you must log in.
Revision history for this message
Anthony Lenton (elachuni) wrote :

Hi Danny,

I really don't think the code is doing what we want there. Comments about the changes in src/webcatalog/views.py:
 - You iterate over all of top_rated_apps (tens of thousands of apps) to keep just the first settings.NUMBER_TOP_RATED_APPS off the filtered list (tens of apps). See if there's a way to only filter enough apps as we need.
 - For each package name you currently keep the last item on the list that matches the name (as the dict is overridden each time you find a new Application instance with the same package name), so I you're effectively keeping the *lowest* rated app instance for each package name.
 - Finally, you're storing the apps in a dict and then asking for values(), so you can't expect any order in top_rated_apps.
 - And, something really minor, Count is being imported unnecessarily.

Kind regards,

achuni.

review: Needs Fixing
126. By Danny Tamez

Remove unused import.
Ensure that as few rows as necessary are iterated on.
Ensure that order is preserved in final result.

127. By Danny Tamez

Refactor to filter as few as needed.

Revision history for this message
Anthony Lenton (elachuni) wrote :

Thanks Danny!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/webcatalog/tests/test_views.py'
2--- src/webcatalog/tests/test_views.py 2012-05-08 07:03:56 +0000
3+++ src/webcatalog/tests/test_views.py 2012-05-23 22:34:23 +0000
4@@ -697,13 +697,17 @@
5 for link in links:
6 self.assertContains(response, link)
7
8- def make_high_medium_and_low_apps(self):
9+ def make_high_medium_and_low_apps(self, score_high=5.0, score_mid=4.0,
10+ score_low=1.0):
11 high = self.factory.make_application(package_name='high',
12- wilson_score=5.0, ratings_average=5, ratings_total=500)
13+ wilson_score=score_high, ratings_average=5,
14+ ratings_total=500)
15 mid = self.factory.make_application(package_name='mid',
16- wilson_score=4.0, ratings_average=4, ratings_total=400)
17+ wilson_score=score_mid, ratings_average=4,
18+ ratings_total=400)
19 low = self.factory.make_application(package_name='low',
20- wilson_score=1.0, ratings_average=1, ratings_total=100)
21+ wilson_score=score_low, ratings_average=1,
22+ ratings_total=100)
23 return (high, mid, low)
24
25 def test_top_rated_apps_in_response(self):
26@@ -712,7 +716,7 @@
27 with patch_settings(NUMBER_TOP_RATED_APPS=1):
28 response = self.client.get(reverse('wc-index'))
29
30- self.assertEqual(1, response.context[0]['top_rated_apps'].count())
31+ self.assertEqual(1, len(response.context[0]['top_rated_apps']))
32 self.assertEqual(high, response.context[0]['top_rated_apps'][0])
33
34 def test_top_rated_apps_display_correctly(self):
35@@ -746,6 +750,23 @@
36 self.assertContains(response, expected, 2)
37 self.assertNotContains(response, app_not_included.package_name)
38
39+ def test_top_rated_apps_does_not_include_duplicate_packages(self):
40+ high, mid, low = self.make_high_medium_and_low_apps(5.0, 4.0, 1.0)
41+ high2, mid2, low2 = self.make_high_medium_and_low_apps(4.8, 3.8, 0.8)
42+ high3, mid3, low3 = self.make_high_medium_and_low_apps(4.6, 3.6, 0.6)
43+ high4, mid4, low4 = self.make_high_medium_and_low_apps(4.4, 3.4, 0.4)
44+
45+ with patch_settings(NUMBER_TOP_RATED_APPS=4):
46+ response = self.client.get(reverse('wc-index'))
47+
48+ apps = response.context['top_rated_apps']
49+ # should have only first high, first mid and first low
50+ # and in that order
51+ self.assertEqual(len(apps), 3)
52+ self.assertEqual(apps[0], high)
53+ self.assertEqual(apps[1], mid)
54+ self.assertEqual(apps[2], low)
55+
56 def test_includes_cache_headers(self):
57 with patch_settings(CACHE_MIDDLEWARE_SECONDS=600):
58 response = self.client.get(reverse('wc-index'))
59
60=== modified file 'src/webcatalog/views.py'
61--- src/webcatalog/views.py 2012-05-08 07:03:56 +0000
62+++ src/webcatalog/views.py 2012-05-23 22:34:23 +0000
63@@ -116,15 +116,25 @@
64 featured_apps = [Application.objects.find_best(package_name=app)
65 for app in settings.FEATURED_APPS]
66 featured_apps = [x for x in featured_apps if x]
67- top_rated_apps = (Application.objects.filter(wilson_score__gt=0)
68- .order_by('-wilson_score'))
69- num = settings.NUMBER_TOP_RATED_APPS
70- top_rated_apps = top_rated_apps[:num]
71+ apps = (Application.objects.filter(wilson_score__gt=0)
72+ .order_by('-wilson_score'))
73+ # filter out apps that are top rated more than once because
74+ # of different distroseries
75+
76+ seen = set()
77+ top_rated = []
78+ for app in apps:
79+ if not app.package_name in seen:
80+ top_rated.append(app)
81+ seen.add(app.package_name)
82+ if len(top_rated) == settings.NUMBER_TOP_RATED_APPS:
83+ break
84+
85 context = RequestContext(request, dict={
86 'depts': depts,
87 'exhibits': exhibits,
88 'featured_apps': featured_apps,
89- 'top_rated_apps': top_rated_apps,
90+ 'top_rated_apps': top_rated,
91 })
92 return render_to_response('webcatalog/index.html',
93 context_instance=context)

Subscribers

People subscribed via source and target branches