plain.models 0.38.0__py3-none-any.whl → 0.39.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. plain/models/CHANGELOG.md +31 -0
  2. plain/models/README.md +31 -0
  3. plain/models/__init__.py +2 -2
  4. plain/models/backends/base/creation.py +1 -1
  5. plain/models/backends/base/operations.py +1 -3
  6. plain/models/backends/base/schema.py +4 -8
  7. plain/models/backends/mysql/base.py +1 -3
  8. plain/models/backends/mysql/introspection.py +2 -6
  9. plain/models/backends/mysql/operations.py +2 -4
  10. plain/models/backends/postgresql/base.py +2 -6
  11. plain/models/backends/postgresql/introspection.py +2 -6
  12. plain/models/backends/postgresql/operations.py +1 -3
  13. plain/models/backends/postgresql/schema.py +2 -10
  14. plain/models/backends/sqlite3/base.py +2 -6
  15. plain/models/backends/sqlite3/introspection.py +2 -8
  16. plain/models/base.py +46 -74
  17. plain/models/constraints.py +3 -3
  18. plain/models/deletion.py +9 -9
  19. plain/models/fields/__init__.py +30 -104
  20. plain/models/fields/related.py +90 -343
  21. plain/models/fields/related_descriptors.py +14 -14
  22. plain/models/fields/related_lookups.py +2 -2
  23. plain/models/fields/reverse_related.py +6 -14
  24. plain/models/forms.py +14 -76
  25. plain/models/lookups.py +2 -2
  26. plain/models/migrations/autodetector.py +2 -25
  27. plain/models/migrations/operations/fields.py +0 -6
  28. plain/models/migrations/state.py +2 -26
  29. plain/models/migrations/utils.py +4 -14
  30. plain/models/options.py +4 -12
  31. plain/models/query.py +46 -54
  32. plain/models/query_utils.py +3 -5
  33. plain/models/sql/compiler.py +16 -18
  34. plain/models/sql/query.py +12 -11
  35. plain/models/sql/subqueries.py +10 -10
  36. {plain_models-0.38.0.dist-info → plain_models-0.39.1.dist-info}/METADATA +32 -1
  37. {plain_models-0.38.0.dist-info → plain_models-0.39.1.dist-info}/RECORD +40 -40
  38. {plain_models-0.38.0.dist-info → plain_models-0.39.1.dist-info}/WHEEL +0 -0
  39. {plain_models-0.38.0.dist-info → plain_models-0.39.1.dist-info}/entry_points.txt +0 -0
  40. {plain_models-0.38.0.dist-info → plain_models-0.39.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,3 @@
1
- import functools
2
- import inspect
3
1
  from functools import cached_property, partial
4
2
 
5
3
  from plain import exceptions, preflight
@@ -27,7 +25,7 @@ from .related_lookups import (
27
25
  RelatedLessThan,
28
26
  RelatedLessThanOrEqual,
29
27
  )
30
- from .reverse_related import ForeignObjectRel, ManyToManyRel, ManyToOneRel
28
+ from .reverse_related import ManyToManyRel, ManyToOneRel
31
29
 
32
30
  RECURSIVE_RELATIONSHIP_CONSTANT = "self"
33
31
 
@@ -367,25 +365,15 @@ class RelatedField(FieldCacheMixin, Field):
367
365
  select all instances of self.related_field.model related through
368
366
  this field to obj. obj is an instance of self.model.
369
367
  """
370
- base_q = Q.create(
368
+ return Q.create(
371
369
  [
372
370
  (rh_field.attname, getattr(obj, lh_field.attname))
373
371
  for lh_field, rh_field in self.related_fields
374
372
  ]
375
373
  )
376
- descriptor_filter = self.get_extra_descriptor_filter(obj)
377
- if isinstance(descriptor_filter, dict):
378
- return base_q & Q(**descriptor_filter)
379
- elif descriptor_filter:
380
- return base_q & descriptor_filter
381
- return base_q
382
374
 
383
375
  def set_attributes_from_rel(self):
384
- self.name = self.name or (
385
- self.remote_field.model._meta.model_name
386
- + "_"
387
- + self.remote_field.model._meta.pk.name
388
- )
376
+ self.name = self.name or (self.remote_field.model._meta.model_name + "_" + "id")
389
377
  self.remote_field.set_field_name()
390
378
 
391
379
  def do_related_class(self, other, cls):
@@ -432,44 +420,58 @@ class RelatedField(FieldCacheMixin, Field):
432
420
  return self.name
433
421
 
434
422
 
435
- class ForeignObject(RelatedField):
436
- """
437
- Abstraction of the ForeignKey relation to support multi-column relations.
423
+ class ForeignKey(RelatedField):
438
424
  """
425
+ Provide a many-to-one relation by adding a column to the local model
426
+ to hold the remote value.
439
427
 
440
- # Field flags
441
- many_to_many = False
442
- many_to_one = True
443
- one_to_many = False
428
+ ForeignKey targets the primary key (id) of the remote model.
429
+ """
444
430
 
445
- requires_unique_target = True
431
+ descriptor_class = ForeignKeyDeferredAttribute
446
432
  related_accessor_class = ReverseManyToOneDescriptor
447
433
  forward_related_accessor_class = ForwardManyToOneDescriptor
448
- rel_class = ForeignObjectRel
434
+ rel_class = ManyToOneRel
435
+
436
+ # Field flags - ForeignKey is many-to-one
437
+ many_to_one = True
438
+
439
+ empty_strings_allowed = False
440
+ default_error_messages = {
441
+ "invalid": "%(model)s instance with %(field)s %(value)r does not exist."
442
+ }
443
+ description = "Foreign Key (type determined by related field)"
449
444
 
450
445
  def __init__(
451
446
  self,
452
447
  to,
453
448
  on_delete,
454
- from_fields,
455
- to_fields,
456
- rel=None,
457
449
  related_name=None,
458
450
  related_query_name=None,
459
451
  limit_choices_to=None,
460
- parent_link=False,
452
+ db_index=True,
453
+ db_constraint=True,
461
454
  **kwargs,
462
455
  ):
463
- if rel is None:
464
- rel = self.rel_class(
465
- self,
466
- to,
467
- related_name=related_name,
468
- related_query_name=related_query_name,
469
- limit_choices_to=limit_choices_to,
470
- parent_link=parent_link,
471
- on_delete=on_delete,
472
- )
456
+ try:
457
+ to._meta.model_name
458
+ except AttributeError:
459
+ if not isinstance(to, str):
460
+ raise TypeError(
461
+ f"{self.__class__.__name__}({to!r}) is invalid. First parameter to ForeignKey must be "
462
+ f"either a model, a model name, or the string {RECURSIVE_RELATIONSHIP_CONSTANT!r}"
463
+ )
464
+ if not callable(on_delete):
465
+ raise TypeError("on_delete must be callable.")
466
+
467
+ rel = self.rel_class(
468
+ self,
469
+ to,
470
+ related_name=related_name,
471
+ related_query_name=related_query_name,
472
+ limit_choices_to=limit_choices_to,
473
+ on_delete=on_delete,
474
+ )
473
475
 
474
476
  super().__init__(
475
477
  rel=rel,
@@ -478,9 +480,8 @@ class ForeignObject(RelatedField):
478
480
  limit_choices_to=limit_choices_to,
479
481
  **kwargs,
480
482
  )
481
-
482
- self.from_fields = from_fields
483
- self.to_fields = to_fields
483
+ self.db_index = db_index
484
+ self.db_constraint = db_constraint
484
485
 
485
486
  def __copy__(self):
486
487
  obj = super().__copy__()
@@ -489,143 +490,6 @@ class ForeignObject(RelatedField):
489
490
  obj.__dict__.pop("reverse_path_infos", None)
490
491
  return obj
491
492
 
492
- def check(self, **kwargs):
493
- return [
494
- *super().check(**kwargs),
495
- *self._check_to_fields_exist(),
496
- *self._check_unique_target(),
497
- ]
498
-
499
- def _check_to_fields_exist(self):
500
- # Skip nonexistent models.
501
- if isinstance(self.remote_field.model, str):
502
- return []
503
-
504
- errors = []
505
- for to_field in self.to_fields:
506
- if to_field:
507
- try:
508
- self.remote_field.model._meta.get_field(to_field)
509
- except exceptions.FieldDoesNotExist:
510
- errors.append(
511
- preflight.Error(
512
- f"The to_field '{to_field}' doesn't exist on the related "
513
- f"model '{self.remote_field.model._meta.label}'.",
514
- obj=self,
515
- id="fields.E312",
516
- )
517
- )
518
- return errors
519
-
520
- def _check_unique_target(self):
521
- rel_is_string = isinstance(self.remote_field.model, str)
522
- if rel_is_string or not self.requires_unique_target:
523
- return []
524
-
525
- try:
526
- self.foreign_related_fields
527
- except exceptions.FieldDoesNotExist:
528
- return []
529
-
530
- if not self.foreign_related_fields:
531
- return []
532
-
533
- unique_foreign_fields = {
534
- frozenset([f.name])
535
- for f in self.remote_field.model._meta.get_fields()
536
- if getattr(f, "primary_key", False)
537
- }
538
- unique_foreign_fields.update(
539
- {
540
- frozenset(uc.fields)
541
- for uc in self.remote_field.model._meta.total_unique_constraints
542
- }
543
- )
544
- foreign_fields = {f.name for f in self.foreign_related_fields}
545
- has_unique_constraint = any(u <= foreign_fields for u in unique_foreign_fields)
546
-
547
- if not has_unique_constraint and len(self.foreign_related_fields) > 1:
548
- field_combination = ", ".join(
549
- f"'{rel_field.name}'" for rel_field in self.foreign_related_fields
550
- )
551
- model_name = self.remote_field.model.__name__
552
- return [
553
- preflight.Error(
554
- f"No subset of the fields {field_combination} on model '{model_name}' is unique.",
555
- hint=(
556
- "Add a set of "
557
- "fields to a unique constraint (via "
558
- "a UniqueConstraint (without condition) in the "
559
- "model Meta.constraints)."
560
- ),
561
- obj=self,
562
- id="fields.E310",
563
- )
564
- ]
565
- elif not has_unique_constraint:
566
- field_name = self.foreign_related_fields[0].name
567
- model_name = self.remote_field.model.__name__
568
- return [
569
- preflight.Error(
570
- f"'{model_name}.{field_name}' must be unique because it is referenced by "
571
- "a foreign key.",
572
- hint=(
573
- "Add a UniqueConstraint (without condition) in the model "
574
- "Meta.constraints."
575
- ),
576
- obj=self,
577
- id="fields.E311",
578
- )
579
- ]
580
- else:
581
- return []
582
-
583
- def deconstruct(self):
584
- name, path, args, kwargs = super().deconstruct()
585
- kwargs["on_delete"] = self.remote_field.on_delete
586
- kwargs["from_fields"] = self.from_fields
587
- kwargs["to_fields"] = self.to_fields
588
-
589
- if self.remote_field.parent_link:
590
- kwargs["parent_link"] = self.remote_field.parent_link
591
- if isinstance(self.remote_field.model, SettingsReference):
592
- kwargs["to"] = self.remote_field.model
593
- elif isinstance(self.remote_field.model, str):
594
- if "." in self.remote_field.model:
595
- package_label, model_name = self.remote_field.model.split(".")
596
- kwargs["to"] = f"{package_label}.{model_name.lower()}"
597
- else:
598
- kwargs["to"] = self.remote_field.model.lower()
599
- else:
600
- kwargs["to"] = self.remote_field.model._meta.label_lower
601
- return name, path, args, kwargs
602
-
603
- def resolve_related_fields(self):
604
- if not self.from_fields or len(self.from_fields) != len(self.to_fields):
605
- raise ValueError(
606
- "Foreign Object from and to fields must be the same non-zero length"
607
- )
608
- if isinstance(self.remote_field.model, str):
609
- raise ValueError(
610
- f"Related model {self.remote_field.model!r} cannot be resolved"
611
- )
612
- related_fields = []
613
- for index in range(len(self.from_fields)):
614
- from_field_name = self.from_fields[index]
615
- to_field_name = self.to_fields[index]
616
- from_field = (
617
- self
618
- if from_field_name == RECURSIVE_RELATIONSHIP_CONSTANT
619
- else self.opts.get_field(from_field_name)
620
- )
621
- to_field = (
622
- self.remote_field.model._meta.pk
623
- if to_field_name is None
624
- else self.remote_field.model._meta.get_field(to_field_name)
625
- )
626
- related_fields.append((from_field, to_field))
627
- return related_fields
628
-
629
493
  @cached_property
630
494
  def related_fields(self):
631
495
  return self.resolve_related_fields()
@@ -645,52 +509,28 @@ class ForeignObject(RelatedField):
645
509
  )
