Ticket #13611: carls_cool_next_by_nullable_FOO.diff

File carls_cool_next_by_nullable_FOO.diff, 4.2 KB (added by CarlFK, 5 years ago)
  • django/db/models/base.py

     
    647647    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
    648648        op = is_next and 'gt' or 'lt'
    649649        order = not is_next and '-' or ''
    650         param = smart_str(getattr(self, field.attname))
    651         q = Q(**{'%s__%s' % (field.name, op): param})
    652         q = q|Q(**{field.name: param, 'pk__%s' % op: self.pk})
     650
     651        current_field_value = getattr(self, field.attname)
     652        if current_field_value is None:
     653            q = Q(**{ "%s__isnull" % field.name: True, 'pk__%s' % op: self.pk})
     654        else:
     655            param = smart_str(current_field_value)
     656            q = Q(**{'%s__%s' % (field.name, op): param})
     657            q = q|Q(**{field.name: param, 'pk__%s' % op: self.pk})
     658
    653659        qs = self.__class__._default_manager.using(self._state.db).filter(**kwargs).filter(q).order_by('%s%s' % (order, field.name), '%spk' % order)
    654660        try:
    655661            return qs[0]
  • django/db/models/fields/__init__.py

     
    627627
    628628    def contribute_to_class(self, cls, name):
    629629        super(DateField,self).contribute_to_class(cls, name)
    630         if not self.null:
    631             setattr(cls, 'get_next_by_%s' % self.name,
    632                 curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=True))
    633             setattr(cls, 'get_previous_by_%s' % self.name,
    634                 curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
     630        setattr(cls, 'get_next_by_%s' % self.name,
     631            curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=True))
     632        setattr(cls, 'get_previous_by_%s' % self.name,
     633            curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False))
    635634
    636635    def get_prep_lookup(self, lookup_type, value):
    637636        # For "__month", "__day", and "__week_day" lookups, convert the value
  • tests/modeltests/lookup/models.py

     
    99
    1010class Article(models.Model):
    1111    headline = models.CharField(max_length=100)
    12     pub_date = models.DateTimeField()
     12    pub_date = models.DateTimeField(null=True)
    1313    class Meta:
    1414        ordering = ('-pub_date', 'headline')
    1515
     
    223223# get_previous_by_FOO() methods.
    224224# In the case of identical date values, these methods will use the ID as a
    225225# fallback check. This guarantees that no records are skipped or duplicated.
     226
     227>>> a8 = Article(headline='Article 8', pub_date=None)
     228>>> a8.save()
     229>>> a9 = Article(headline='Article 9', pub_date=None)
     230>>> a9.save()
     231
    226232>>> a1.get_next_by_pub_date()
    227233<Article: Article 2>
    228234>>> a2.get_next_by_pub_date()
     
    255261>>> a2.get_previous_by_pub_date()
    256262<Article: Article 1>
    257263
     264# test walking around in null land:
     265
     266# go from first null date to 2nd null date and back
     267>>> a8.get_next_by_pub_date()
     268<Article: Article 9>
     269>>> a9.get_previous_by_pub_date()
     270<Article: Article 8>
     271
     272# try to go past first/last null date
     273a9.get_next_by_pub_date()
     274>>> a8.get_previous_by_pub_date()
     275Traceback (most recent call last):
     276    ...
     277DoesNotExist: Article matching query does not exist.
     278>>> a9.get_next_by_pub_date()
     279Traceback (most recent call last):
     280    ...
     281DoesNotExist: Article matching query does not exist.
     282
     283# try to go from first date up into nulls (which SQL ORDER BY puts before values)
     284>>> a1.get_previous_by_pub_date()
     285Traceback (most recent call last):
     286    ...
     287DoesNotExist: Article matching query does not exist.
     288
     289# because I don't feel like modifying the rest of the tests:
     290>>> a8.delete()
     291>>> a9.delete()
     292
    258293# Underscores and percent signs have special meaning in the underlying
    259294# SQL code, but Django handles the quoting of them automatically.
    260295>>> a8 = Article(headline='Article_ with underscore', pub_date=datetime(2005, 11, 20))
Back to Top