1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

[soc2010/query-refactor] Implemented F() expressions for MongoDB.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/query-refactor@13430 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2010-07-13 19:17:41 +00:00
parent 317010ed40
commit d83203cb07
4 changed files with 47 additions and 5 deletions

View File

@ -2,6 +2,7 @@ import re
from pymongo import ASCENDING, DESCENDING from pymongo import ASCENDING, DESCENDING
from django.db.models import F
from django.db.models.sql.datastructures import FullResultSet, EmptyResultSet from django.db.models.sql.datastructures import FullResultSet, EmptyResultSet
@ -153,8 +154,25 @@ class SQLUpdateCompiler(SQLCompiler):
filters = self.get_filters(self.query.where) filters = self.get_filters(self.query.where)
# TODO: Don't use set for everything, use INC and such where # TODO: Don't use set for everything, use INC and such where
# appropriate. # appropriate.
vals = {}
for field, o, value in self.query.values:
if hasattr(value, "evaluate"):
assert value.connector in (value.ADD, value.SUB)
assert not value.negated
assert not value.subtree_parents
lhs, rhs = value.children
if isinstance(lhs, F):
assert not isinstance(rhs, F)
if value.connector == value.SUB:
rhs = -rhs
else:
assert value.connector == value.ADD
rhs, lhs = lhs, rhs
vals.setdefault("$inc", {})[lhs.name] = rhs
else:
vals.setdefault("$set", {})[field.column] = value
return self.connection.db[self.query.model._meta.db_table].update( return self.connection.db[self.query.model._meta.db_table].update(
filters, filters,
{"$set": dict((f.column, val) for f, o, val in self.query.values)}, vals,
multi=True multi=True
) )

View File

@ -8,7 +8,8 @@ from itertools import izip
from django.db import connections, router, transaction, IntegrityError from django.db import connections, router, transaction, IntegrityError
from django.db.models.aggregates import Aggregate from django.db.models.aggregates import Aggregate
from django.db.models.fields import DateField from django.db.models.fields import DateField
from django.db.models.query_utils import Q, select_related_descend, CollectedObjects, CyclicDependency, deferred_class_factory, InvalidQuery from django.db.models.query_utils import (Q, select_related_descend,
CollectedObjects, CyclicDependency, deferred_class_factory, InvalidQuery)
from django.db.models import signals, sql from django.db.models import signals, sql
from django.utils.copycompat import deepcopy from django.utils.copycompat import deepcopy
@ -464,7 +465,7 @@ class QuerySet(object):
else: else:
forced_managed = False forced_managed = False
try: try:
rows = query.get_compiler(self.db).execute_sql(None) rows = query.get_compiler(self.db).update(None)
if forced_managed: if forced_managed:
transaction.commit(using=self.db) transaction.commit(using=self.db)
else: else:

View File

@ -5,6 +5,7 @@ class Artist(models.Model):
id = models.NativeAutoField(primary_key=True) id = models.NativeAutoField(primary_key=True)
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
good = models.BooleanField() good = models.BooleanField()
age = models.IntegerField(null=True)
current_group = models.ForeignKey("Group", null=True) current_group = models.ForeignKey("Group", null=True)

View File

@ -1,4 +1,4 @@
from django.db.models import Count from django.db.models import Count, F
from django.test import TestCase from django.test import TestCase
from models import Artist, Group from models import Artist, Group
@ -27,6 +27,28 @@ class MongoTestCase(TestCase):
l = Artist.objects.get(pk=pk) l = Artist.objects.get(pk=pk)
self.assertTrue(not l.good) self.assertTrue(not l.good)
def test_bulk_update(self):
# Doesn't actually do an op on more than 1 item, but it's the bulk
# update syntax nonetheless
v = Artist.objects.create(name="Van Morrison", good=False)
# How do you make a mistake like this, I don't know...
Artist.objects.filter(pk=v.pk).update(good=True)
self.assertTrue(Artist.objects.get(pk=v.pk).good)
def test_f_expressions(self):
k = Artist.objects.create(name="Keb' Mo'", age=57, good=True)
# Birthday!
Artist.objects.filter(pk=k.pk).update(age=F("age") + 1)
self.assertEqual(Artist.objects.get(pk=k.pk).age, 58)
# Backwards birthday
Artist.objects.filter(pk=k.pk).update(age=F("age") - 1)
self.assertEqual(Artist.objects.get(pk=k.pk).age, 57)
# Birthday again!
Artist.objects.filter(pk=k.pk).update(age=1 + F("age"))
self.assertEqual(Artist.objects.get(pk=k.pk).age, 58)
def test_count(self): def test_count(self):
Artist.objects.create(name="Billy Joel", good=True) Artist.objects.create(name="Billy Joel", good=True)
Artist.objects.create(name="John Mellencamp", good=True) Artist.objects.create(name="John Mellencamp", good=True)
@ -121,7 +143,7 @@ class MongoTestCase(TestCase):
self.assertQuerysetEqual( self.assertQuerysetEqual(
Artist.objects.values(), [ Artist.objects.values(), [
{"name": "Steve Perry", "good": True, "current_group_id": None, "id": a.pk}, {"name": "Steve Perry", "good": True, "current_group_id": None, "id": a.pk, "age": None},
], ],
lambda a: a, lambda a: a,
) )