646
510
 
647
511
  def get_local_related_value(self, instance):
648
- return self.get_instance_value_for_fields(instance, self.local_related_fields)
512
+ # Always returns the value of the single local field
513
+ field = self.local_related_fields[0]
514
+ if field.primary_key:
515
+ return (instance.id,)
516
+ return (getattr(instance, field.attname),)
649
517
 
650
518
  def get_foreign_related_value(self, instance):
651
- return self.get_instance_value_for_fields(instance, self.foreign_related_fields)
652
-
653
- @staticmethod
654
- def get_instance_value_for_fields(instance, fields):
655
- ret = []
656
- for field in fields:
657
- # Gotcha: in some cases (like fixture loading) a model can have
658
- # different values in parent_ptr_id and parent's id. So, use
659
- # instance.pk (that is, parent_ptr_id) when asked for instance.id.
660
- if field.primary_key:
661
- ret.append(instance.pk)
662
- continue
663
- ret.append(getattr(instance, field.attname))
664
- return tuple(ret)
665
-
666
- def get_attname_column(self):
667
- attname, column = super().get_attname_column()
668
- return attname, None
519
+ # Always returns the id of the foreign instance
520
+ return (instance.id,)
669
521
 
670
522
  def get_joining_columns(self, reverse_join=False):
