Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

copy_relations() docs expanded #1570

Merged
merged 2 commits into from
Jan 7, 2013
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 56 additions & 15 deletions docs/extending_cms/custom_plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -248,39 +248,80 @@ else clause.
Handling Relations
==================

If your custom plugin has foreign key or many-to-many relations you are
responsible for copying those if necessary whenever the CMS copies the plugin.
If your custom plugin has foreign key (to it, or from it) or many-to-many
relations you are responsible for copying those related objects, if required,
whenever the CMS copies the plugin - **it won't do it for you automatically**.

To do this you can implement a method called
:meth:`cms.models.pluginmodel.CMSPlugin.copy_relations` on your plugin
model which gets the **old** instance of the plugin as an argument.
Every plugin model inherits the empty
:meth:`cms.models.pluginmodel.CMSPlugin.copy_relations` method from the base
class, and it's called when your plugin is copied. So, it's there for you to
adapt to your purposes as required.

Let's assume this is your plugin::
Typically, you will want it to copy related objects. To do this you should
create a method called ``copy_relations`` on your plugin model, that receives
the **old** instance of the plugin as an argument.

You may however decide that the related objects shouldn't be copied - you may
want to leave them alone, for example. Or, you might even want to choose some
altogether different relations for it, or to create new ones when it's copied...
it depends on your plugin and the way you want it to work.

If you do want to copy related objects, you'll need to do this in two slightly
different ways, depending on whether your plugin has relations *to* or *from*
other objects that need to be copied too:

For foreign key relations *from* other objects
----------------------------------------------

Your plugin may have items with foreign keys to it, which will typically be the
case if you set it up so that they are inlines in its admin. So you might have a
two models, one for the plugin and one for those items::

class ArticlePluginModel(CMSPlugin):
title = models.CharField(max_length=50)
sections = models.ManyToManyField(Section)

def __unicode__(self):
return self.title
class AssociatedItem(models.Model):
plugin = models.ForeignKey(
ArticlePluginModel,
related_name="associated_item"
)

Now when the plugin gets copied, you want to make sure the sections stay::
You'll then need the ``copy_relations()`` method on your plugin model to loop
over the associated items and copy them, giving the copies foreign keys to the
new plugin::

class ArticlePluginModel(CMSPlugin):
title = models.CharField(max_length=50)

def copy_relations(self, oldinstance):
self.sections = oldinstance.sections.all()
for associated_item in oldinstance.associated_item.all():
# instance.pk = None; instance.pk.save() is the slightly odd but
# standard Django way of copying a saved model instance
associated_item.pk = None
associated_item.plugin = self
associated_item.save()

For many-to-many or foreign key relations *to* other objects
------------------------------------------------------------

Your full model now::
Let's assume these are the relevant bits of your plugin::

class ArticlePluginModel(CMSPlugin):
title = models.CharField(max_length=50)
sections = models.ManyToManyField(Section)
sections = models.ManyToManyField(Section)

Now when the plugin gets copied, you want to make sure the sections stay, so
it becomes::

def __unicode__(self):
return self.title
class ArticlePluginModel(CMSPlugin):
title = models.CharField(max_length=50)
sections = models.ManyToManyField(Section)

def copy_relations(self, oldinstance):
self.sections = oldinstance.sections.all()

If your plugins have relational fields of both kinds, you may of course need to
use *both* the copying techniques described above.

********
Advanced
Expand Down