@@ -32,6 +32,28 @@ def test_add_another(self):
3232        self .assertEqual (review .title , "Not so great" )
3333        self .assertEqual (review .rating , 1 )
3434
35+     def  test_no_change (self ):
36+         movie  =  Movie .objects .create (
37+             title = "Lion King" ,
38+             reviews = [Review (title = "Great!" , rating = 10 )],
39+         )
40+         data  =  {
41+             "title" : "Lion King" ,
42+             "reviews-0-title" : "Great!" ,
43+             "reviews-0-rating" : "10" ,
44+             "reviews-TOTAL_FORMS" : 2 ,
45+             "reviews-INITIAL_FORMS" : 1 ,
46+         }
47+         form  =  MovieForm (data , instance = movie )
48+         self .assertTrue (form .is_valid ())
49+         form .save ()
50+         self .assertEqual (form .changed_data , [])
51+         movie .refresh_from_db ()
52+         self .assertEqual (len (movie .reviews ), 1 )
53+         review  =  movie .reviews [0 ]
54+         self .assertEqual (review .title , "Great!" )
55+         self .assertEqual (review .rating , 10 )
56+ 
3557    def  test_update (self ):
3658        movie  =  Movie .objects .create (
3759            title = "Lion King" ,
@@ -47,6 +69,7 @@ def test_update(self):
4769        form  =  MovieForm (data , instance = movie )
4870        self .assertTrue (form .is_valid ())
4971        form .save ()
72+         self .assertEqual (form .changed_data , ["reviews" ])
5073        movie .refresh_from_db ()
5174        self .assertEqual (len (movie .reviews ), 1 )
5275        review  =  movie .reviews [0 ]
@@ -149,34 +172,38 @@ def test_delete_required(self):
149172        self .assertFalse (form .is_valid ())
150173        self .assertEqual (form .errors ["reviews" ], ["This field cannot be blank." ])
151174
152-     #     def test_nullable_field(self):
153-     #          """A nullable EmbeddedModelField  is removed  if all fields  are empty ."""
154-     #         author = Author .objects.create(
155-     #             name="Bob ",
156-     #             age=50 ,
157-     #             address=Address(city="NYC ", state="NY", zip_code="10001") ,
158-     #             billing_address=Address(city="NYC", state="NY", zip_code="10001"), 
159-     #         ) 
160-     #         data = { 
161-     #             "name ": "Bob ",
162-     #             "age ": 51 ,
163-     #             "address-po_box ": "",
164-     #             "address-city ": "New York City" ,
165-     #             "address-state ": "NY" ,
166-     #             "address-zip_code ": "10001 ",
167-     #             "billing_address-po_box ": "",
168-     #             "billing_address-city ": "",
169-     #             "billing_address-state ": "" ,
170-     #             "billing_address-zip_code ": "" ,
171-     #         }
172-     #          form = AuthorForm (data, instance=author )
173-     #         self.assertTrue(form.is_valid())
174-     #         form.save()
175-     #         author .refresh_from_db()
176-     #          self.assertIsNone(author.billing_address )
175+     def  test_nullable_field (self ):
176+         """A nullable field  is emptied  if all rows  are deleted .""" 
177+         movie   =   Movie .objects .create (
178+             title = "Lion King "
179+             reviews = [ Review ( title = "Great!" ,  rating = 10 )] ,
180+             featured_reviews = [ Review ( title = "Okay "rating = 5 )] ,
181+         ) 
182+         data   =  { 
183+             "title" :  "Lion King" , 
184+             "reviews-0-title ""Not so great " ,
185+             "reviews-0-rating ""1" ,
186+             "reviews-0-DELETE """ ,
187+             "reviews-TOTAL_FORMS "2 ,
188+             "reviews-INITIAL_FORMS "1 ,
189+             "featured-reviews-0-title ""Okay " ,
190+             "featured-reviews-0-rating ""5 " ,
191+             "featured-reviews-0-DELETE ""1 " ,
192+             "featured-reviews-TOTAL_FORMS "2 ,
193+             "featured-reviews-INITIAL_FORMS "1 ,
194+         }
195+         form  =  MovieForm (data , instance = movie )
196+         self .assertTrue (form .is_valid ())
197+         form .save ()
198+         movie .refresh_from_db ()
199+         self .assertEqual ( len ( movie . featured_reviews ),  0 )
177200
178201    def  test_rendering (self ):
179202        form  =  MovieForm ()
203+         self .assertHTMLEqual (
204+             str (form .fields ["reviews" ].get_bound_field (form , "reviews" ).label_tag ()),
205+             '<label for="id_reviews">Reviews:</label>' ,
206+         )
180207        self .assertHTMLEqual (
181208            str (form .fields ["reviews" ].get_bound_field (form , "reviews" )),
182209            """ 
@@ -209,6 +236,64 @@ def test_rendering(self):
209236                name="reviews-MAX_NUM_FORMS" value="1000" id="id_reviews-MAX_NUM_FORMS">""" ,
210237        )
211238
239+     def  test_rendering_initial (self ):
240+         movie  =  Movie .objects .create (
241+             title = "Lion King" ,
242+             reviews = [Review (title = "Great!" , rating = 10 )],
243+         )
244+         form  =  MovieForm (instance = movie )
245+         self .assertHTMLEqual (
246+             str (form .fields ["reviews" ].get_bound_field (form , "reviews" )),
247+             """ 
248+             <table> 
249+             <tbody><tr> 
250+                 <th><label for="id_reviews-0-title">Title:</label></th> 
251+                 <td> 
252+                   <input type="text" name="reviews-0-title" maxlength="255" 
253+                     id="id_reviews-0-title" value="Great!"> 
254+                 </td> 
255+               </tr> 
256+               <tr> 
257+                 <th><label for="id_reviews-0-rating">Rating:</label></th> 
258+                 <td> 
259+                   <input type="number" name="reviews-0-rating" 
260+                     id="id_reviews-0-rating" value="10"> 
261+                 </td> 
262+               </tr> 
263+               <tr> 
264+                 <th><label for="id_reviews-0-DELETE">Delete:</label></th> 
265+                 <td> 
266+                   <input type="checkbox" name="reviews-0-DELETE" id="id_reviews-0-DELETE"> 
267+                 </td> 
268+               </tr></tbody> 
269+             <tbody><tr> 
270+                 <th><label for="id_reviews-1-title">Title:</label></th> 
271+                 <td> 
272+                   <input type="text" name="reviews-1-title" maxlength="255" id="id_reviews-1-title"> 
273+                 </td> 
274+               </tr> 
275+               <tr> 
276+                 <th><label for="id_reviews-1-rating">Rating:</label></th> 
277+                 <td> 
278+                   <input type="number" name="reviews-1-rating" id="id_reviews-1-rating"> 
279+                 </td> 
280+               </tr> 
281+               <tr> 
282+                 <th><label for="id_reviews-1-DELETE">Delete:</label></th> 
283+                 <td> 
284+                   <input type="checkbox" name="reviews-1-DELETE" id="id_reviews-1-DELETE"> 
285+                 </td> 
286+               </tr></tbody> 
287+             </table> 
288+             <input type="hidden" name="reviews-TOTAL_FORMS" value="2" 
289+                 id="id_reviews-TOTAL_FORMS"><input type="hidden" 
290+                 name="reviews-INITIAL_FORMS" value="1" 
291+                 id="id_reviews-INITIAL_FORMS"> 
292+             <input type="hidden" name="reviews-MIN_NUM_FORMS" value="0" 
293+                 id="id_reviews-MIN_NUM_FORMS"><input type="hidden" 
294+                 name="reviews-MAX_NUM_FORMS" value="1000" id="id_reviews-MAX_NUM_FORMS">""" ,
295+         )
296+ 
212297
213298# class NestedFormTests(TestCase): 
214299#    def test_update(self): 
0 commit comments