James,

Thanks, that's really well put. 

I've implemented an override, and better still I love that with a model mix 
in I can override the save method on the object. Sort of like:

class MyMixIn:
    def check_stuff(self)
         ...
         if ...:
              self.save = self.disabled_save

    def disabled_save(self):
        raise Exception("Can't save me!")

class MyModel(MyMixIn, models.Model):
   ...

Now yes, your insight that this can be circumvented is interesting, and it 
might (though I wonder how in this version, perhaps by calling 
models.Model.save(obj)?) but am content with a solution for now that 
prevents inadvertent saving not malicious saving efforts. What this allows 
is that the extant body of code can tested and run and even put into 
production in a sense, trusting that any overlooked save avenues will throw 
this exception. Which is awesome.  

Bot 100% secure perhaps, but pretty danged good. I've tested this sort of 
thing now and walked the code in a debugger and am pretty happy with it. As 
long as there are not other ways the django core code might go and save an 
object (i.e. not using a models save() method. I sort of imagine and hope 
not that one of the deign paradigms was in fact to make something like this 
possible, to override base model methods with confidence (typically 
invoking super() to extend on existing functions but perhaps not as in 
here). 

Anyhow, rather pleased this works. Opens up a pile of interesting options 
(the main interest I have is in loading an object, modifying an object for 
display purposes and sandbox purposes, but securing against an inadvertent 
save of the object).

Regards,

Bernd.

On Tuesday, 6 March 2018 19:28:58 UTC+11, James Bennett wrote:
>
> The only way to guarantee a model is unsaveable is to do it at the 
> database permission level.
>
> You can override methods on the model in your Python code to make it 
> *harder* to save, but you can't make it impossible, because of how Python 
> works.
>
> Consider the following simplified pair of classes:
>
>
> class Base:
>     def __init__(self, name):
>         self.name = name
>
>     def save(self):
>         print("Saving {}".format(self.name))
>
>
> class Child(Base):
>     def save(self):
>         raise Exception("Can't save me!")
>
>
> You'd think you can't save() an instance of Child. Except:
>
>
> c = Child(name="Unsaveable instance")
> Base.save(c)
>
>
> Which will succeed and print that it's saving the "unsaveable" instance of 
> Child. Now imagine that you override save() and everything else you can 
> think of on your model class, and then someone goes and grabs the base 
> Model class and calls its save() method passing in an instance of your 
> "unsaveable" class. It's going to succeed in saving your "unsaveable" model.
>
> No matter how much you do to your model class in Python, someone who's 
> sufficiently determined will always be able to find a way to save it. Only 
> by cutting off the ability to run INSERT/UPDATE queries at the 
> database-permission level can you completely stop this. 
>
>
>
> On Tue, Mar 6, 2018 at 12:12 AM, Melvyn Sopacua <m.r.s...@gmail.com 
> <javascript:>> wrote:
>
>> Hi Bernd,
>>
>> On zondag 4 maart 2018 10:41:52 CET Bernd Wechner wrote:
>>
>> > Here is the use case:
>> >
>> >  1. Load an object from database
>> >  2. Flag it as unsaveable, not to be written back to database under any
>> >     circumstances
>> >  3. Make changes to the object (its fields)
>> >  4. Present a detail view of the object.
>>
>> Since this is for display purposes, why does it have to remain a model?
>> --
>> Melvyn Sopacua
>>
>> --
>> You received this message because you are subscribed to the Google Groups 
>> "Django users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to django-users...@googlegroups.com <javascript:>.
>> To post to this group, send email to django...@googlegroups.com 
>> <javascript:>.
>> Visit this group at https://groups.google.com/group/django-users.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-users/2367426.DusgZ0bLcz%40fritzbook
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/06fd9834-aafc-4167-901f-5112cb3ca566%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to