671
- source = self.reverse_related_fields if reverse_join else self.related_fields
672
- return tuple(
673
- (lhs_field.column, rhs_field.column) for lhs_field, rhs_field in source
674
- )
523
+ # Always returns a single column pair
524
+ if reverse_join:
525
+ from_field, to_field = self.related_fields[0]
526
+ return ((to_field.column, from_field.column),)
527
+ else:
528
+ from_field, to_field = self.related_fields[0]
529
+ return ((from_field.column, to_field.column),)
675
530
 
676
531
  def get_reverse_joining_columns(self):
677
532
  return self.get_joining_columns(reverse_join=True)
678
533
 
679
- def get_extra_descriptor_filter(self, instance):
680
- """
681
- Return an extra filter condition for related object fetching when
682
- user does 'instance.fieldname', that is the extra filter is used in
683
- the descriptor of the field.
684
-
685
- The filter should be either a dict usable in .filter(**kwargs) call or
686
- a Q-object. The condition will be ANDed together with the relation's
687
- joining columns.
688
-
689
- A parallel method is get_extra_restriction() which is used in
690
- JOIN and subquery conditions.
691
- """
692
- return {}
693
-
694
534
  def get_extra_restriction(self, alias, related_alias):
695
535
  """
696
536
  Return a pair condition used for joining and subquery pushdown. The
@@ -733,7 +573,7 @@ class ForeignObject(RelatedField):
733
573
  PathInfo(
734
574
  from_opts=from_opts,
735
575
  to_opts=opts,
736
- target_fields=(opts.pk,),
576
+ target_fields=(opts.get_field("id"),),
737
577
  join_field=self.remote_field,
738
578
  m2m=not self.primary_key,
739
579
  direct=False,
@@ -745,14 +585,6 @@ class ForeignObject(RelatedField):
745
585
  def reverse_path_infos(self):
746
586
  return self.get_reverse_path_info()
747
587
 
748
- @classmethod
749
- @functools.cache
750
- def get_class_lookups(cls):
751
- bases = inspect.getmro(cls)
752
- bases = bases[: bases.index(ForeignObject) + 1]
753
- class_lookups = [parent.__dict__.get("class_lookups", {}) for parent in bases]
754
- return cls.merge_dicts(class_lookups)
755
-
756
588
  def contribute_to_class(self, cls, name, private_only=False, **kwargs):
757
589
  super().contribute_to_class(cls, name, private_only=private_only, **kwargs)
758
590
  setattr(cls, self.name, self.forward_related_accessor_class(self))
@@ -773,95 +605,6 @@ class ForeignObject(RelatedField):
773
605
  self.remote_field.limit_choices_to
774
606
  )
775
607
 
776
-
777
- ForeignObject.register_lookup(RelatedIn)
778
- ForeignObject.register_lookup(RelatedExact)
779
- ForeignObject.register_lookup(RelatedLessThan)
780
- ForeignObject.register_lookup(RelatedGreaterThan)
781
- ForeignObject.register_lookup(RelatedGreaterThanOrEqual)
782
- ForeignObject.register_lookup(RelatedLessThanOrEqual)
783
- ForeignObject.register_lookup(RelatedIsNull)
784
-
785
-
786
- class ForeignKey(ForeignObject):
787
- """
788
- Provide a many-to-one relation by adding a column to the local model
789
- to hold the remote value.
790
-
791
- By default ForeignKey will target the pk of the remote model but this
792
- behavior can be changed by using the ``to_field`` argument.
793
- """
794
-
795
- descriptor_class = ForeignKeyDeferredAttribute
796
- # Field flags
797
- many_to_many = False
798
- many_to_one = True
799
- one_to_many = False
800
-
801
- rel_class = ManyToOneRel
802
-
803
- empty_strings_allowed = False
804
- default_error_messages = {
805
- "invalid": "%(model)s instance with %(field)s %(value)r does not exist."
806
- }
807
- description = "Foreign Key (type determined by related field)"
808
-
809
- def __init__(
810
- self,
811
- to,
812
- on_delete,
813
- related_name=None,
814
- related_query_name=None,
815
- limit_choices_to=None,
816
- parent_link=False,
817
- to_field=None,
818
- db_index=True,
819
- db_constraint=True,
820
- **kwargs,
821
- ):
822
- try:
823
- to._meta.model_name
824
- except AttributeError:
825
- if not isinstance(to, str):
826
- raise TypeError(
827
- f"{self.__class__.__name__}({to!r}) is invalid. First parameter to ForeignKey must be "
828
- f"either a model, a model name, or the string {RECURSIVE_RELATIONSHIP_CONSTANT!r}"
829
- )
830
- else:
831
- # For backwards compatibility purposes, we need to *try* and set
832
- # the to_field during FK construction. It won't be guaranteed to
833
- # be correct until contribute_to_class is called. Refs #12190.
834
- to_field = to_field or (to._meta.pk and to._meta.pk.name)
835
- if not callable(on_delete):
836
- raise TypeError("on_delete must be callable.")
837
-
838
- kwargs["rel"] = self.rel_class(
839
- self,
840
- to,
841
- to_field,
842
- related_name=related_name,
843
- related_query_name=related_query_name,
844
- limit_choices_to=limit_choices_to,
845
- parent_link=parent_link,
846
- on_delete=on_delete,
847
- )
848
-
849
- super().__init__(
850
- to,
851
- on_delete,
852
- related_name=related_name,
853
- related_query_name=related_query_name,
854
- limit_choices_to=limit_choices_to,
855
- from_fields=[RECURSIVE_RELATIONSHIP_CONSTANT],
856
- to_fields=[to_field],
857
- **kwargs,
858
- )
859
- self.db_index = db_index
860
- self.db_constraint = db_constraint
861
-
862
- def __class_getitem__(cls, *args, **kwargs):
863
- return cls
864
-
865
608
  def check(self, **kwargs):
866
609
  return [
867
610
  *super().check(**kwargs),
@@ -896,8 +639,18 @@ class ForeignKey(ForeignObject):
896
639
 
897
640
  def deconstruct(self):
898
641
  name, path, args, kwargs = super().deconstruct()
899
- del kwargs["to_fields"]
900
- del kwargs["from_fields"]
642
+ kwargs["on_delete"] = self.remote_field.on_delete
643
+
644
+ if isinstance(self.remote_field.model, SettingsReference):
645
+ kwargs["to"] = self.remote_field.model
646
+ elif isinstance(self.remote_field.model, str):
647
+ if "." in self.remote_field.model:
648
+ package_label, model_name = self.remote_field.model.split(".")
649
+ kwargs["to"] = f"{package_label}.{model_name.lower()}"
650
+ else:
651
+ kwargs["to"] = self.remote_field.model.lower()
652
+ else:
653
+ kwargs["to"] = self.remote_field.model._meta.label_lower
901
654
 
902
655
  if self.db_index is not True:
903
656
  kwargs["db_index"] = self.db_index
@@ -905,13 +658,6 @@ class ForeignKey(ForeignObject):
905
658
  if self.db_constraint is not True:
906
659
  kwargs["db_constraint"] = self.db_constraint
907
660
 
908
- # Rel needs more work.
909
- to_meta = getattr(self.remote_field.model, "_meta", None)
910
- if self.remote_field.field_name and (
911
- not to_meta
912
- or (to_meta.pk and self.remote_field.field_name != to_meta.pk.name)
913
- ):
914
- kwargs["to_field"] = self.remote_field.field_name
915
661
  return name, path, args, kwargs
916
662
 
917
663
  def to_python(self, value):
@@ -922,8 +668,6 @@ class ForeignKey(ForeignObject):
922
668
  return self.foreign_related_fields[0]
923
669
 
924
670
  def validate(self, value, model_instance):
925
- if self.remote_field.parent_link:
926
- return
927
671
  super().validate(value, model_instance)
928
672
  if value is None:
929
673
  return
@@ -938,14 +682,21 @@ class ForeignKey(ForeignObject):
938
682
  code="invalid",
939
683
  params={
940
684
  "model": self.remote_field.model._meta.model_name,
941
- "pk": value,
685
+ "id": value,
942
686
  "field": self.remote_field.field_name,
943
687
  "value": value,
944
- }, # 'pk' is included for backwards compatibility
688
+ },
945
689
  )
946
690
 
947
691
  def resolve_related_fields(self):
948
- related_fields = super().resolve_related_fields()
692
+ if isinstance(self.remote_field.model, str):
693
+ raise ValueError(
694
+ f"Related model {self.remote_field.model!r} cannot be resolved"
695
+ )
696
+ from_field = self
697
+ to_field = self.remote_field.model._meta.get_field("id")
698
+ related_fields = [(from_field, to_field)]
699
+
949
700
  for from_field, to_field in related_fields:
950
701
  if (
951
702
  to_field
@@ -986,11 +737,6 @@ class ForeignKey(ForeignObject):
986
737
  def get_prep_value(self, value):
987
738
  return self.target_field.get_prep_value(value)
988
739
 
989
- def contribute_to_related_class(self, cls, related):
990
- super().contribute_to_related_class(cls, related)
991
- if self.remote_field.field_name is None:
992
- self.remote_field.field_name = cls._meta.pk.name
993
-
994
740
  def db_check(self, connection):
995
741
  return None
996
742
 
@@ -1008,15 +754,6 @@ class ForeignKey(ForeignObject):
1008
754
  "collation": target_db_parameters.get("collation"),
1009
755
  }
1010
756
 
1011
- def convert_empty_strings(self, value, expression, connection):
1012
- if (not value) and isinstance(value, str):
1013
- return None
1014
- return value
1015
-
1016
- def get_db_converters(self, connection):
1017
- converters = super().get_db_converters(connection)
1018
- return converters
1019
-
1020
757
  def get_col(self, alias, output_field=None):
1021
758
  if output_field is None:
1022
759
  output_field = self.target_field
@@ -1027,6 +764,16 @@ class ForeignKey(ForeignObject):
1027
764
  return super().get_col(alias, output_field)
1028
765
 
1029
766
 
767
+ # Register lookups for ForeignKey
768
+ ForeignKey.register_lookup(RelatedIn)
769
+ ForeignKey.register_lookup(RelatedExact)
770
+ ForeignKey.register_lookup(RelatedLessThan)
771
+ ForeignKey.register_lookup(RelatedGreaterThan)
772
+ ForeignKey.register_lookup(RelatedGreaterThanOrEqual)
773
+ ForeignKey.register_lookup(RelatedLessThanOrEqual)
774
+ ForeignKey.register_lookup(RelatedIsNull)
775
+
776
+
1030
777
  class ManyToManyField(RelatedField):
1031
778
  """
