Ticket #17186: 17186-4.patch

File 17186-4.patch, 4.3 KB (added by Nate Bragg, 12 years ago)

Updated docs and added a test

  • django/db/models/expressions.py

    From 395bc2aa3fede50646f78a07b4035824339a1e44 Mon Sep 17 00:00:00 2001
    From: Nate Bragg <jonathan.bragg@alum.rpi.edu>
    Date: Wed, 18 Jan 2012 22:02:12 -0500
    Subject: [PATCH] Implemented a fix to #17186 using a negation node; Updated
     docs and tests
    
    ---
     django/db/models/expressions.py        |   14 ++++++++++++++
     docs/topics/db/queries.txt             |   23 +++++++++++++++++++++++
     tests/modeltests/expressions/models.py |    3 +++
     tests/modeltests/expressions/tests.py  |   13 +++++++++++++
     4 files changed, 53 insertions(+), 0 deletions(-)
    
    diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
    index a71f4a3..7c978dc 100644
    a b class ExpressionNode(tree.Node):  
    7070    def __or__(self, other):
    7171        return self._combine(other, self.OR, False)
    7272
     73    def __invert__(self):
     74        return NotNode([self])
     75
    7376    def __radd__(self, other):
    7477        return self._combine(other, self.ADD, True)
    7578
    class F(ExpressionNode):  
    113116    def evaluate(self, evaluator, qn, connection):
    114117        return evaluator.evaluate_leaf(self, qn, connection)
    115118
     119class NotNode(ExpressionNode):
     120    """
     121    Node that represents a negation.
     122    """
     123    def __init__(self, children=None):
     124        super(NotNode, self).__init__(children, None, True)
     125
     126    def evaluate(self, evaluator, qn, connection):
     127        sql, params = evaluator.evaluate_node(self, qn, connection)
     128        return ("NOT %s" % sql, params)
     129
    116130class DateModifierNode(ExpressionNode):
    117131    """
    118132    Node that implements the following syntax:
  • docs/topics/db/queries.txt

    diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt
    index 345687e..5059f0e 100644
    a b after they were published::  
    594594    >>> from datetime import timedelta
    595595    >>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
    596596
     597.. versionadded:: 1.4
     598
     599Additionally, ``F()`` objects can be negated using the ``~`` operator.
     600Note that for ``NULL`` values, this performs no changes::
     601
     602    >>> class A(Model):
     603    ...    f = NullBooleanField()
     604    ...
     605    >>> A.objects.create()
     606    <A: A object>
     607    >>> for m in A.objects.all():
     608    ...     m.f = not m.f; m.save()  # all NULL values are now True
     609    ...
     610    >>> A.objects.values('f')
     611    [{'f': True}]
     612    >>> A.objects.all().delete()
     613    >>> A.objects.create()
     614    <A: A object>
     615    >>> A.objects.update(f=~F('f')) # this leaves NULL values unchanged as NOT NULL is NULL
     616    1
     617    >>> A.objects.values('f')
     618    [{'f': None}]
     619
    597620The pk lookup shortcut
    598621----------------------
    599622
  • tests/modeltests/expressions/models.py

    diff --git a/tests/modeltests/expressions/models.py b/tests/modeltests/expressions/models.py
    index dd50499..da6f1df 100644
    a b from django.db import models  
    88class Employee(models.Model):
    99    firstname = models.CharField(max_length=50)
    1010    lastname = models.CharField(max_length=50)
     11    is_active = models.BooleanField(default=False)
    1112
    1213    def __unicode__(self):
    1314        return u'%s %s' % (self.firstname, self.lastname)
    class Company(models.Model):  
    2627
    2728    def __unicode__(self):
    2829        return self.name
     30
     31
  • tests/modeltests/expressions/tests.py

    diff --git a/tests/modeltests/expressions/tests.py b/tests/modeltests/expressions/tests.py
    index 8f4f546..c1096c0 100644
    a b class ExpressionsTests(TestCase):  
    2222            ceo=Employee.objects.create(firstname="Max", lastname="Mustermann")
    2323        )
    2424
     25        # mark active employees when their companies have num_chairs greater than 3
     26        employee_qs = Employee.objects.filter(is_active=False)
     27        self.assertEqual(employee_qs.count(), 3)
     28
     29        Employee.objects.filter(company_ceo_set__num_chairs__gte=3)\
     30            .update(is_active=~F("is_active"))
     31
     32        employee_qs = Employee.objects.filter(is_active=False)
     33        self.assertEqual(employee_qs.count(), 1)
     34
     35        employee_qs = Employee.objects.filter(is_active=~(~F('is_active')))
     36        self.assertEqual(employee_qs.count(), Employee.objects.count())
     37
    2538        company_query = Company.objects.values(
    2639            "name", "num_employees", "num_chairs"
    2740        ).order_by(
Back to Top