~ubuntu-branches/debian/squeeze/python-django/squeeze

« back to all changes in this revision

Viewing changes to tests/modeltests/model_formsets/models.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb, Chris Lamb, David Spreen, Sandro Tosi
  • Date: 2008-11-19 21:31:00 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20081119213100-gp0lqhxl1qxa6dgl
Tags: 1.0.2-1
[ Chris Lamb ]
* New upstream bugfix release. Closes: #505783
* Add myself to Uploaders with ACK from Brett.

[ David Spreen ]
* Remove python-pysqlite2 from Recommends because Python 2.5 includes
  sqlite library used by Django. Closes: 497886

[ Sandro Tosi ]
* debian/control
  - switch Vcs-Browser field to viewsvn

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
import datetime
3
 
 
4
 
from django import forms
5
 
from django.db import models
6
 
 
7
 
try:
8
 
    sorted
9
 
except NameError:
10
 
    from django.utils.itercompat import sorted
11
 
 
12
 
class Author(models.Model):
13
 
    name = models.CharField(max_length=100)
14
 
 
15
 
    class Meta:
16
 
        ordering = ('name',)
17
 
 
18
 
    def __unicode__(self):
19
 
        return self.name
20
 
 
21
 
class BetterAuthor(Author):
22
 
    write_speed = models.IntegerField()
23
 
 
24
 
class Book(models.Model):
25
 
    author = models.ForeignKey(Author)
26
 
    title = models.CharField(max_length=100)
27
 
 
28
 
    def __unicode__(self):
29
 
        return self.title
30
 
 
31
 
class AuthorMeeting(models.Model):
32
 
    name = models.CharField(max_length=100)
33
 
    authors = models.ManyToManyField(Author)
34
 
    created = models.DateField(editable=False)
35
 
 
36
 
    def __unicode__(self):
37
 
        return self.name
38
 
 
39
 
class CustomPrimaryKey(models.Model):
40
 
    my_pk = models.CharField(max_length=10, primary_key=True)
41
 
    some_field = models.CharField(max_length=100)
42
 
 
43
 
 
44
 
# models for inheritance tests.
45
 
 
46
 
class Place(models.Model):
47
 
    name = models.CharField(max_length=50)
48
 
    city = models.CharField(max_length=50)
49
 
    
50
 
    def __unicode__(self):
51
 
        return self.name
52
 
 
53
 
class Owner(models.Model):
54
 
    auto_id = models.AutoField(primary_key=True)
55
 
    name = models.CharField(max_length=100)
56
 
    place = models.ForeignKey(Place)
57
 
    
58
 
    def __unicode__(self):
59
 
        return "%s at %s" % (self.name, self.place)
60
 
 
61
 
class Location(models.Model):
62
 
    place = models.ForeignKey(Place, unique=True)
63
 
    # this is purely for testing the data doesn't matter here :)
64
 
    lat = models.CharField(max_length=100)
65
 
    lon = models.CharField(max_length=100)
66
 
 
67
 
class OwnerProfile(models.Model):
68
 
    owner = models.OneToOneField(Owner, primary_key=True)
69
 
    age = models.PositiveIntegerField()
70
 
    
71
 
    def __unicode__(self):
72
 
        return "%s is %d" % (self.owner.name, self.age)
73
 
 
74
 
class Restaurant(Place):
75
 
    serves_pizza = models.BooleanField()
76
 
    
77
 
    def __unicode__(self):
78
 
        return self.name
79
 
 
80
 
class Product(models.Model):
81
 
    slug = models.SlugField(unique=True)
82
 
 
83
 
    def __unicode__(self):
84
 
        return self.slug
85
 
 
86
 
class Price(models.Model):
87
 
    price = models.DecimalField(max_digits=10, decimal_places=2)
88
 
    quantity = models.PositiveIntegerField()
89
 
 
90
 
    def __unicode__(self):
91
 
        return u"%s for %s" % (self.quantity, self.price)
92
 
 
93
 
    class Meta:
94
 
        unique_together = (('price', 'quantity'),)
95
 
 
96
 
class MexicanRestaurant(Restaurant):
97
 
    serves_tacos = models.BooleanField()
98
 
 
99
 
# models for testing callable defaults (see bug #7975). If you define a model
100
 
# with a callable default value, you cannot rely on the initial value in a
101
 
# form.
102
 
class Person(models.Model):
103
 
    name = models.CharField(max_length=128)
104
 
 
105
 
class Membership(models.Model):
106
 
    person = models.ForeignKey(Person)
107
 
    date_joined = models.DateTimeField(default=datetime.datetime.now)
108
 
    karma = models.IntegerField()
109
 
 
110
 
