parts/django/tests/modeltests/expressions/tests.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 from django.core.exceptions import FieldError
       
     2 from django.db.models import F
       
     3 from django.test import TestCase
       
     4 
       
     5 from models import Company, Employee
       
     6 
       
     7 
       
     8 class ExpressionsTests(TestCase):
       
     9     def test_filter(self):
       
    10         Company.objects.create(
       
    11             name="Example Inc.", num_employees=2300, num_chairs=5,
       
    12             ceo=Employee.objects.create(firstname="Joe", lastname="Smith")
       
    13         )
       
    14         Company.objects.create(
       
    15             name="Foobar Ltd.", num_employees=3, num_chairs=4,
       
    16             ceo=Employee.objects.create(firstname="Frank", lastname="Meyer")
       
    17         )
       
    18         Company.objects.create(
       
    19             name="Test GmbH", num_employees=32, num_chairs=1,
       
    20             ceo=Employee.objects.create(firstname="Max", lastname="Mustermann")
       
    21         )
       
    22 
       
    23         company_query = Company.objects.values(
       
    24             "name", "num_employees", "num_chairs"
       
    25         ).order_by(
       
    26             "name", "num_employees", "num_chairs"
       
    27         )
       
    28 
       
    29         # We can filter for companies where the number of employees is greater
       
    30         # than the number of chairs.
       
    31         self.assertQuerysetEqual(
       
    32             company_query.filter(num_employees__gt=F("num_chairs")), [
       
    33                 {
       
    34                     "num_chairs": 5,
       
    35                     "name": "Example Inc.",
       
    36                     "num_employees": 2300,
       
    37                 },
       
    38                 {
       
    39                     "num_chairs": 1,
       
    40                     "name": "Test GmbH",
       
    41                     "num_employees": 32
       
    42                 },
       
    43             ],
       
    44             lambda o: o
       
    45         )
       
    46 
       
    47         # We can set one field to have the value of another field
       
    48         # Make sure we have enough chairs
       
    49         company_query.update(num_chairs=F("num_employees"))
       
    50         self.assertQuerysetEqual(
       
    51             company_query, [
       
    52                 {
       
    53                     "num_chairs": 2300,
       
    54                     "name": "Example Inc.",
       
    55                     "num_employees": 2300
       
    56                 },
       
    57                 {
       
    58                     "num_chairs": 3,
       
    59                     "name": "Foobar Ltd.",
       
    60                     "num_employees": 3
       
    61                 },
       
    62                 {
       
    63                     "num_chairs": 32,
       
    64                     "name": "Test GmbH",
       
    65                     "num_employees": 32
       
    66                 }
       
    67             ],
       
    68             lambda o: o
       
    69         )
       
    70 
       
    71         # We can perform arithmetic operations in expressions
       
    72         # Make sure we have 2 spare chairs
       
    73         company_query.update(num_chairs=F("num_employees")+2)
       
    74         self.assertQuerysetEqual(
       
    75             company_query, [
       
    76                 {
       
    77                     'num_chairs': 2302,
       
    78                     'name': u'Example Inc.',
       
    79                     'num_employees': 2300
       
    80                 },
       
    81                 {
       
    82                     'num_chairs': 5,
       
    83                     'name': u'Foobar Ltd.',
       
    84                     'num_employees': 3
       
    85                 },
       
    86                 {
       
    87                     'num_chairs': 34,
       
    88                     'name': u'Test GmbH',
       
    89                     'num_employees': 32
       
    90                 }
       
    91             ],
       
    92             lambda o: o,
       
    93         )
       
    94 
       
    95         # Law of order of operations is followed
       
    96         company_query.update(
       
    97             num_chairs=F('num_employees') + 2 * F('num_employees')
       
    98         )
       
    99         self.assertQuerysetEqual(
       
   100             company_query, [
       
   101                 {
       
   102                     'num_chairs': 6900,
       
   103                     'name': u'Example Inc.',
       
   104                     'num_employees': 2300
       
   105                 },
       
   106                 {
       
   107                     'num_chairs': 9,
       
   108                     'name': u'Foobar Ltd.',
       
   109                     'num_employees': 3
       
   110                 },
       
   111                 {
       
   112                     'num_chairs': 96,
       
   113                     'name': u'Test GmbH',
       
   114                     'num_employees': 32
       
   115                 }
       
   116             ],
       
   117             lambda o: o,
       
   118         )
       
   119 
       
   120         # Law of order of operations can be overridden by parentheses
       
   121         company_query.update(
       
   122             num_chairs=((F('num_employees') + 2) * F('num_employees'))
       
   123         )
       
   124         self.assertQuerysetEqual(
       
   125             company_query, [
       
   126                 {
       
   127                     'num_chairs': 5294600,
       
   128                     'name': u'Example Inc.',
       
   129                     'num_employees': 2300
       
   130                 },
       
   131                 {
       
   132                     'num_chairs': 15,
       
   133                     'name': u'Foobar Ltd.',
       
   134                     'num_employees': 3
       
   135                 },
       
   136                 {
       
   137                     'num_chairs': 1088,
       
   138                     'name': u'Test GmbH',
       
   139                     'num_employees': 32
       
   140                 }
       
   141             ],
       
   142             lambda o: o,
       
   143         )
       
   144 
       
   145         # The relation of a foreign key can become copied over to an other
       
   146         # foreign key.
       
   147         self.assertEqual(
       
   148             Company.objects.update(point_of_contact=F('ceo')),
       
   149             3
       
   150         )
       
   151         self.assertQuerysetEqual(
       
   152             Company.objects.all(), [
       
   153                 "Joe Smith",
       
   154                 "Frank Meyer",
       
   155                 "Max Mustermann",
       
   156             ],
       
   157             lambda c: unicode(c.point_of_contact),
       
   158         )
       
   159 
       
   160         c = Company.objects.all()[0]
       
   161         c.point_of_contact = Employee.objects.create(firstname="Guido", lastname="van Rossum")
       
   162         c.save()
       
   163 
       
   164         # F Expressions can also span joins
       
   165         self.assertQuerysetEqual(
       
   166             Company.objects.filter(ceo__firstname=F("point_of_contact__firstname")), [
       
   167                 "Foobar Ltd.",
       
   168                 "Test GmbH",
       
   169             ],
       
   170             lambda c: c.name
       
   171         )
       
   172 
       
   173         Company.objects.exclude(
       
   174             ceo__firstname=F("point_of_contact__firstname")
       
   175         ).update(name="foo")
       
   176         self.assertEqual(
       
   177             Company.objects.exclude(
       
   178                 ceo__firstname=F('point_of_contact__firstname')
       
   179             ).get().name,
       
   180             "foo",
       
   181         )
       
   182 
       
   183         self.assertRaises(FieldError,
       
   184             lambda: Company.objects.exclude(
       
   185                 ceo__firstname=F('point_of_contact__firstname')
       
   186             ).update(name=F('point_of_contact__lastname'))
       
   187         )
       
   188 
       
   189         # F expressions can be used to update attributes on single objects
       
   190         test_gmbh = Company.objects.get(name="Test GmbH")
       
   191         self.assertEqual(test_gmbh.num_employees, 32)
       
   192         test_gmbh.num_employees = F("num_employees") + 4
       
   193         test_gmbh.save()
       
   194         test_gmbh = Company.objects.get(pk=test_gmbh.pk)
       
   195         self.assertEqual(test_gmbh.num_employees, 36)
       
   196 
       
   197         # F expressions cannot be used to update attributes which are foreign
       
   198         # keys, or attributes which involve joins.
       
   199         test_gmbh.point_of_contact = None
       
   200         test_gmbh.save()
       
   201         self.assertTrue(test_gmbh.point_of_contact is None)
       
   202         def test():
       
   203             test_gmbh.point_of_contact = F("ceo")
       
   204         self.assertRaises(ValueError, test)
       
   205 
       
   206         test_gmbh.point_of_contact = test_gmbh.ceo
       
   207         test_gmbh.save()
       
   208         test_gmbh.name = F("ceo__last_name")
       
   209         self.assertRaises(FieldError, test_gmbh.save)
       
   210 
       
   211         # F expressions cannot be used to update attributes on objects which do
       
   212         # not yet exist in the database
       
   213         acme = Company(
       
   214             name="The Acme Widget Co.", num_employees=12, num_chairs=5,
       
   215             ceo=test_gmbh.ceo
       
   216         )
       
   217         acme.num_employees = F("num_employees") + 16
       
   218         self.assertRaises(TypeError, acme.save)