#34925: refresh_from_db() will not iterate through all of the fields listed in 
the
'fields' parameter.
-------------------------------------+-------------------------------------
               Reporter:  Andrew     |          Owner:  nobody
  Cordery                            |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  4.2
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  1
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 This one was killing me today.  If you pass the 'fields' parameter to
 {{{refresh_from_db}}} it is supposed to only remove those fields from
 {{{_prefetched_objects_cache}}} as described in the docs:
 
https://docs.djangoproject.com/en/4.2/ref/models/instances/#django.db.models.Model.refresh_from_db.

 Unfortunately, it modifies the 'fields' variable as it iterates through
 it:

 ''Line 694 of django.db.models.base.py:''
 {{{
             for field in fields:
                 if field in prefetched_objects_cache:
                     del prefetched_objects_cache[field]
                     fields.remove(field)
 }}}

 Modifying the list that we are iterating over causes some list items to be
 skipped.  For example here we would expected to see 'a', 'b', and 'c',
 removed from dict {{{d}}} but 'b' is skipped:

 {{{
 In [8]: d = dict(a=1,b=2, c=3)

 In [9]: fields = ['a','b','c']

 In [10]: for f in fields:
     ...:     print(f)
     ...:     if f in d:
     ...:         del d[f]
     ...:         fields.remove(f)
     ...:
 a
 c

 In [11]: fields
 Out[11]: ['b']
 In [12]: d
 Out[12]: {'b': 2}

 }}}

 I beieve that all that needs to be done to correct this is to create a
 copy of the list by wrapping fields in list(), like so:

 {{{
 In [13]: fields = ['a','b','c']

 In [14]: d=dict(a=1,b=2, c=3)

 In [15]: for f in list(fields):
     ...:     print(f)
     ...:     if f in d:
     ...:         del d[f]
     ...:         fields.remove(f)
     ...:
 a
 b
 c

 In [16]: d
 Out[16]: {}

 In [17]: fields
 Out[17]: []
 }}}

 Therefore as far as I can tell the fix to the django code would be as easy
 as wrapping fields in list():

 ''Line 694 of django.db.models.base.py:'' modified
 {{{
             for field in list(fields):
                 if field in prefetched_objects_cache:
                     del prefetched_objects_cache[field]
                     fields.remove(field)
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34925>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018b626f0809-ba4b776b-7246-44df-a5a9-c220ae15402f-000000%40eu-central-1.amazonses.com.

Reply via email to