Code

Ticket #3182: update_or_create2.diff

File update_or_create2.diff, 7.0 KB (added by Gary Wilson <gary.wilson@…>, 7 years ago)

added documentation and tests

Line 
1=== added directory 'tests/modeltests/update_or_create'
2=== added file 'tests/modeltests/update_or_create/__init__.py'
3=== added file 'tests/modeltests/update_or_create/models.py'
4--- tests/modeltests/update_or_create/models.py 1970-01-01 00:00:00 +0000
5+++ tests/modeltests/update_or_create/models.py 2006-12-24 22:33:57 +0000
6@@ -0,0 +1,75 @@
7+"""
8+35. update_or_create()
9+
10+update_or_create() tries to look up an object with the given parameters.
11+If an object is found, it updates the object.  If an object isn't found, it
12+creates one with the given parameters.
13+"""
14+
15+from django.db import models
16+
17+class Person(models.Model):
18+    first_name = models.CharField(maxlength=100)
19+    last_name = models.CharField(maxlength=100)
20+    birthday = models.DateField()
21+
22+    def __str__(self):
23+        return '%s %s, Birthday: %s' % (self.first_name, self.last_name,
24+                                        self.birthday)
25+
26+    class Meta:
27+        ordering = ('last_name',)
28+
29+__test__ = {'API_TESTS':"""
30+# Create a Person.
31+>>> from datetime import date
32+>>> p = Person.objects.create(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
33+
34+# Only one Person is in the database at this point.
35+>>> Person.objects.all()
36+[<Person: John Lennon, Birthday: 1940-10-09>]
37+
38+# update_or_create() a Person with the same name.
39+>>> p, created = Person.objects.update_or_create(first_name='John', last_name='Lennon', defaults={'birthday': date(1970, 10, 9)})
40+
41+# update_or_create() didn't have to create an object.
42+>>> created
43+False
44+
45+# There's still only one Person in the database, and their birthday was updated.
46+>>> Person.objects.all()
47+[<Person: John Lennon, Birthday: 1970-10-09>]
48+
49+# update_or_create() a Person with a different name.
50+>>> p, created = Person.objects.update_or_create(first_name='George', last_name='Harrison', defaults={'birthday': date(1943, 2, 25)})
51+>>> created
52+True
53+
54+# Two People in the database now.
55+>>> Person.objects.all()
56+[<Person: George Harrison, Birthday: 1943-02-25>, <Person: John Lennon, Birthday: 1970-10-09>]
57+
58+# If we execute the exact same statement, it won't create a Person.
59+>>> p, created = Person.objects.update_or_create(first_name='George', last_name='Harrison', defaults={'birthday': date(1943, 2, 25)})
60+>>> created
61+False
62+
63+# The two People in the database haven't changed.
64+>>> Person.objects.all()
65+[<Person: George Harrison, Birthday: 1943-02-25>, <Person: John Lennon, Birthday: 1970-10-09>]
66+
67+# update_or_create() can take an empty 'defaults' parameter, but in this
68+# situation behaves exactly like get_or_create().  This is useful if you are
69+# building the 'defaults' dictionary dynamically.
70+>>> p, created = Person.objects.update_or_create(first_name='George', last_name='Harrison', defaults={})
71+>>> created
72+False
73+
74+# A different name with an empty 'defaults'.
75+>>> p, created = Person.objects.update_or_create(first_name='John', last_name='Smith', birthday=date(1950, 2, 10), defaults={})
76+>>> created
77+True
78+
79+>>> Person.objects.all()
80+[<Person: George Harrison, Birthday: 1943-02-25>, <Person: John Lennon, Birthday: 1970-10-09>, <Person: John Smith, Birthday: 1950-02-10>]
81+"""}
82
83=== modified file 'django/db/models/manager.py'
84--- django/db/models/manager.py 2006-12-19 04:35:09 +0000
85+++ django/db/models/manager.py 2006-12-22 06:44:11 +0000
86@@ -68,7 +68,10 @@
87 
88     def get_or_create(self, **kwargs):
89         return self.get_query_set().get_or_create(**kwargs)
90-       
91+
92+    def update_or_create(self, **kwargs):
93+        return self.get_query_set().update_or_create(**kwargs)
94+
95     def create(self, **kwargs):
96         return self.get_query_set().create(**kwargs)
97 
98
99=== modified file 'django/db/models/query.py'
100--- django/db/models/query.py   2006-12-19 04:35:09 +0000
101+++ django/db/models/query.py   2006-12-24 22:15:33 +0000
102@@ -240,6 +240,19 @@
103             obj.save()
104             return obj, True
105 
106+    def update_or_create(self, **kwargs):
107+        """
108+        Looks up an object with the given kwargs, creating one if necessary.
109+        If the object already exists, then its fields are updated with the
110+        values passed in the defaults dictionary.
111+        Returns a tuple of (object, created), where created is a boolean
112+        specifying whether an object was created.
113+        """
114+        obj, created = self.get_or_create(**kwargs)
115+        if not created:
116+            obj.update(**kwargs.pop('defaults', {}))
117+        return obj, created
118+
119     def latest(self, field_name=None):
120         """
121         Returns the latest object, according to the model's 'get_latest_by'
122
123=== modified file 'docs/db-api.txt'
124--- docs/db-api.txt     2006-12-22 02:25:11 +0000
125+++ docs/db-api.txt     2006-12-24 22:48:02 +0000
126@@ -784,6 +784,52 @@
127 
128 .. _Safe methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
129 
130+``update_or_create(**kwargs)``
131+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132+
133+A convenience method for looking up an object with the given kwargs, and then
134+either updating the values of the object if one is found or creating an
135+object if one was not found.
136+
137+This method calls ``get_or_create()`` behind the scenes, and similarly
138+returns a tuple of ``(object, created)``, where``object`` is the updated or
139+created object and ``created`` is a boolean specifying whether a new object
140+was created.
141+
142+This is meant as a shortcut to the following type of code::
143+
144+    obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
145+                       defaults={'birthday': date(1940, 10, 9)})
146+    if not created:
147+           obj.update('birthday'=date(1940, 10, 9))
148+
149+This pattern gets quite unwieldy as the number of fields in a model goes up.
150+The above example can be rewritten using ``update_or_create()`` like so::
151+
152+    obj, created = Person.objects.update_or_create(first_name='John', last_name='Lennon',
153+                       defaults={'birthday': date(1940, 10, 9)})
154+
155+Any keyword arguments passed to ``update_or_create()`` will be used in a
156+call to ``get_or_create()``. If ``get_or_create()`` creates an object, then
157+nothing needs to be done by ``update_or_create()`` and a tuple of the created
158+object and ``True`` is returned. If, on the other hand, ``get_or_create()``
159+does not create a new object, then ``update_or_create()`` will update the
160+object with the values passed in the required ``defaults`` parameter and a
161+tuple of the updated object and ``True`` is returned.
162+
163+The ``defaults`` parameter should be a dict of attribute-value pairs that
164+you want to update. If ``defaults`` is empty or not specified, then
165+``update_or_create()`` will act exactly like ``get_or_create()`` since there
166+would be nothing to update.
167+
168+As with ``get_or_create()``, if you need to use ``update_or_create()`` in a
169+view, please make sure to use it only in ``POST`` requests unless you have a
170+good reason not to. ``GET`` requests shouldn't have any effect on data; use
171+``POST`` whenever a request to a page has a side effect on your data. For
172+more, see `Safe methods`_ in the HTTP spec.
173+
174+.. _Safe methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
175+
176 ``count()``
177 ~~~~~~~~~~~
178 
179