Skip to content
This repository has been archived by the owner on Feb 7, 2019. It is now read-only.

Using the provided ModelAdmin it creates a new version even when there are errors #107

Open
rasca opened this issue Sep 24, 2015 · 5 comments

Comments

@rasca
Copy link

rasca commented Sep 24, 2015

You clone the object in get_object before the forms validation take place.

I think the correct place to do this would be in save_model() taking into consideration that it also affects save_related().

@boydjohnson
Copy link
Contributor

I was able to confirm with a field that does the validation in the Python like EmailField, that cloning happens even though errors happen. @rasca, I think you are right that the cloning should happen in save_model. The below seemed to work, but I don't have time to fully test it out.

def save_model(self, request, obj, form, change):
    if obj and obj.is_latest and 'will_not_clone' not in request.path:
        obj = obj.clone()
    super(VersionedAdmin, self).save_model(request, obj, form, change)

@rasca
Copy link
Author

rasca commented Sep 25, 2015

I don't think that solution will work.
You need to think about the m2m fields and the inline formsets that are saved in the save_related().

In the upcoming 1.9 cloning the object in save_model() and assigning it to form.instance and the formsets instances will work, but in 1.8 and previous versions it will not work, because the way in which form.save_m2m is created (when calling form.save(commit=False)) before validating the inlines takes places.

@rasca
Copy link
Author

rasca commented Sep 25, 2015

I think I found a solution for 1.8 and earlier:

    def save_model(self, request, obj, form, change):
        if change:
            obj = obj.clone()
            form.instance = obj
            form.save(commit=False)  # trigger save_instance() and update save_m2m

What do you think? We should also update each formset.instace to the cloned obj in save_related().

@boydjohnson
Copy link
Contributor

@rasca Sorry for the delay, when I ran that code it saves the previous object with the updated (cloned) information, so a City named Northfield gets cloned and renamed to Demascus then they both are Demascus.

@rasca
Copy link
Author

rasca commented Oct 4, 2015

Yes.. I ended up using this code:

    def save_model(self, request, obj, form, change):
        if change:
            fresh = obj._meta.model.objects.as_of().get(pk=obj.pk)
            new = fresh.clone()
            obj.version_start_date = new.version_start_date
            obj.save()
            form.instance = obj
            form.save(commit=False)  # trigger save_instance() and update save_m2m
        else:
            obj.save()

Though it takes two additional queries and messes with version_start_date manually.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants