Initial commit
This commit is contained in:
113
env/lib/python3.10/site-packages/wagtail/models/copying.py
vendored
Normal file
113
env/lib/python3.10/site-packages/wagtail/models/copying.py
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.db import models
|
||||
from modelcluster.fields import ParentalKey, ParentalManyToManyField
|
||||
from modelcluster.models import ClusterableModel
|
||||
|
||||
|
||||
def _extract_field_data(source, exclude_fields=None):
|
||||
"""
|
||||
Get dictionaries representing the model's field data.
|
||||
|
||||
This excludes many to many fields (which are handled by _copy_m2m_relations)'
|
||||
"""
|
||||
exclude_fields = exclude_fields or []
|
||||
data_dict = {}
|
||||
|
||||
for field in source._meta.get_fields():
|
||||
# Ignore explicitly excluded fields
|
||||
if field.name in exclude_fields:
|
||||
continue
|
||||
|
||||
# Ignore reverse relations
|
||||
if field.auto_created:
|
||||
continue
|
||||
|
||||
# Ignore reverse generic relations
|
||||
if isinstance(field, GenericRelation):
|
||||
continue
|
||||
|
||||
# Copy parental m2m relations
|
||||
if field.many_to_many:
|
||||
if isinstance(field, ParentalManyToManyField):
|
||||
parental_field = getattr(source, field.name)
|
||||
if hasattr(parental_field, "all"):
|
||||
values = parental_field.all()
|
||||
if values:
|
||||
data_dict[field.name] = values
|
||||
continue
|
||||
|
||||
# Ignore parent links (page_ptr)
|
||||
if isinstance(field, models.OneToOneField) and field.remote_field.parent_link:
|
||||
continue
|
||||
|
||||
if isinstance(field, models.ForeignKey):
|
||||
# Use attname to copy the ID instead of retrieving the instance
|
||||
|
||||
# Note: We first need to set the field to None to unset any object
|
||||
# that's there already just setting _id on its own won't change the
|
||||
# field until its saved.
|
||||
|
||||
data_dict[field.name] = None
|
||||
data_dict[field.attname] = getattr(source, field.attname)
|
||||
|
||||
else:
|
||||
data_dict[field.name] = getattr(source, field.name)
|
||||
|
||||
return data_dict
|
||||
|
||||
|
||||
def _copy_m2m_relations(source, target, exclude_fields=None, update_attrs=None):
|
||||
"""
|
||||
Copies non-ParentalManyToMany m2m relations
|
||||
"""
|
||||
update_attrs = update_attrs or {}
|
||||
exclude_fields = exclude_fields or []
|
||||
|
||||
for field in source._meta.get_fields():
|
||||
# Copy m2m relations. Ignore explicitly excluded fields, reverse relations, and Parental m2m fields.
|
||||
if (
|
||||
field.many_to_many
|
||||
and field.name not in exclude_fields
|
||||
and not field.auto_created
|
||||
and not isinstance(field, ParentalManyToManyField)
|
||||
):
|
||||
try:
|
||||
# Do not copy m2m links with a through model that has a ParentalKey to the model being copied - these will be copied as child objects
|
||||
through_model_parental_links = [
|
||||
field
|
||||
for field in field.through._meta.get_fields()
|
||||
if isinstance(field, ParentalKey)
|
||||
and issubclass(source.__class__, field.related_model)
|
||||
]
|
||||
if through_model_parental_links:
|
||||
continue
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if field.name in update_attrs:
|
||||
value = update_attrs[field.name]
|
||||
|
||||
else:
|
||||
value = getattr(source, field.name).all()
|
||||
|
||||
getattr(target, field.name).set(value)
|
||||
|
||||
|
||||
def _copy(source, exclude_fields=None, update_attrs=None):
|
||||
data_dict = _extract_field_data(source, exclude_fields=exclude_fields)
|
||||
target = source.__class__(**data_dict)
|
||||
|
||||
if update_attrs:
|
||||
for field, value in update_attrs.items():
|
||||
if field not in data_dict:
|
||||
continue
|
||||
setattr(target, field, value)
|
||||
|
||||
if isinstance(source, ClusterableModel):
|
||||
child_object_map = source.copy_all_child_relations(
|
||||
target, exclude=exclude_fields
|
||||
)
|
||||
else:
|
||||
child_object_map = {}
|
||||
|
||||
return target, child_object_map
|
||||
Reference in New Issue
Block a user