1032
779
  Provide a many-to-many relation by using an intermediary model that
@@ -1557,7 +1304,7 @@ class ManyToManyField(RelatedField):
1557
1304
  pass
1558
1305
 
1559
1306
  def value_from_object(self, obj):
1560
- return [] if obj.pk is None else list(getattr(obj, self.attname).all())
1307
+ return [] if obj.id is None else list(getattr(obj, self.attname).all())
1561
1308
 
1562
1309
  def save_form_data(self, instance, data):
1563
1310
  getattr(instance, self.attname).set(data)
@@ -408,10 +408,10 @@ def create_reverse_many_to_one_manager(superclass, rel):
408
408
  pass # nothing to clear from cache
409
409
 
410
410
  def get_queryset(self):
411
- # Even if this relation is not to pk, we require still pk value.
411
+ # Even if this relation is not to primary key, we require still primary key value.
412
412
  # The wish is that the instance has been already saved to DB,
413
- # although having a pk value isn't a guarantee of that.
414
- if self.instance.pk is None:
413
+ # although having a primary key value isn't a guarantee of that.
414
+ if self.instance.id is None:
415
415
  raise ValueError(
416
416
  f"{self.instance.__class__.__name__!r} instance needs to have a "
417
417
  f"primary key value before this relationship can be used."
@@ -456,7 +456,7 @@ def create_reverse_many_to_one_manager(superclass, rel):
456
456
  setattr(obj, self.field.name, self.instance)
457
457
 
458
458
  if bulk:
459
- pks = []
459
+ ids = []
460
460
  for obj in objs:
461
461
  check_and_update_obj(obj)
462
462
  if obj._state.adding:
@@ -464,8 +464,8 @@ def create_reverse_many_to_one_manager(superclass, rel):
464
464
  f"{obj!r} instance isn't saved. Use bulk=False or save "
465
465
  "the object first."
466
466
  )