__test__ = {'API_TESTS': """
111
 
 
112
 
>>> from datetime import date
113
 
 
114
 
>>> from django.forms.models import modelformset_factory
115
 
 
116
 
>>> qs = Author.objects.all()
117
 
>>> AuthorFormSet = modelformset_factory(Author, extra=3)
118
 
 
119
 
>>> formset = AuthorFormSet(queryset=qs)
120
 
>>> for form in formset.forms:
121
 
...     print form.as_p()
122
 
<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></p>
123
 
<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" maxlength="100" /><input type="hidden" name="form-1-id" id="id_form-1-id" /></p>
124
 
<p><label for="id_form-2-name">Name:</label> <input id="id_form-2-name" type="text" name="form-2-name" maxlength="100" /><input type="hidden" name="form-2-id" id="id_form-2-id" /></p>
125
 
 
126
 
>>> data = {
127
 
...     'form-TOTAL_FORMS': '3', # the number of forms rendered
128
 
...     'form-INITIAL_FORMS': '0', # the number of forms with initial data
129
 
...     'form-0-name': 'Charles Baudelaire',
130
 
...     'form-1-name': 'Arthur Rimbaud',
131
 
...     'form-2-name': '',
132
 
... }
133
 
 
134
 
>>> formset = AuthorFormSet(data=data, queryset=qs)
135
 
>>> formset.is_valid()
136
 
True
137
 
 
138
 
>>> formset.save()
139
 
[<Author: Charles Baudelaire>, <Author: Arthur Rimbaud>]
140
 
 
141
 
>>> for author in Author.objects.order_by('name'):
142
 
...     print author.name
143
 
Arthur Rimbaud
144
 
Charles Baudelaire
145
 
 
146
 
 
147
 
Gah! We forgot Paul Verlaine. Let's create a formset to edit the existing
148
 
authors with an extra form to add him. We *could* pass in a queryset to
149
 
restrict the Author objects we edit, but in this case we'll use it to display
150
 
them in alphabetical order by name.
151
 
 
152
 
>>> qs = Author.objects.order_by('name')
153
 
>>> AuthorFormSet = modelformset_factory(Author, extra=1, can_delete=False)
154
 
 
155
 
>>> formset = AuthorFormSet(queryset=qs)
156
 
>>> for form in formset.forms:
157
 
...     print form.as_p()
158
 
<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" value="Arthur Rimbaud" maxlength="100" /><input type="hidden" name="form-0-id" value="2" id="id_form-0-id" /></p>
159
 
<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-1-id" value="1" id="id_form-1-id" /></p>
160
 
<p><label for="id_form-2-name">Name:</label> <input id="id_form-2-name" type="text" name="form-2-name" maxlength="100" /><input type="hidden" name="form-2-id" id="id_form-2-id" /></p>
161
 
 
162
 
 
163
 
>>> data = {
164
 
...     'form-TOTAL_FORMS': '3', # the number of forms rendered
165
 
...     'form-INITIAL_FORMS': '2', # the number of forms with initial data
166
 
...     'form-0-id': '2',
167
 
...     'form-0-name': 'Arthur Rimbaud',
168
 
...     'form-1-id': '1',
169
 
...     'form-1-name': 'Charles Baudelaire',
170
 
...     'form-2-name': 'Paul Verlaine',
171
 
... }
172
 
 
173
 
>>> formset = AuthorFormSet(data=data, queryset=qs)
174
 
>>> formset.is_valid()
175
 
True
176
 
 
177
 
# Only changed or new objects are returned from formset.save()
178
 
>>> formset.save()
179
 
[<Author: Paul Verlaine>]
180
 
 
181
 
>>> for author in Author.objects.order_by('name'):
182
 
...     print author.name
183
 
Arthur Rimbaud
184
 
Charles Baudelaire
185
 
Paul Verlaine
186
 
 
187
 
 
188
 
This probably shouldn't happen, but it will. If an add form was marked for
189
 
deltetion, make sure we don't save that form.
190
 
 
191
 
>>> qs = Author.objects.order_by('name')
192
 
>>> AuthorFormSet = modelformset_factory(Author, extra=1, can_delete=True)
193
 
 
194
 
>>> formset = AuthorFormSet(queryset=qs)
195
 
>>> for form in formset.forms:
196
 
...     print form.as_p()
197
 
<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" value="Arthur Rimbaud" maxlength="100" /></p>
198
 
<p><label for="id_form-0-DELETE">Delete:</label> <input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /><input type="hidden" name="form-0-id" value="2" id="id_form-0-id" /></p>
199
 
<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" value="Charles Baudelaire" maxlength="100" /></p>
200
 
<p><label for="id_form-1-DELETE">Delete:</label> <input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /><input type="hidden" name="form-1-id" value="1" id="id_form-1-id" /></p>
201
 
<p><label for="id_form-2-name">Name:</label> <input id="id_form-2-name" type="text" name="form-2-name" value="Paul Verlaine" maxlength="100" /></p>
202
 
<p><label for="id_form-2-DELETE">Delete:</label> <input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /><input type="hidden" name="form-2-id" value="3" id="id_form-2-id" /></p>
203
 
<p><label for="id_form-3-name">Name:</label> <input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /></p>
204
 
<p><label for="id_form-3-DELETE">Delete:</label> <input type="checkbox" name="form-3-DELETE" id="id_form-3-DELETE" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></p>
205
 
 
206
 
>>> data = {
207
 
...     'form-TOTAL_FORMS': '4', # the number of forms rendered
208
 
...     'form-INITIAL_FORMS': '3', # the number of forms with initial data
209
 
...     'form-0-id': '2',
210
 
...     'form-0-name': 'Arthur Rimbaud',
211
 
...     'form-1-id': '1',
212
 
...     'form-1-name': 'Charles Baudelaire',
213
 
...     'form-2-id': '3',
214
 
...     'form-2-name': 'Paul Verlaine',
215
 
...     'form-3-name': 'Walt Whitman',
216
 
...     'form-3-DELETE': 'on',
217
 
... }
218
 
 
219
 
>>> formset = AuthorFormSet(data=data, queryset=qs)
220
 
>>> formset.is_valid()
221
 
True
222
 
 
223
 
# No objects were changed or saved so nothing will come back.
224
 
>>> formset.save()
225
 
[]
226
 
 
227
 
>>> for author in Author.objects.order_by('name'):
228
 
...     print author.name
229
 
Arthur Rimbaud
230
 
Charles Baudelaire
231
 
Paul Verlaine
232
 
 
233
 
Let's edit a record to ensure save only returns that one record.
234
 
 
235
 
>>> data = {
236
 
...     'form-TOTAL_FORMS': '4', # the number of forms rendered
237
 
...     'form-INITIAL_FORMS': '3', # the number of forms with initial data
238
 
...     'form-0-id': '2',
239
 
...     'form-0-name': 'Walt Whitman',
240
 
...     'form-1-id': '1',
241
 
...     'form-1-name': 'Charles Baudelaire',
242
 
...     'form-2-id': '3',
243
 
...     'form-2-name': 'Paul Verlaine',
244
 
...     'form-3-name': '',
245
 
...     'form-3-DELETE': '',
246
 
... }
247
 
 
248
 
>>> formset = AuthorFormSet(data=data, queryset=qs)
249
 
>>> formset.is_valid()
250
 
True
251
 
 
252
 
# One record has changed.
253
 
>>> formset.save()
254
 
[<Author: Walt Whitman>]
255
 
 
256
 
Test the behavior of commit=False and save_m2m
257
 
 
258
 
>>> meeting = AuthorMeeting.objects.create(created=date.today())
259
 
>>> meeting.authors = Author.objects.all()
260
 
 
261
 
# create an Author instance to add to the meeting.
262
 
>>> new_author = Author.objects.create(name=u'John Steinbeck')
263
 
 
264
 
>>> AuthorMeetingFormSet = modelformset_factory(AuthorMeeting, extra=1, can_delete=True)
265
 
>>> data = {
266
 
...     'form-TOTAL_FORMS': '2', # the number of forms rendered
267
 
...     'form-INITIAL_FORMS': '1', # the number of forms with initial data
268
 
...     'form-0-id': '1',
269
 
...     'form-0-name': '2nd Tuesday of the Week Meeting',
270
 
...     'form-0-authors': [2, 1, 3, 4],
271
 
...     'form-1-name': '',
272
 
...     'form-1-authors': '',
273
 
...     'form-1-DELETE': '',
274
 
... }
275
 
>>> formset = AuthorMeetingFormSet(data=data, queryset=AuthorMeeting.objects.all())
276
 
>>> formset.is_valid()
277
 
True
278
 
>>> instances = formset.save(commit=False)
279
 
>>> for instance in instances:
280
 
...     instance.created = date.today()
281
 
...     instance.save()
282
 
>>> formset.save_m2m()
283
 
>>> instances[0].authors.all()
284
 
[<Author: Charles Baudelaire>, <Author: John Steinbeck>, <Author: Paul Verlaine>, <Author: Walt Whitman>]
285
 
 
286
 
# delete the author we created to allow later tests to continue working.
287
 
>>> new_author.delete()
288
 
 
289
 
Test the behavior of max_num with model formsets. It should properly limit
290
 
the queryset to reduce the amount of objects being pulled in when not being
291
 
used.
292
 
 
293
 
>>> qs = Author.objects.order_by('name')
294
 
 
295
 
>>> AuthorFormSet = modelformset_factory(Author, max_num=2)
296
 
>>> formset = AuthorFormSet(queryset=qs)
297
 
>>> [sorted(x.items()) for x in formset.initial]
298
 
[[('id', 1), ('name', u'Charles Baudelaire')], [('id', 3), ('name', u'Paul Verlaine')]]
299
 
 
300
 
>>> AuthorFormSet = modelformset_factory(Author, max_num=3)
301
 
>>> formset = AuthorFormSet(queryset=qs)
302
 
>>> [sorted(x.items()) for x in formset.initial]
303
 
[[('id', 1), ('name', u'Charles Baudelaire')], [('id', 3), ('name', u'Paul Verlaine')], [('id', 2), ('name', u'Walt Whitman')]]
304
 
 
305
 
# Model inheritance in model formsets ########################################
306
 
 
307
 
>>> BetterAuthorFormSet = modelformset_factory(BetterAuthor)
308
 
>>> formset = BetterAuthorFormSet()
309
 
>>> for form in formset.forms:
310
 
...     print form.as_p()
311
 
<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></p>
312
 
<p><label for="id_form-0-write_speed">Write speed:</label> <input type="text" name="form-0-write_speed" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" id="id_form-0-author_ptr" /></p>
313
 
 
314
 
>>> data = {
315
 
...     'form-TOTAL_FORMS': '1', # the number of forms rendered
316
 
...     'form-INITIAL_FORMS': '0', # the number of forms with initial data
317
 
...     'form-0-author_ptr': '',
318
 
...     'form-0-name': 'Ernest Hemingway',
319
 
...     'form-0-write_speed': '10',
320
 
... }
321
 
 
322
 
>>> formset = BetterAuthorFormSet(data)
323
 
>>> formset.is_valid()
324
 
True
325
 
>>> formset.save()
326
 
[<BetterAuthor: Ernest Hemingway>]
327
 
>>> hemingway_id = BetterAuthor.objects.get(name="Ernest Hemingway").pk
328
 
 
329
 
>>> formset = BetterAuthorFormSet()
330
 
>>> for form in formset.forms:
331
 
...     print form.as_p()
332
 
<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" value="Ernest Hemingway" maxlength="100" /></p>
333
 
<p><label for="id_form-0-write_speed">Write speed:</label> <input type="text" name="form-0-write_speed" value="10" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" value="..." id="id_form-0-author_ptr" /></p>
334
 
<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" maxlength="100" /></p>
335
 
<p><label for="id_form-1-write_speed">Write speed:</label> <input type="text" name="form-1-write_speed" id="id_form-1-write_speed" /><input type="hidden" name="form-1-author_ptr" id="id_form-1-author_ptr" /></p>
336
 
 
337
 
>>> data = {
338
 
...     'form-TOTAL_FORMS': '2', # the number of forms rendered
339
 
...     'form-INITIAL_FORMS': '1', # the number of forms with initial data
340
 
...     'form-0-author_ptr': hemingway_id,
341
 
...     'form-0-name': 'Ernest Hemingway',
342
 
...     'form-0-write_speed': '10',
343
 
...     'form-1-author_ptr': '',
344
 
...     'form-1-name': '',
345
 
...     'form-1-write_speed': '',
346
 
... }
347
 
 
348
 
>>> formset = BetterAuthorFormSet(data)
349
 
>>> formset.is_valid()
350
 
True
351
 
>>> formset.save()
352
 
[]
353
 
 
354
 
# Inline Formsets ############################################################
355
 
 
356
 
We can also create a formset that is tied to a parent model. This is how the
357
 
admin system's edit inline functionality works.
358
 
 
359
 
>>> from django.forms.models import inlineformset_factory
360
 
 
361
 
>>> AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=3)
362
 
>>> author = Author.objects.get(name='Charles Baudelaire')
363
 
 
364
 
>>> formset = AuthorBooksFormSet(instance=author)
365
 
>>> for form in formset.forms:
366
 
...     print form.as_p()
367
 
<p><label for="id_book_set-0-title">Title:</label> <input id="id_book_set-0-title" type="text" name="book_set-0-title" maxlength="100" /><input type="hidden" name="book_set-0-id" id="id_book_set-0-id" /></p>
368
 
<p><label for="id_book_set-1-title">Title:</label> <input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" /><input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>
369
 
<p><label for="id_book_set-2-title">Title:</label> <input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" /><input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>
370
 
 
371
 
>>> data = {
372
 
...     'book_set-TOTAL_FORMS': '3', # the number of forms rendered
373
 
...     'book_set-INITIAL_FORMS': '0', # the number of forms with initial data
374
 
...     'book_set-0-title': 'Les Fleurs du Mal',
375
 
...     'book_set-1-title': '',
376
 
...     'book_set-2-title': '',
377
 
... }
378
 
 
379
 
>>> formset = AuthorBooksFormSet(data, instance=author)
380
 
>>> formset.is_valid()
381
 
True
382
 
 
383
 
>>> formset.save()
384
 
[<Book: Les Fleurs du Mal>]
385
 
 
386
 
>>> for book in author.book_set.all():
387
 
...     print book.title
388
 
Les Fleurs du Mal
389
 
 
390
 
 
391
 
Now that we've added a book to Charles Baudelaire, let's try adding another
392
 
one. This time though, an edit form will be available for every existing
393
 
book.
394
 
 
395
 
>>> AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2)
396
 
>>> author = Author.objects.get(name='Charles Baudelaire')
397
 
 
398
 
>>> formset = AuthorBooksFormSet(instance=author)
399
 
>>> for form in formset.forms:
400
 
...     print form.as_p()
401
 
<p><label for="id_book_set-0-title">Title:</label> <input id="id_book_set-0-title" type="text" name="book_set-0-title" value="Les Fleurs du Mal" maxlength="100" /><input type="hidden" name="book_set-0-id" value="1" id="id_book_set-0-id" /></p>
402
 
<p><label for="id_book_set-1-title">Title:</label> <input id="id_book_set-1-title" type="text" name="book_set-1-title" maxlength="100" /><input type="hidden" name="book_set-1-id" id="id_book_set-1-id" /></p>
403
 
<p><label for="id_book_set-2-title">Title:</label> <input id="id_book_set-2-title" type="text" name="book_set-2-title" maxlength="100" /><input type="hidden" name="book_set-2-id" id="id_book_set-2-id" /></p>
404
 
 
405
 
>>> data = {
406
 
...     'book_set-TOTAL_FORMS': '3', # the number of forms rendered
407
 
...     'book_set-INITIAL_FORMS': '1', # the number of forms with initial data
408
 
...     'book_set-0-id': '1',
409
 
...     'book_set-0-title': 'Les Fleurs du Mal',
410
 
...     'book_set-1-title': 'Le Spleen de Paris',
411
 
...     'book_set-2-title': '',
412
 
... }
413
 
 
414
 
>>> formset = AuthorBooksFormSet(data, instance=author)
415
 
>>> formset.is_valid()
416
 
True
417
 
 
418
 
>>> formset.save()
419
 
[<Book: Le Spleen de Paris>]
420
 
 
421
 
As you can see, 'Le Spleen de Paris' is now a book belonging to Charles Baudelaire.
422
 
 
423
 
>>> for book in author.book_set.order_by('id'):
424
 
...     print book.title
425
 
Les Fleurs du Mal
426
 
Le Spleen de Paris
427
 
 
428
 
The save_as_new parameter lets you re-associate the data to a new instance.
429
 
This is used in the admin for save_as functionality.
430
 
 
431
 
>>> data = {
432
 
...     'book_set-TOTAL_FORMS': '3', # the number of forms rendered
433
 
...     'book_set-INITIAL_FORMS': '2', # the number of forms with initial data
434
 
...     'book_set-0-id': '1',
435
 
...     'book_set-0-title': 'Les Fleurs du Mal',
436
 
...     'book_set-1-id': '2',
437
 
...     'book_set-1-title': 'Le Spleen de Paris',
438
 
...     'book_set-2-title': '',
439
 
... }
440
 
 
441
 
>>> formset = AuthorBooksFormSet(data, instance=Author(), save_as_new=True)
442
 
>>> formset.is_valid()
443
 
True
444
 
 
445
 
>>> new_author = Author.objects.create(name='Charles Baudelaire')
446
 
>>> formset.instance = new_author
447
 
>>> [book for book in formset.save() if book.author.pk == new_author.pk]
448
 
[<Book: Les Fleurs du Mal>, <Book: Le Spleen de Paris>]
449
 
 
450
 
Test using a custom prefix on an inline formset.
451
 
 
452
 
>>> formset = AuthorBooksFormSet(prefix="test")
453
 
>>> for form in formset.forms:
454
 
...     print form.as_p()
455
 
<p><label for="id_test-0-title">Title:</label> <input id="id_test-0-title" type="text" name="test-0-title" maxlength="100" /><input type="hidden" name="test-0-id" id="id_test-0-id" /></p>
456
 
<p><label for="id_test-1-title">Title:</label> <input id="id_test-1-title" type="text" name="test-1-title" maxlength="100" /><input type="hidden" name="test-1-id" id="id_test-1-id" /></p>
457
 
 
458
 
# Test a custom primary key ###################################################
459
 
 
460
 
We need to ensure that it is displayed
461
 
 
462
 
>>> CustomPrimaryKeyFormSet = modelformset_factory(CustomPrimaryKey)
463
 
>>> formset = CustomPrimaryKeyFormSet()
464
 
>>> for form in formset.forms:
465
 
...     print form.as_p()
466
 
<p><label for="id_form-0-my_pk">My pk:</label> <input id="id_form-0-my_pk" type="text" name="form-0-my_pk" maxlength="10" /></p>
467
 
<p><label for="id_form-0-some_field">Some field:</label> <input id="id_form-0-some_field" type="text" name="form-0-some_field" maxlength="100" /></p>
468
 
 
469
 
# Custom primary keys with ForeignKey, OneToOneField and AutoField ############
470
 
 
471
 
>>> place = Place(name=u'Giordanos', city=u'Chicago')
472
 
>>> place.save()
473
 
 
474
 
>>> FormSet = inlineformset_factory(Place, Owner, extra=2, can_delete=False)
475
 
>>> formset = FormSet(instance=place)
476
 
>>> for form in formset.forms:
477
 
...     print form.as_p()
478
 
<p><label for="id_owner_set-0-name">Name:</label> <input id="id_owner_set-0-name" type="text" name="owner_set-0-name" maxlength="100" /><input type="hidden" name="owner_set-0-auto_id" id="id_owner_set-0-auto_id" /></p>
479
 
<p><label for="id_owner_set-1-name">Name:</label> <input id="id_owner_set-1-name" type="text" name="owner_set-1-name" maxlength="100" /><input type="hidden" name="owner_set-1-auto_id" id="id_owner_set-1-auto_id" /></p>
480
 
 
481
 
>>> data = {
482
 
...     'owner_set-TOTAL_FORMS': '2',
483
 
...     'owner_set-INITIAL_FORMS': '0',
484
 
...     'owner_set-0-auto_id': '',
485
 
...     'owner_set-0-name': u'Joe Perry',
486
 
...     'owner_set-1-auto_id': '',
487
 
...     'owner_set-1-name': '',
488
 
... }
489
 
>>> formset = FormSet(data, instance=place)
490
 
>>> formset.is_valid()
491
 
True
492
 
>>> formset.save()
493
 
[<Owner: Joe Perry at Giordanos>]
494
 
 
495
 
>>> formset = FormSet(instance=place)
496
 
>>> for form in formset.forms:
497
 
...     print form.as_p()
498
 
<p><label for="id_owner_set-0-name">Name:</label> <input id="id_owner_set-0-name" type="text" name="owner_set-0-name" value="Joe Perry" maxlength="100" /><input type="hidden" name="owner_set-0-auto_id" value="1" id="id_owner_set-0-auto_id" /></p>
499
 
<p><label for="id_owner_set-1-name">Name:</label> <input id="id_owner_set-1-name" type="text" name="owner_set-1-name" maxlength="100" /><input type="hidden" name="owner_set-1-auto_id" id="id_owner_set-1-auto_id" /></p>
500
 
<p><label for="id_owner_set-2-name">Name:</label> <input id="id_owner_set-2-name" type="text" name="owner_set-2-name" maxlength="100" /><input type="hidden" name="owner_set-2-auto_id" id="id_owner_set-2-auto_id" /></p>
501
 
 
502
 
>>> data = {
503
 
...     'owner_set-TOTAL_FORMS': '3',
504
 
...     'owner_set-INITIAL_FORMS': '1',
505
 
...     'owner_set-0-auto_id': u'1',
506
 
...     'owner_set-0-name': u'Joe Perry',
507
 
...     'owner_set-1-auto_id': '',
508
 
...     'owner_set-1-name': u'Jack Berry',
509
 
...     'owner_set-2-auto_id': '',
510
 
...     'owner_set-2-name': '',
511
 
... }
512
 
>>> formset = FormSet(data, instance=place)
513
 
>>> formset.is_valid()
514
 
True
515
 
>>> formset.save()
516
 
[<Owner: Jack Berry at Giordanos>]
517
 
 
518
 
# Ensure a custom primary key that is a ForeignKey or OneToOneField get rendered for the user to choose.
519
 
 
520
 
>>> FormSet = modelformset_factory(OwnerProfile)
521
 
>>> formset = FormSet()
522
 
>>> for form in formset.forms:
523
 
...     print form.as_p()
524
 
<p><label for="id_form-0-owner">Owner:</label> <select name="form-0-owner" id="id_form-0-owner">
525
 
<option value="" selected="selected">---------</option>
526
 
<option value="1">Joe Perry at Giordanos</option>
527
 
<option value="2">Jack Berry at Giordanos</option>
528
 
</select></p>
529
 
<p><label for="id_form-0-age">Age:</label> <input type="text" name="form-0-age" id="id_form-0-age" /></p>
530
 
 
531
 
>>> owner = Owner.objects.get(name=u'Joe Perry')
532
 
>>> FormSet = inlineformset_factory(Owner, OwnerProfile, max_num=1, can_delete=False)
533
 
 
534
 
>>> formset = FormSet(instance=owner)
535
 
>>> for form in formset.forms:
536
 
...     print form.as_p()
537
 
<p><label for="id_ownerprofile-0-age">Age:</label> <input type="text" name="ownerprofile-0-age" id="id_ownerprofile-0-age" /><input type="hidden" name="ownerprofile-0-owner" id="id_ownerprofile-0-owner" /></p>
538
 
 
539
 
>>> data = {
540
 
...     'ownerprofile-TOTAL_FORMS': '1',
541
 
...     'ownerprofile-INITIAL_FORMS': '0',
542
 
...     'ownerprofile-0-owner': '',
543
 
...     'ownerprofile-0-age': u'54',
544
 
... }
545
 
>>> formset = FormSet(data, instance=owner)
546
 
>>> formset.is_valid()
547
 
True
548
 
>>> formset.save()
549
 
[<OwnerProfile: Joe Perry is 54>]
550
 
 
551
 
>>> formset = FormSet(instance=owner)
552
 
>>> for form in formset.forms:
553
 
...     print form.as_p()
554
 
<p><label for="id_ownerprofile-0-age">Age:</label> <input type="text" name="ownerprofile-0-age" value="54" id="id_ownerprofile-0-age" /><input type="hidden" name="ownerprofile-0-owner" value="1" id="id_ownerprofile-0-owner" /></p>
555
 
 
556
 
>>> data = {
557
 
...     'ownerprofile-TOTAL_FORMS': '1',
558
 
...     'ownerprofile-INITIAL_FORMS': '1',
559
 
...     'ownerprofile-0-owner': u'1',
560
 
...     'ownerprofile-0-age': u'55',
561
 
... }
562
 
>>> formset = FormSet(data, instance=owner)
563
 
>>> formset.is_valid()
564
 
True
565
 
>>> formset.save()
566
 
[<OwnerProfile: Joe Perry is 55>]
567
 
 
568
 
# ForeignKey with unique=True should enforce max_num=1 
569
 
 
570
 
>>> FormSet = inlineformset_factory(Place, Location, can_delete=False)
571
 
>>> formset = FormSet(instance=place)
572
 
>>> for form in formset.forms:
573
 
...     print form.as_p()
574
 
<p><label for="id_location_set-0-lat">Lat:</label> <input id="id_location_set-0-lat" type="text" name="location_set-0-lat" maxlength="100" /></p>
575
 
<p><label for="id_location_set-0-lon">Lon:</label> <input id="id_location_set-0-lon" type="text" name="location_set-0-lon" maxlength="100" /><input type="hidden" name="location_set-0-id" id="id_location_set-0-id" /></p>
576
 
 
577
 
# Foreign keys in parents ########################################
578
 
 
579
 
>>> from django.forms.models import _get_foreign_key
580
 
 
581
 
>>> type(_get_foreign_key(Restaurant, Owner))
582
 
<class 'django.db.models.fields.related.ForeignKey'>
583
 
>>> type(_get_foreign_key(MexicanRestaurant, Owner))
584
 
<class 'django.db.models.fields.related.ForeignKey'>
585
 
 
586
 
# unique/unique_together validation ###########################################
587
 
 
588
 
>>> FormSet = modelformset_factory(Product, extra=1)
589
 
>>> data = {
590
 
...     'form-TOTAL_FORMS': '1',
591
 
...     'form-INITIAL_FORMS': '0',
592
 
...     'form-0-slug': 'car-red',
593
 
... }
594
 
>>> formset = FormSet(data)
595
 
>>> formset.is_valid()
596
 
True
597
 
>>> formset.save()
598
 
[<Product: car-red>]
599
 
 
600
 
>>> data = {
601
 
...     'form-TOTAL_FORMS': '1',
602
 
...     'form-INITIAL_FORMS': '0',
603
 
...     'form-0-slug': 'car-red',
604
 
... }
605
 
>>> formset = FormSet(data)
606
 
>>> formset.is_valid()
607
 
False
608
 
>>> formset.errors
609
 
[{'slug': [u'Product with this Slug already exists.']}]
610
 
 
611
 
# unique_together
612
 
 
613
 
>>> FormSet = modelformset_factory(Price, extra=1)
614
 
>>> data = {
615
 
...     'form-TOTAL_FORMS': '1',
616
 
...     'form-INITIAL_FORMS': '0',
617
 
...     'form-0-price': u'12.00',
618
 
...     'form-0-quantity': '1',
619
 
... }
620
 
>>> formset = FormSet(data)
621
 
>>> formset.is_valid()
622
 
True
623
 
>>> formset.save()
624
 
[<Price: 1 for 12.00>]
625
 
 
626
 
>>> data = {
627
 
...     'form-TOTAL_FORMS': '1',
628
 
...     'form-INITIAL_FORMS': '0',
629
 
...     'form-0-price': u'12.00',
630
 
...     'form-0-quantity': '1',
631
 
... }
632
 
>>> formset = FormSet(data)
633
 
>>> formset.is_valid()
634
 
False
635
 
>>> formset.errors
636
 
[{'__all__': [u'Price with this Price and Quantity already exists.']}]
637
 
 
638
 
# Use of callable defaults (see bug #7975).
639
 
 
640
 
>>> person = Person.objects.create(name='Ringo')
641
 
>>> FormSet = inlineformset_factory(Person, Membership, can_delete=False, extra=1)
642
 
>>> formset = FormSet(instance=person)
643
 
 
644
 
# Django will render a hidden field for model fields that have a callable
645
 
# default. This is required to ensure the value is tested for change correctly
646
 
# when determine what extra forms have changed to save.
647
 
 
648
 
>>> form = formset.forms[0] # this formset only has one form
649
 
>>> now = form.fields['date_joined'].initial
650
 
>>> print form.as_p()
651
 
<p><label for="id_membership_set-0-date_joined">Date joined:</label> <input type="text" name="membership_set-0-date_joined" value="..." id="id_membership_set-0-date_joined" /><input type="hidden" name="initial-membership_set-0-date_joined" value="..." id="id_membership_set-0-date_joined" /></p>
652
 
<p><label for="id_membership_set-0-karma">Karma:</label> <input type="text" name="membership_set-0-karma" id="id_membership_set-0-karma" /><input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p>
653
 
 
654
 
# test for validation with callable defaults. Validations rely on hidden fields
655
 
 
656
 
>>> data = {
657
 
...     'membership_set-TOTAL_FORMS': '1',
658
 
...     'membership_set-INITIAL_FORMS': '0',
659
 
...     'membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
660
 
...     'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
661
 
...     'membership_set-0-karma': '',
662
 
... }
663
 
>>> formset = FormSet(data, instance=person)
664
 
>>> formset.is_valid()
665
 
True
666
 
 
667
 
# now test for when the data changes
668
 
 
669
 
>>> one_day_later = now + datetime.timedelta(days=1)
670
 
>>> filled_data = {
671
 
...     'membership_set-TOTAL_FORMS': '1',
672
 
...     'membership_set-INITIAL_FORMS': '0',
673
 
...     'membership_set-0-date_joined': unicode(one_day_later.strftime('%Y-%m-%d %H:%M:%S')),
674
 
...     'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
675
 
...     'membership_set-0-karma': '',
676
 
... }
677
 
>>> formset = FormSet(filled_data, instance=person)
678
 
>>> formset.is_valid()
679
 
False
680
 
 
681
 
# now test with split datetime fields
682
 
 
683
 
>>> class MembershipForm(forms.ModelForm):
684
 
...     date_joined = forms.SplitDateTimeField(initial=now)
685
 
...     class Meta:
686
 
...         model = Membership
687
 
...     def __init__(self, **kwargs):
688
 
...         super(MembershipForm, self).__init__(**kwargs)
689
 
...         self.fields['date_joined'].widget = forms.SplitDateTimeWidget()
690
 
 
691
 
>>> FormSet = inlineformset_factory(Person, Membership, form=MembershipForm, can_delete=False, extra=1)
692
 
>>> data = {
693
 
...     'membership_set-TOTAL_FORMS': '1',
694
 
...     'membership_set-INITIAL_FORMS': '0',
695
 
...     'membership_set-0-date_joined_0': unicode(now.strftime('%Y-%m-%d')),
696
 
...     'membership_set-0-date_joined_1': unicode(now.strftime('%H:%M:%S')),
697
 
...     'initial-membership_set-0-date_joined': unicode(now.strftime('%Y-%m-%d %H:%M:%S')),
698
 
...     'membership_set-0-karma': '',
699
 
... }
700
 
>>> formset = FormSet(data, instance=person)
701
 
>>> formset.is_valid()
702
 
True
703
 
 
704
 
"""}