Skip to content

Commit

Permalink
Link to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
abondar committed Apr 28, 2024
1 parent a938077 commit 4327e1b
Showing 1 changed file with 2 additions and 279 deletions.
281 changes: 2 additions & 279 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,284 +54,7 @@ To install with poetry:
poetry add django-copyist
Basic usage
Usage
-----------

.. warning::
For more comfortable reading - read it in docs
https://abondar.github.io/django-copyist/quickstart.html

Assuming you have following models in your Django app:

.. code-block:: python
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
class Project(models.Model):
name = models.CharField(max_length=100)
company = models.ForeignKey(
Company, related_name="projects", on_delete=models.CASCADE
)
class Employee(models.Model):
name = models.CharField(max_length=100)
company = models.ForeignKey(
Company, related_name="employees", on_delete=models.CASCADE
)
class Counterpart(models.Model):
name = models.CharField(max_length=100)
external_id = models.IntegerField()
project = models.ForeignKey(
Project, related_name="counterparts", on_delete=models.CASCADE
)
class Task(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
assignee = models.ForeignKey(
Employee, related_name="tasks", on_delete=models.CASCADE
)
project = models.ForeignKey(Project, related_name="tasks", on_delete=models.CASCADE)
counterparts = models.ManyToManyField(Counterpart, related_name="tasks")
And you want to create full copy of company with all nested data, but also want it to be created with different name and address.
In this case you should write following ModelCopyConfig

.. code-block:: python
from django_copyist.config import (
ModelCopyConfig,
TAKE_FROM_ORIGIN,
MakeCopy,
UpdateToCopied,
FieldCopyConfig,
CopyActions,
)
from example.demo.models import (
Project,
Counterpart,
Task,
Company,
Employee,
)
config = ModelCopyConfig(
model=Company,
filter_field_to_input_key={"id": "company_id"},
field_copy_actions={
"name": FieldCopyConfig(
action=CopyActions.TAKE_FROM_INPUT,
input_key="new_company_name",
),
"address": FieldCopyConfig(
action=CopyActions.TAKE_FROM_INPUT,
input_key="new_company_address",
),
"projects": MakeCopy(
ModelCopyConfig(
model=Project,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
"counterparts": MakeCopy(
ModelCopyConfig(
model=Counterpart,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
"external_id": TAKE_FROM_ORIGIN,
},
)
),
},
)
),
"employees": MakeCopy(
ModelCopyConfig(
model=Employee,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
},
)
),
},
compound_copy_actions=[
ModelCopyConfig(
model=Task,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
"description": TAKE_FROM_ORIGIN,
"counterparts": UpdateToCopied(Counterpart),
"project": UpdateToCopied(Project),
"assignee": UpdateToCopied(Employee),
},
)
],
)
And then you can execute copy action like this:

.. code-block:: python
from django_copyist.copy_request import CopyRequest
from django_copyist.copyist import CopyistConfig, Copyist
copy_request = CopyRequest(
config=CopyistConfig([config]),
input_data={
"company_id": company_id,
"new_company_name": new_company_name,
"new_company_address": new_company_address,
},
confirm_write=False,
)
result = Copyist(copy_request).execute_copy_request()
With this, all company data should be copied.
That seems like a lot to take in, so let's break it down to what exactly happens here:

1. We define a `ModelCopyConfig` for the `Company` model.

.. code-block:: python
config = ModelCopyConfig(
model=Company,
filter_field_to_input_key={"id": "company_id"},
...
`ModelCopyConfig` is a class that defines how to copy a model. It takes the model class as the first argument and a dictionary that maps the filter field to the input key. This is used to find the object to copy.
2. Next we define `field_copy_actions` for the `Company` model.
.. code-block:: python
field_copy_actions={
"name": FieldCopyConfig(
action=CopyActions.TAKE_FROM_INPUT,
input_key="new_company_name",
),
"address": FieldCopyConfig(
action=CopyActions.TAKE_FROM_INPUT,
input_key="new_company_address",
),
"projects": MakeCopy(
ModelCopyConfig(
model=Project,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
"counterparts": MakeCopy(
ModelCopyConfig(
model=Counterpart,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
"external_id": TAKE_FROM_ORIGIN,
},
)
),
},
)
),
"employees": MakeCopy(
ModelCopyConfig(
model=Employee,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
},
)
),
...
`field_copy_actions` is a dictionary that maps the field name to a `FieldCopyConfig` object.
The `FieldCopyConfig` object defines how to copy the field. In this case, we take the `name` and `address` fields from the input data.
`TAKE_FROM_ORIGIN` is a shortcut for creating `FieldCopyConfig` with `CopyActions.TAKE_FROM_ORIGIN` action, which takes value for new object from original object.
We also define how to copy the `projects` and `employees` fields.
We use the `MakeCopy` action to copy the related objects.
`MakeCopy` is a shortcut for creating `FieldCopyConfig` with `CopyActions.MAKE_COPY` action and reference to given model.
Nested `MakeCopy` automatically propagate parent id to child object.
3. We define `compound_copy_actions` for the `Company` model.
.. code-block:: python
compound_copy_actions=[
ModelCopyConfig(
model=Task,
field_copy_actions={
"name": TAKE_FROM_ORIGIN,
"description": TAKE_FROM_ORIGIN,
"counterparts": UpdateToCopied(Counterpart),
"project": UpdateToCopied(Project),
"assignee": UpdateToCopied(Employee),
},
)
...
`compound_copy_actions` is a list of `ModelCopyConfig` objects that define how
to copy related objects that are not directly related to the model, or related through multiple relations that need to be created beforehand.
`compound_copy_actions` are executed after all fields are copied.
In this case, we define how to copy the `Task` model. We take the `name` and `description` fields from the original object. We also define how to copy the `counterparts`, `project`, and `assignee` fields.
`UpdateToCopied` is a shortcut for creating `FieldCopyConfig` with `CopyActions.UPDATE_TO_COPIED` action and reference to given model.
It will search mapping of previously copied objects and update reference to copied object.
4. We create a `CopyRequest` object with the `CopyistConfig` and input data.
.. code-block:: python
copy_request = CopyRequest(
config=CopyistConfig([config]),
input_data={
"company_id": company_id,
"new_company_name": new_company_name,
"new_company_address": new_company_address,
},
confirm_write=False,
)
...
`CopyRequest` is a class that defines the copy request. It takes the `CopyistConfig` object, input data, and a boolean flag that indicates whether to confirm the write operation.
`CopyistConfig` is a class that defines the configuration for the copy operation. It takes a list of `ModelCopyConfig` objects.
`input_data` is a dictionary that contains the input data for the copy operation. It is later used in filtering or `TAKE_FROM_INPUT` actions.
`confirm_write` is a boolean flag that indicates whether to confirm the write operation,
even if there are issues with matching objects in origin location with objects in target destination.
It is not used in this example, but you can read more about it in overview section of this documentation.
5. We execute the copy request.
.. code-block:: python
result = Copyist(copy_request).execute_copy_request()
`Copyist` is a class that executes the copy request. It takes the `CopyRequest` object as an argument.
`execute_copy_request` method returns `CopyResult` object that contains information about the copy operation. Read more about it in overview section.
And like this you have copied the company with all related data and can see and edit configuration in one place.
Next steps
----------
This is just a basic example of how to use django-copyist.
It can do much more granular control on how it should execute copy, and you can read more about it in the documentation.
https://abondar.github.io/django-copyist/overview.html
`See quickstart in docs <https://abondar.github.io/django-copyist/quickstart.html>`_

0 comments on commit 4327e1b

Please sign in to comment.