467
- pks.append(obj.pk)
468
- self.model._base_manager.filter(pk__in=pks).update(
467
+ ids.append(obj.id)
468
+ self.model._base_manager.filter(id__in=ids).update(
469
469
  **{
470
470
  self.field.name: self.instance,
471
471
  }
@@ -508,12 +508,12 @@ def create_reverse_many_to_one_manager(superclass, rel):
508
508
  )
509
509
  # Is obj actually part of this descriptor set?
510
510
  if self.field.get_local_related_value(obj) == val:
511
- old_ids.add(obj.pk)
511
+ old_ids.add(obj.id)
512
512
  else:
513
513
  raise self.field.remote_field.model.DoesNotExist(
514
514
  f"{obj!r} is not related to {self.instance!r}."
515
515
  )
516
- self._clear(self.filter(pk__in=old_ids), bulk)
516
+ self._clear(self.filter(id__in=old_ids), bulk)
517
517
 
518
518
  def clear(self, *, bulk=True):
519
519
  self._check_fk_val()
@@ -641,22 +641,22 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
641
641
  self.target_field = self.through._meta.get_field(self.target_field_name)
642
642
 
643
643
  self.core_filters = {}
644
- self.pk_field_names = {}
644
+ self.id_field_names = {}
645
645
  for lh_field, rh_field in self.source_field.related_fields:
646
646
  core_filter_key = f"{self.query_field_name}__{rh_field.name}"
647
647
  self.core_filters[core_filter_key] = getattr(instance, rh_field.attname)
648
- self.pk_field_names[lh_field.name] = rh_field.name
648
+ self.id_field_names[lh_field.name] = rh_field.name
649
649
 
650
650
  self.related_val = self.source_field.get_foreign_related_value(instance)
651
651
  if None in self.related_val:
652
652
  raise ValueError(
653
- f'"{instance!r}" needs to have a value for field "{self.pk_field_names[self.source_field_name]}" before '
653
+ f'"{instance!r}" needs to have a value for field "{self.id_field_names[self.source_field_name]}" before '
654
654
  "this many-to-many relationship can be used."
655
655
  )
656
- # Even if this relation is not to pk, we require still pk value.
656
+ # Even if this relation is not to primary key, we require still primary key value.
657
657
  # The wish is that the instance has been already saved to DB,
658
- # although having a pk value isn't a guarantee of that.
659
- if instance.pk is None:
658
+ # although having a primary key value isn't a guarantee of that.
659
+ if instance.id is None:
660
660
  raise ValueError(
661
661
  f"{instance.__class__.__name__!r} instance needs to have a primary key value before "
662
662
  "a many-to-many relationship can be used."
@@ -41,7 +41,7 @@ def get_normalized_value(value, lhs):
41
41
  from plain.models import Model
42
42
 
43
43
  if isinstance(value, Model):
44
- if value.pk is None:
44
+ if value.id is None:
45
45
  raise ValueError("Model instances passed to related filters must be saved.")
46
46
  value_list = []
47
47
  sources = lhs.output_field.path_infos[-1].target_fields
@@ -55,7 +55,7 @@ def get_normalized_value(value, lhs):
55
55
  except AttributeError:
56
56
  # A case like Restaurant.objects.filter(place=restaurant_instance),
57
57
  # where place is a OneToOneField and the primary key of Restaurant.
58
- return (value.pk,)
58
+ return (value.id,)
59
59
  return tuple(value_list)
60
60
  if not isinstance(value, tuple):
61
61
  return (value,)