From d674b674a27de65bdb64980240795041fc503b63 Mon Sep 17 00:00:00 2001 From: Drew Winstel Date: Fri, 9 Aug 2019 20:58:34 -0500 Subject: [PATCH 1/3] Make tap admin list look prettier (#229) Fixes #215. --- taps/admin.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/taps/admin.py b/taps/admin.py index 78e54492..529d3958 100644 --- a/taps/admin.py +++ b/taps/admin.py @@ -2,4 +2,13 @@ from . import models -admin.site.register(models.Tap) + +class TapAdmin(admin.ModelAdmin): + + list_display = ('tap_number', 'venue', 'beer', 'id') + list_filter = ('venue', ) + list_select_related = ('venue', 'beer') + search_fields = ('beer__name', 'venue__name', 'beer__manufacturer__name') + + +admin.site.register(models.Tap, TapAdmin) From cf3fdfa8d53054971d71c6f0f5b04af32f7e2b0d Mon Sep 17 00:00:00 2001 From: Drew Winstel Date: Mon, 12 Aug 2019 16:28:46 -0500 Subject: [PATCH 2/3] Propagate venue deletions to BeerPrice instances (#232) That way when a venue closes, we don't have to manually delete pricing info. Fixes #231 --- beers/migrations/0030_auto_20190807_2142.py | 19 +++++++++++++++++++ beers/models.py | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 beers/migrations/0030_auto_20190807_2142.py diff --git a/beers/migrations/0030_auto_20190807_2142.py b/beers/migrations/0030_auto_20190807_2142.py new file mode 100644 index 00000000..b34c7922 --- /dev/null +++ b/beers/migrations/0030_auto_20190807_2142.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-08-07 21:42 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('beers', '0029_merge_20190519_1259'), + ] + + operations = [ + migrations.AlterField( + model_name='beerprice', + name='venue', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='beer_prices', to='venues.Venue'), + ), + ] diff --git a/beers/models.py b/beers/models.py index 457eadc3..f9794cbc 100644 --- a/beers/models.py +++ b/beers/models.py @@ -273,7 +273,7 @@ def __str__(self): class BeerPrice(models.Model): beer = models.ForeignKey(Beer, models.CASCADE, related_name='prices') venue = models.ForeignKey( - 'venues.Venue', models.DO_NOTHING, related_name='beer_prices', + 'venues.Venue', models.CASCADE, related_name='beer_prices', ) serving_size = models.ForeignKey( ServingSize, models.DO_NOTHING, related_name='beer_prices', From 575845b4eff012d338a6735b6198e9fb67fe6a30 Mon Sep 17 00:00:00 2001 From: Drew Winstel Date: Tue, 13 Aug 2019 21:09:05 -0500 Subject: [PATCH 3/3] Enable sort by recently tapped (#198) * Add ability to sort beers by most recently added to a tap This looks across *all* taps, so depending on how STA handles changing kegs, this might make Monkeynaut always seem new. * Validate that we don't add extra queries with the annotation --- beers/filters.py | 1 + beers/test/test_views.py | 31 +++++++++++++++++++++++++++++++ beers/views.py | 4 +++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/beers/filters.py b/beers/filters.py index 11e1b184..ebb23353 100644 --- a/beers/filters.py +++ b/beers/filters.py @@ -21,6 +21,7 @@ class BeerFilterSet(FilterSet): fields=[ 'name', 'abv', 'ibu', 'style__name', 'style__alternate_names__name', 'manufacturer__name', + 'most_recently_added', ], ) diff --git a/beers/test/test_views.py b/beers/test/test_views.py index 2dc00414..508809ed 100644 --- a/beers/test/test_views.py +++ b/beers/test/test_views.py @@ -1,3 +1,5 @@ +from dateutil.relativedelta import relativedelta +from django.utils.timezone import now from django.urls import reverse from nose.tools import eq_ from rest_framework.test import APITestCase @@ -161,3 +163,32 @@ def test_on_tap_no_dupes(self): eq_(response.status_code, 200) eq_(len(response.data['results']), 1, response.data) eq_(response.data['results'][0]['name'], self.beer.name, response.data) + + def test_sort_by_time_added(self): + # create a tap for a second beer in between the two + other_beer = BeerFactory() + TapFactory( + beer=other_beer, + time_added=now() - relativedelta(hours=5, minutes=2), + ) + # create another beer on tap with no time added, so therefore it's now + third_beer = TapFactory(beer=BeerFactory()).beer + + # create two taps for the first beer + TapFactory(beer=self.beer, time_added=now() - relativedelta(hours=1)) + TapFactory(beer=self.beer, time_added=now() - relativedelta(hours=16)) + + # 5 queries: + # 1. count of results + # 2. beers + # 3. taps + # 4. alt names + # 5. prices + with self.assertNumQueries(5): + response = self.client.get(f'{self.url}?o=-most_recently_added') + eq_(response.status_code, 200) + # expected order is third_beer, self.beer, other_beer + eq_(len(response.data['results']), 3, response.data) + eq_(response.data['results'][0]['name'], third_beer.name, response.data) + eq_(response.data['results'][1]['name'], self.beer.name, response.data) + eq_(response.data['results'][2]['name'], other_beer.name, response.data) diff --git a/beers/views.py b/beers/views.py index 7a579160..a3079303 100644 --- a/beers/views.py +++ b/beers/views.py @@ -1,7 +1,7 @@ from django.db import transaction from django.db.utils import IntegrityError -from django.db.models import Prefetch, Count +from django.db.models import Prefetch, Count, Max from django.http import HttpResponse from django.shortcuts import redirect from django.urls import reverse @@ -73,6 +73,8 @@ class BeerViewSet(CachedListMixin, ModerationMixin, ModelViewSet): 'venue', 'serving_size', ) ), + ).annotate( + most_recently_added=Max('taps__time_added'), ).order_by('manufacturer__name', 'name') filterset_class = filters.BeerFilterSet