7

I have a model Goal which has two M2M fields and is referred to by another model Event. Now, the requirement is such that Goal is editable which means I can add/delete from M2M fields and add/delete events. But editing goes through moderation and only after approval the changes are to be reflected or in case of rejection changes must be reverted.

I have gone through deepcopy but it doesn't serve my purpose because lets say if I do x=deepcopy(goal object) I get copy of goal object but I am unsure what I can do with it.

Then I came to know about model_to_dict from django.forms module it serializes the whole object which is handy. I was thinking may be I could use this dictionary to create a model RevisedGoal with original goal as foreign key. Is it a feasible solution? Are there any othe ways of achieving this?

Rajesh Yogeshwar
  • 2,111
  • 2
  • 18
  • 37
  • Are you asking [how to clone a model instance](http://stackoverflow.com/questions/4733609/how-do-i-clone-a-django-model-instance-object-and-save-it-to-the-database)? – Sayse Mar 16 '16 at 10:29
  • @Sayse Would cloning allow me to maintain two version of a record? Because I went through the link you gave before posting – Rajesh Yogeshwar Mar 16 '16 at 10:39
  • Essentially it makes a completely separate instance of it, a duplicate if you will, this wouldn't create new records of related fields by default however – Sayse Mar 16 '16 at 10:41
  • As a I said, I have M2M fields as well, so if those change its a revision again. In that case I guess model_to_dict can give me a snapshot of last version of the object. I think I would like to build up on that. I did find an interesting project called [django-reversion](https://github.com/etianen/django-reversion) – Rajesh Yogeshwar Mar 16 '16 at 10:51
  • I am still open to more and better solutions. – Rajesh Yogeshwar Mar 16 '16 at 12:25

1 Answers1

1

I think that you're essentially asking how you can keep track of changes to Goal's M2M fields such that they can be approved or reverted. If you need to persist these pending changes to the database to approve or deny later, then cloning the model may not be the best solution, particularly if you want to revert. If you expect a lot of these changes, you'll want to separate the potential changes from the "live" instances of your Goals and Events.

I would suggest creating a new model that is linked to Goal and represents these pending changes. This object would keep track of added/removed records from the Goals M2M fields, and could contain some additional fields related to approval (like who approved the changes and when). When one of these new objects gets marked approved, you can make the requisite changes on the original Goal instance.

How you keep track of the added/removed M2M fields is the tricky part. In the example below, I've just created corresponding M2Ms on the pending changes object that you could iterate through on approval to apply to the original Goal object.

class Goal(models.Model):
...


class PendingGoalChange(models.Model):
    goal = models.ForeignKey(Goal, related_name='changes')
    approved = ...
    approver = ....

    added_m2m_field_instances = models.ManyToMany(...)
    removed_m2m_field_instances = models.ManyToMany(...)

    def approve(self):
        self.approved = True
        ...
        for new_field in self.added_m2m_field_instances.all():
            self.goal.field.add(new_field)
Jordan Haines
  • 206
  • 1
  • 4
  • I managed to find a decent solution to this problem based on serialization of the current state and restoring the same on event of rejection and updating the last approved state with with current approved state. I had same philosophy as you said but I just went about it in a different way – Rajesh Yogeshwar Apr 19 '16 at 07:18
  • @RajeshYogeshwar may I ask you to share your approach with some tiny code snippet? I upvoted your question and I feel curious about it – Iulian Pinzaru Jan 11 '22 at 05:55
  • @lulian Pinzaru. This is almost 6 years old now. If I remember correctly, back then I serialized the entire object before updating it and stored it. As of now you can look at https://django-simple-history.readthedocs.io/en/latest/ . It's a really nice one. I had my team use it on my last project. It worked. – Rajesh Yogeshwar Jan 11 '22 at 11:36