33
33
from django .db .models .expressions import DatabaseDefault
34
34
from django .db .models .fields .composite import CompositePrimaryKey
35
35
from django .db .models .fields .related import (
36
+ ForeignObject ,
36
37
ForeignObjectRel ,
37
38
OneToOneField ,
38
39
lazy_related_operation ,
@@ -680,6 +681,52 @@ def get_deferred_fields(self):
680
681
if f .attname not in self .__dict__
681
682
}
682
683
684
+ def _refresh_from_db_with_foreign_object (self ):
685
+ """
686
+ Refreshes the current instance from the database, taking into account
687
+ ForeignObject fields and composite primary keys.
688
+ This is a private helper method and should only be invoked by
689
+ refresh_from_db().
690
+ """
691
+ from_queryset = self .__class__ .objects
692
+
693
+ # Collect fields from ForeignObject and PK
694
+ composite_fields = [
695
+ field
696
+ for field in self ._meta .fields
697
+ if isinstance (field , ForeignObject )
698
+ or (
699
+ hasattr (self ._meta .pk , "fields" )
700
+ and field .attname in [f .attname for f in self ._meta .pk .fields ]
701
+ )
702
+ or field .attname == self ._meta .pk .attname
703
+ ]
704
+
705
+ # Raw data without avoiding the cache
706
+ original_values = {
707
+ field .attname : self .__dict__ .get (field .attname )
708
+ for field in composite_fields
709
+ if self .__dict__ .get (field .attname ) is not None
710
+ }
711
+
712
+ if not original_values :
713
+ raise ValueError ("Impossible to find the object: key not found." )
714
+
715
+ try :
716
+ # Query instance from DB
717
+ db_instance = from_queryset .get (** original_values )
718
+ except self .__class__ .DoesNotExist :
719
+ raise self .__class__ .DoesNotExist (
720
+ f"{ self .__class__ .__name__ } matching query does not exist. "
721
+ f"Values: { original_values } "
722
+ )
723
+
724
+ # Update instance with data from DB
725
+ for field in self ._meta .fields :
726
+ setattr (self , field .attname , getattr (db_instance , field .attname ))
727
+
728
+ self ._state .db = db_instance ._state .db
729
+
683
730
def refresh_from_db (self , using = None , fields = None , from_queryset = None ):
684
731
"""
685
732
Reload field values from the database.
@@ -711,7 +758,6 @@ def refresh_from_db(self, using=None, fields=None, from_queryset=None):
711
758
'Found "%s" in fields argument. Relations and transforms '
712
759
"are not allowed in fields." % LOOKUP_SEP
713
760
)
714
-
715
761
if from_queryset is None :
716
762
hints = {"instance" : self }
717
763
from_queryset = self .__class__ ._base_manager .db_manager (using , hints = hints )
@@ -733,6 +779,9 @@ def refresh_from_db(self, using=None, fields=None, from_queryset=None):
733
779
}
734
780
)
735
781
782
+ if any (type (field ) is ForeignObject for field in self ._meta .get_fields ()):
783
+ return self ._refresh_from_db_with_foreign_object ()
784
+
736
785
db_instance = db_instance_qs .get ()
737
786
non_loaded_fields = db_instance .get_deferred_fields ()
738
787
for field in self ._meta .concrete_fields :
0 commit comments