Ticket #18217: 18217-backport.patch

File 18217-backport.patch, 23.5 KB (added by Aymeric Augustin, 13 years ago)
  • django/views/generic/dates.py

    diff --git a/django/views/generic/dates.py b/django/views/generic/dates.py
    index 5f5f959..8eb5b0a 100644
    a b  
    11import datetime
     2from django.conf import settings
    23from django.db import models
    34from django.core.exceptions import ImproperlyConfigured
    45from django.http import Http404
    56from django.utils.encoding import force_unicode
     7from django.utils.functional import cached_property
    68from django.utils.translation import ugettext as _
    79from django.utils import timezone
    810from django.views.generic.base import View
    class DateMixin(object):  
    161163        """
    162164        return self.allow_future
    163165
     166    # Note: the following three methods only work in subclasses that also
     167    # inherit SingleObjectMixin or MultipleObjectMixin.
     168
     169    @cached_property
     170    def uses_datetime_field(self):
     171        """
     172        Return `True` if the date field is a `DateTimeField` and `False`
     173        if it's a `DateField`.
     174        """
     175        model = self.get_queryset().model if self.model is None else self.model
     176        field = model._meta.get_field(self.get_date_field())
     177        return isinstance(field, models.DateTimeField)
     178
     179    def _make_date_lookup_arg(self, value):
     180        """
     181        Convert a date into a datetime when the date field is a DateTimeField.
     182
     183        When time zone support is enabled, `date` is assumed to be in the
     184        current time zone, so that displayed items are consistent with the URL.
     185        """
     186        if self.uses_datetime_field:
     187            value = datetime.datetime.combine(value, datetime.time.min)
     188            if settings.USE_TZ:
     189                value = timezone.make_aware(value, timezone.get_current_timezone())
     190        return value
     191
     192    def _make_single_date_lookup(self, date):
     193        """
     194        Get the lookup kwargs for filtering on a single date.
     195
     196        If the date field is a DateTimeField, we can't just filter on
     197        date_field=date because that doesn't take the time into account.
     198        """
     199        date_field = self.get_date_field()
     200        if self.uses_datetime_field:
     201            since = self._make_date_lookup_arg(date)
     202            until = self._make_date_lookup_arg(date + datetime.timedelta(days=1))
     203            return {
     204                '%s__gte' % date_field: since,
     205                '%s__lt' % date_field: until,
     206            }
     207        else:
     208            # Skip self._make_date_lookup_arg, it's a no-op in this branch.
     209            return {date_field: date}
     210
    164211
    165212class BaseDateListView(MultipleObjectMixin, DateMixin, View):
    166213    """
    class BaseDateListView(MultipleObjectMixin, DateMixin, View):  
    177224
    178225    def get_dated_items(self):
    179226        """
    180         Obtain the list of dates and itesm
     227        Obtain the list of dates and items.
    181228        """
    182229        raise NotImplementedError('A DateView must provide an implementation of get_dated_items()')
    183230
    class BaseDateListView(MultipleObjectMixin, DateMixin, View):  
    192239        allow_empty = self.get_allow_empty()
    193240
    194241        if not allow_future:
    195             qs = qs.filter(**{'%s__lte' % date_field: timezone.now()})
     242            now = timezone.now() if self.uses_datetime_field else datetime.date.today()
     243            qs = qs.filter(**{'%s__lte' % date_field: now})
    196244
    197245        if not allow_empty and not qs:
    198246            raise Http404(_(u"No %(verbose_name_plural)s available") % {
    class BaseYearArchiveView(YearMixin, BaseDateListView):  
    267315        """
    268316        Return (date_list, items, extra_context) for this request.
    269317        """
    270         # Yes, no error checking: the URLpattern ought to validate this; it's
    271         # an error if it doesn't.
    272318        year = self.get_year()
     319
    273320        date_field = self.get_date_field()
    274         qs = self.get_dated_queryset(**{date_field+'__year': year})
     321        date = _date_from_string(year, self.get_year_format())
     322
     323        since = self._make_date_lookup_arg(date)
     324        until = self._make_date_lookup_arg(datetime.date(date.year + 1, 1, 1))
     325        lookup_kwargs = {
     326            '%s__gte' % date_field: since,
     327            '%s__lt' % date_field: until,
     328        }
     329
     330        qs = self.get_dated_queryset(**lookup_kwargs)
    275331        date_list = self.get_date_list(qs, 'month')
    276332
    277333        if self.get_make_object_list():
    278             object_list = qs.order_by('-'+date_field)
     334            object_list = qs.order_by('-' + date_field)
    279335        else:
    280336            # We need this to be a queryset since parent classes introspect it
    281337            # to find information about the model.
    class BaseMonthArchiveView(YearMixin, MonthMixin, BaseDateListView):  
    314370                                 month, self.get_month_format())
    315371
    316372        # Construct a date-range lookup.
    317         first_day, last_day = _month_bounds(date)
     373        since = self._make_date_lookup_arg(date)
     374        if date.month == 12:
     375            until = self._make_date_lookup_arg(datetime.date(date.year + 1, 1, 1))
     376        else:
     377            until = self._make_date_lookup_arg(datetime.date(date.year, date.month + 1, 1))
    318378        lookup_kwargs = {
    319             '%s__gte' % date_field: first_day,
    320             '%s__lt' % date_field: last_day,
     379            '%s__gte' % date_field: since,
     380            '%s__lt' % date_field: until,
    321381        }
    322382
    323383        qs = self.get_dated_queryset(**lookup_kwargs)
    class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView):  
    360420                                 week, week_format)
    361421
    362422        # Construct a date-range lookup.
    363         first_day = date
    364         last_day = date + datetime.timedelta(days=7)
     423        since = self._make_date_lookup_arg(date)
     424        until = self._make_date_lookup_arg(date + datetime.timedelta(days=7))
    365425        lookup_kwargs = {
    366             '%s__gte' % date_field: first_day,
    367             '%s__lt' % date_field: last_day,
     426            '%s__gte' % date_field: since,
     427            '%s__lt' % date_field: until,
    368428        }
    369429
    370430        qs = self.get_dated_queryset(**lookup_kwargs)
    class BaseDayArchiveView(YearMixin, MonthMixin, DayMixin, BaseDateListView):  
    402462        Do the actual heavy lifting of getting the dated items; this accepts a
    403463        date object so that TodayArchiveView can be trivial.
    404464        """
    405         date_field = self.get_date_field()
    406 
    407         field = self.get_queryset().model._meta.get_field(date_field)
    408         lookup_kwargs = _date_lookup_for_field(field, date)
    409 
     465        lookup_kwargs = self._make_single_date_lookup(date)
    410466        qs = self.get_dated_queryset(**lookup_kwargs)
    411467
    412468        return (None, qs, {
    class BaseDateDetailView(YearMixin, MonthMixin, DayMixin, DateMixin, BaseDetailV  
    472528        # Filter down a queryset from self.queryset using the date from the
    473529        # URL. This'll get passed as the queryset to DetailView.get_object,
    474530        # which'll handle the 404
    475         date_field = self.get_date_field()
    476         field = qs.model._meta.get_field(date_field)
    477         lookup = _date_lookup_for_field(field, date)
    478         qs = qs.filter(**lookup)
     531        lookup_kwargs = self._make_single_date_lookup(date)
     532        qs = qs.filter(**lookup_kwargs)
    479533
    480534        return super(BaseDetailView, self).get_object(queryset=qs)
    481535
    class DateDetailView(SingleObjectTemplateResponseMixin, BaseDateDetailView):  
    488542    template_name_suffix = '_detail'
    489543
    490544
    491 def _date_from_string(year, year_format, month, month_format, day='', day_format='', delim='__'):
     545def _date_from_string(year, year_format, month='', month_format='', day='', day_format='', delim='__'):
    492546    """
    493547    Helper: get a datetime.date object given a format string and a year,
    494     month, and possibly day; raise a 404 for an invalid date.
     548    month, and day (only year is mandatory). Raise a 404 for an invalid date.
    495549    """
    496550    format = delim.join((year_format, month_format, day_format))
    497551    datestr = delim.join((year, month, day))
    def _get_next_prev_month(generic_view, naive_result, is_previous, use_first_day)  
    559613        # Construct a lookup and an ordering depending on whether we're doing
    560614        # a previous date or a next date lookup.
    561615        if is_previous:
    562             lookup = {'%s__lte' % date_field: naive_result}
     616            lookup = {'%s__lte' % date_field: generic_view._make_date_lookup_arg(naive_result)}
    563617            ordering = '-%s' % date_field
    564618        else:
    565             lookup = {'%s__gte' % date_field: naive_result}
     619            lookup = {'%s__gte' % date_field: generic_view._make_date_lookup_arg(naive_result)}
    566620            ordering = date_field
    567621
    568622        qs = generic_view.get_queryset().filter(**lookup).order_by(ordering)
    def _get_next_prev_month(generic_view, naive_result, is_previous, use_first_day)  
    575629            result = None
    576630
    577631    # Convert datetimes to a dates
    578     if hasattr(result, 'date'):
     632    if result and generic_view.uses_datetime_field:
     633        if settings.USE_TZ:
     634            result = timezone.localtime(result)
    579635        result = result.date()
    580636
    581637    # For month views, we always want to have a date that's the first of the
    def _get_next_prev_month(generic_view, naive_result, is_previous, use_first_day)  
    588644        return result
    589645    else:
    590646        return None
    591 
    592 
    593 def _date_lookup_for_field(field, date):
    594     """
    595     Get the lookup kwargs for looking up a date against a given Field. If the
    596     date field is a DateTimeField, we can't just do filter(df=date) because
    597     that doesn't take the time into account. So we need to make a range lookup
    598     in those cases.
    599     """
    600     if isinstance(field, models.DateTimeField):
    601         date_range = (
    602             datetime.datetime.combine(date, datetime.time.min),
    603             datetime.datetime.combine(date, datetime.time.max)
    604         )
    605         return {'%s__range' % field.name: date_range}
    606     else:
    607         return {field.name: date}
  • docs/ref/class-based-views.txt

    diff --git a/docs/ref/class-based-views.txt b/docs/ref/class-based-views.txt
    index 5223aee..0d4bdd6 100644
    a b DateMixin  
    752752        ``QuerySet``'s model that the date-based archive should use to
    753753        determine the objects on the page.
    754754
     755        When :doc:`time zone support </topics/i18n/timezones>` is enabled and
     756        ``date_field`` is a ``DateTimeField``, dates are assumed to be in the
     757        current time zone. As a consequence, if you have implemented per-user
     758        time zone selection, users living in different time zones may view a
     759        different set of objects at the same URL.
     760
    755761    .. attribute:: allow_future
    756762
    757763        A boolean specifying whether to include "future" objects on this page,
  • tests/regressiontests/generic_views/dates.py

    diff --git a/tests/regressiontests/generic_views/dates.py b/tests/regressiontests/generic_views/dates.py
    index 652f66b..1c02056 100644
    a b import datetime  
    44
    55from django.core.exceptions import ImproperlyConfigured
    66from django.test import TestCase
     7from django.test.utils import override_settings
     8from django.utils import timezone
     9
     10from .models import Book, BookSigning
     11
     12
     13import warnings
     14warnings.filterwarnings(
     15        'error', r"DateTimeField received a naive datetime",
     16        RuntimeWarning, r'django\.db\.models\.fields')
     17
    718
    8 from .models import Book
    919
    1020
    1121class ArchiveIndexViewTests(TestCase):
    class ArchiveIndexViewTests(TestCase):  
    7989        self.assertEqual(list(res.context['latest']), list(Book.objects.all()[10:20]))
    8090
    8191
     92    def test_datetime_archive_view(self):
     93        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
     94        res = self.client.get('/dates/booksignings/')
     95        self.assertEqual(res.status_code, 200)
     96
     97    @override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
     98    def test_aware_datetime_archive_view(self):
     99        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
     100        res = self.client.get('/dates/booksignings/')
     101        self.assertEqual(res.status_code, 200)
     102
     103
    82104class YearArchiveViewTests(TestCase):
    83105    fixtures = ['generic-views-test-data.json']
    84106    urls = 'regressiontests.generic_views.urls'
    class YearArchiveViewTests(TestCase):  
    132154        res = self.client.get('/dates/books/no_year/')
    133155        self.assertEqual(res.status_code, 404)
    134156
     157    def test_datetime_year_view(self):
     158        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
     159        res = self.client.get('/dates/booksignings/2008/')
     160        self.assertEqual(res.status_code, 200)
     161
     162    @override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
     163    def test_aware_datetime_year_view(self):
     164        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
     165        res = self.client.get('/dates/booksignings/2008/')
     166        self.assertEqual(res.status_code, 200)
     167
     168
    135169class MonthArchiveViewTests(TestCase):
    136170    fixtures = ['generic-views-test-data.json']
    137171    urls = 'regressiontests.generic_views.urls'
    class MonthArchiveViewTests(TestCase):  
    236270        self.assertEqual(res.status_code, 200)
    237271        self.assertEqual(res.context['previous_month'], datetime.date(2010,9,1))
    238272
     273    def test_datetime_month_view(self):
     274        BookSigning.objects.create(event_date=datetime.datetime(2008, 2, 1, 12, 0))
     275        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
     276        BookSigning.objects.create(event_date=datetime.datetime(2008, 6, 3, 12, 0))
     277        res = self.client.get('/dates/booksignings/2008/apr/')
     278        self.assertEqual(res.status_code, 200)
     279
     280    @override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
     281    def test_aware_datetime_month_view(self):
     282        BookSigning.objects.create(event_date=datetime.datetime(2008, 2, 1, 12, 0, tzinfo=timezone.utc))
     283        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
     284        BookSigning.objects.create(event_date=datetime.datetime(2008, 6, 3, 12, 0, tzinfo=timezone.utc))
     285        res = self.client.get('/dates/booksignings/2008/apr/')
     286        self.assertEqual(res.status_code, 200)
     287
    239288
    240289class WeekArchiveViewTests(TestCase):
    241290    fixtures = ['generic-views-test-data.json']
    class WeekArchiveViewTests(TestCase):  
    291340        self.assertEqual(res.status_code, 200)
    292341        self.assertEqual(res.context['week'], datetime.date(2008, 9, 29))
    293342
     343    def test_datetime_week_view(self):
     344        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
     345        res = self.client.get('/dates/booksignings/2008/week/13/')
     346        self.assertEqual(res.status_code, 200)
     347
     348    @override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
     349    def test_aware_datetime_week_view(self):
     350        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
     351        res = self.client.get('/dates/booksignings/2008/week/13/')
     352        self.assertEqual(res.status_code, 200)
     353
     354
    294355class DayArchiveViewTests(TestCase):
    295356    fixtures = ['generic-views-test-data.json']
    296357    urls = 'regressiontests.generic_views.urls'
    class DayArchiveViewTests(TestCase):  
    379440        self.assertEqual(res.status_code, 200)
    380441        self.assertEqual(res.context['day'], datetime.date.today())
    381442
     443    def test_datetime_day_view(self):
     444        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
     445        res = self.client.get('/dates/booksignings/2008/apr/2/')
     446        self.assertEqual(res.status_code, 200)
     447
     448    @override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
     449    def test_aware_datetime_day_view(self):
     450        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
     451        res = self.client.get('/dates/booksignings/2008/apr/2/')
     452        self.assertEqual(res.status_code, 200)
     453        # 2008-04-02T00:00:00+03:00 (beginning of day) > 2008-04-01T22:00:00+00:00 (book signing event date)
     454        BookSigning.objects.filter(pk=1).update(event_date=datetime.datetime(2008, 4, 1, 22, 0, tzinfo=timezone.utc))
     455        res = self.client.get('/dates/booksignings/2008/apr/2/')
     456        self.assertEqual(res.status_code, 200)
     457        # 2008-04-03T00:00:00+03:00 (end of day) > 2008-04-02T22:00:00+00:00 (book signing event date)
     458        BookSigning.objects.filter(pk=1).update(event_date=datetime.datetime(2008, 4, 2, 22, 0, tzinfo=timezone.utc))
     459        res = self.client.get('/dates/booksignings/2008/apr/2/')
     460        self.assertEqual(res.status_code, 404)
     461
     462
    382463class DateDetailViewTests(TestCase):
    383464    fixtures = ['generic-views-test-data.json']
    384465    urls = 'regressiontests.generic_views.urls'
    class DateDetailViewTests(TestCase):  
    432513        res = self.client.get(
    433514            '/dates/books/get_object_custom_queryset/2008/oct/01/1/')
    434515        self.assertEqual(res.status_code, 404)
     516
     517    def test_datetime_date_detail(self):
     518        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
     519        res = self.client.get('/dates/booksignings/2008/apr/2/1/')
     520        self.assertEqual(res.status_code, 200)
     521
     522    @override_settings(USE_TZ=True, TIME_ZONE='Africa/Nairobi')
     523    def test_aware_datetime_date_detail(self):
     524        BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0, tzinfo=timezone.utc))
     525        res = self.client.get('/dates/booksignings/2008/apr/2/1/')
     526        self.assertEqual(res.status_code, 200)
     527        # 2008-04-02T00:00:00+03:00 (beginning of day) > 2008-04-01T22:00:00+00:00 (book signing event date)
     528        BookSigning.objects.filter(pk=1).update(event_date=datetime.datetime(2008, 4, 1, 22, 0, tzinfo=timezone.utc))
     529        res = self.client.get('/dates/booksignings/2008/apr/2/1/')
     530        self.assertEqual(res.status_code, 200)
     531        # 2008-04-03T00:00:00+03:00 (end of day) > 2008-04-02T22:00:00+00:00 (book signing event date)
     532        BookSigning.objects.filter(pk=1).update(event_date=datetime.datetime(2008, 4, 2, 22, 0, tzinfo=timezone.utc))
     533        res = self.client.get('/dates/booksignings/2008/apr/2/1/')
     534        self.assertEqual(res.status_code, 404)
  • tests/regressiontests/generic_views/models.py

    diff --git a/tests/regressiontests/generic_views/models.py b/tests/regressiontests/generic_views/models.py
    index 5977258..2355769 100644
    a b class Book(models.Model):  
    4242class Page(models.Model):
    4343    content = models.TextField()
    4444    template = models.CharField(max_length=300)
     45
     46class BookSigning(models.Model):
     47    event_date = models.DateTimeField()
  • tests/regressiontests/generic_views/urls.py

    diff --git a/tests/regressiontests/generic_views/urls.py b/tests/regressiontests/generic_views/urls.py
    index 090ec73..9c47ab8 100644
    a b urlpatterns = patterns('',  
    108108        views.BookArchive.as_view(queryset=None)),
    109109    (r'^dates/books/paginated/$',
    110110        views.BookArchive.as_view(paginate_by=10)),
     111    (r'^dates/booksignings/$',
     112        views.BookSigningArchive.as_view()),
    111113
    112114    # ListView
    113115    (r'^list/dict/$',
    urlpatterns = patterns('',  
    156158        views.BookYearArchive.as_view(make_object_list=True, paginate_by=30)),
    157159    (r'^dates/books/no_year/$',
    158160        views.BookYearArchive.as_view()),
     161    (r'^dates/booksignings/(?P<year>\d{4})/$',
     162        views.BookSigningYearArchive.as_view()),
    159163
    160164    # MonthArchiveView
    161165    (r'^dates/books/(?P<year>\d{4})/(?P<month>[a-z]{3})/$',
    urlpatterns = patterns('',  
    170174        views.BookMonthArchive.as_view(paginate_by=30)),
    171175    (r'^dates/books/(?P<year>\d{4})/no_month/$',
    172176        views.BookMonthArchive.as_view()),
     177    (r'^dates/booksignings/(?P<year>\d{4})/(?P<month>[a-z]{3})/$',
     178        views.BookSigningMonthArchive.as_view()),
    173179
    174180    # WeekArchiveView
    175181    (r'^dates/books/(?P<year>\d{4})/week/(?P<week>\d{1,2})/$',
    urlpatterns = patterns('',  
    184190        views.BookWeekArchive.as_view()),
    185191    (r'^dates/books/(?P<year>\d{4})/week/(?P<week>\d{1,2})/monday/$',
    186192        views.BookWeekArchive.as_view(week_format='%W')),
     193    (r'^dates/booksignings/(?P<year>\d{4})/week/(?P<week>\d{1,2})/$',
     194        views.BookSigningWeekArchive.as_view()),
    187195
    188196    # DayArchiveView
    189197    (r'^dates/books/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{1,2})/$',
    urlpatterns = patterns('',  
    198206        views.BookDayArchive.as_view(paginate_by=True)),
    199207    (r'^dates/books/(?P<year>\d{4})/(?P<month>[a-z]{3})/no_day/$',
    200208        views.BookDayArchive.as_view()),
     209    (r'^dates/booksignings/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{1,2})/$',
     210        views.BookSigningDayArchive.as_view()),
    201211
    202212    # TodayArchiveView
    203     (r'dates/books/today/$',
     213    (r'^dates/books/today/$',
    204214        views.BookTodayArchive.as_view()),
    205     (r'dates/books/today/allow_empty/$',
     215    (r'^dates/books/today/allow_empty/$',
    206216        views.BookTodayArchive.as_view(allow_empty=True)),
     217    (r'^dates/booksignings/today/$',
     218        views.BookSigningTodayArchive.as_view()),
    207219
    208220    # DateDetailView
    209221    (r'^dates/books/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{1,2})/(?P<pk>\d+)/$',
    urlpatterns = patterns('',  
    221233    (r'^dates/books/get_object_custom_queryset/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{1,2})/(?P<pk>\d+)/$',
    222234        views.BookDetailGetObjectCustomQueryset.as_view()),
    223235
     236    (r'^dates/booksignings/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{1,2})/(?P<pk>\d+)/$',
     237        views.BookSigningDetail.as_view()),
     238
    224239    # Useful for testing redirects
    225240    (r'^accounts/login/$',  'django.contrib.auth.views.login')
    226241)
  • tests/regressiontests/generic_views/views.py

    diff --git a/tests/regressiontests/generic_views/views.py b/tests/regressiontests/generic_views/views.py
    index 5ff9cf0..a519e10 100644
    a b from django.utils.decorators import method_decorator  
    77from django.views import generic
    88
    99from .forms import AuthorForm
    10 from .models import Artist, Author, Book, Page
     10from .models import Artist, Author, Book, Page, BookSigning
    1111
    1212
    1313class CustomTemplateView(generic.TemplateView):
    class BookDetailGetObjectCustomQueryset(BookDetail):  
    184184    def get_object(self, queryset=None):
    185185        return super(BookDetailGetObjectCustomQueryset,self).get_object(
    186186            queryset=Book.objects.filter(pk=2))
     187
     188class CustomContextView(generic.detail.SingleObjectMixin, generic.View):
     189    model = Book
     190    object = Book(name='dummy')
     191
     192    def get_object(self):
     193        return Book(name="dummy")
     194
     195    def get_context_data(self, **kwargs):
     196        context = {'custom_key': 'custom_value'}
     197        context.update(kwargs)
     198        return super(CustomContextView, self).get_context_data(**context)
     199
     200    def get_context_object_name(self, obj):
     201        return "test_name"
     202
     203class BookSigningConfig(object):
     204    model = BookSigning
     205    date_field = 'event_date'
     206    # use the same templates as for books
     207    def get_template_names(self):
     208        return ['generic_views/book%s.html' % self.template_name_suffix]
     209
     210class BookSigningArchive(BookSigningConfig, generic.ArchiveIndexView):
     211    pass
     212
     213class BookSigningYearArchive(BookSigningConfig, generic.YearArchiveView):
     214    pass
     215
     216class BookSigningMonthArchive(BookSigningConfig, generic.MonthArchiveView):
     217    pass
     218
     219class BookSigningWeekArchive(BookSigningConfig, generic.WeekArchiveView):
     220    pass
     221
     222class BookSigningDayArchive(BookSigningConfig, generic.DayArchiveView):
     223    pass
     224
     225class BookSigningTodayArchive(BookSigningConfig, generic.TodayArchiveView):
     226    pass
     227
     228class BookSigningDetail(BookSigningConfig, generic.DateDetailView):
     229    context_object_name = 'book'
Back to Top