That's an idea I like. Though it affects OneToMany relations too  (no idea 
why this is so often presented as an m2m issue, when it's literally a 2m 
issue. So I'd prefer the attribute to be something like 
validate_tomany_relations or validate_2m perhaps. The focus on m2m is 
misleading. 

Either way yes, the attribute could default to False in the core CreateView 
and UpdateView conserving existing behaviour and be set to True in derived 
views to win a callback to Model.clean_rleations() (or a method with some 
other name, the name is up for discussion). Could even be that clean() 
accepts an optional arg like relationships_available or 2nd_pass or 
whatever ... and we can code clean() in our Models to have two paths, one 
on the first pass for the model fields (which can force a bail before we 
bother to start a transaction that needs rolling back) and a second pass 
after the forms and formsets are saved inside a transaction and all the 
relationships are visible.

Of course I'm still not sure if this works on MySQL or Lightdb? MY empircal 
testing is entirely on Postgresql for now.

But yes I agree it's more flexible as it can be set for individual model 
views or not as desired rather than for the whole app! Thumbs up really for 
that.

On Friday, 22 February 2019 09:10:05 UTC+11, Ian Foote wrote:
>
> I don't think a new setting is the way to go. I'd prefer to add an 
> attribute (validate_m2m = False?) to the CreateView and UpdateView classes 
> that allows a developer to opt-in to the new behaviour when they need it. 
> This is more flexible and still maintains backwards compatibility.
>
> Regards,
> Ian
>
> On Thu, 21 Feb 2019 at 11:03, Bernd Wechner <[email protected] 
> <javascript:>> wrote:
>
>> Most once sided discussion I've seen on a developers group in a while 
>> ;-), but I'll go so far as to suggest an API for the Django Core on this 
>> one. I mean I have a way to advance myself now, but methinks this need is 
>> so common that perhaps it's best sitting in the Django Core, albeit with a 
>> setting as it demands an atomic transaction for create and update views. 
>> Now this rests on a few premises, namely:
>>
>>
>>    1. That there is nothing overly broken with my suggestion that I am 
>>    not seeing as yet (I am the noob after all, and while pretty Python and 
>>    Django savvy, not diving into the core code very often at all, as little 
>> as 
>>    I've needed to, the very benefit of a cool framewor, keeping us isolated 
>>    from the dirty details ;-).
>>    2. That the observations I tabled are valid across all three database 
>>    backends that Django supports. if it's only  1 (Postgres) or 2 then it 
>>    shoudl definitely stay an enable-able option and not a default behaviour.
>>
>> A suggested API is as follows:
>>
>>
>>    1. Implement a  setting to enable this new behaviour. Looking over 
>>    exiting settings they can get quite long in name (like  
>>    DATA_UPLOAD_MAX_NUMBER_FIELDS for example) and so perhaps a name like: 
>>    RELATIONSHIP_VALIDATORS. I take inspiration from this setting:
>>    
>>    AUTH_PASSWORD_VALIDATORS¶ 
>>    
>> <https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators>
>>  
>>    
>>    Default: [] (Empty list)
>>    
>>    The list of validators that are used to check the strength of user’s 
>>    passwords. See Password validation 
>>    
>> <https://docs.djangoproject.com/en/2.1/topics/auth/passwords/#password-validation>
>>  
>>    for more details. By default, no validation is performed and all 
>> passwords 
>>    are accepted.
>>    
>>    And propose:
>>    
>>    TOMANY_RELATIONSHIP_VALIDATORS¶ 
>>    
>> <https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators>
>>  
>>    
>>    Default: False
>>    
>>    A boolean that specifies whether to use atomic transactions on in 
>>    CreateView and UpdateView POST requests in order to support relationship 
>>    (OneToMany and ManyToMany) validation in the Model itself. If true, 
>>    Model.clean() is called as usual, then inside an atomic transaction all 
>>    submitted forms and formsets are saved and Model.clean_relations() is 
>>    called. It is important to note that when Model.clean() is saved ToMany 
>>    relationship (creation or changes) are not visible to Model.clean() but 
>> are 
>>    visible in Model.clean_relations() where they can be validated.
>>    
>>    2. 
>>    
>>    Implement the code in CreateView.post(...) and UpdateView.post(...) 
>>    that does this, that is a little savvier than my example in previous 
>> mail, 
>>    but if form.is_valid() pass opens a transaction, saves the form and then 
>>    for each other form or formset in the POSTed data (not sure off hand how 
>> to 
>>    find those, more learning for me), check each with their .is_valid() and 
>> if 
>>    passing save it, then call Model.clean_relations() (for each model 
>> involved 
>>    (associated with any of the submitted forms or formsets). Of course has 
>> to 
>>    work if the model fails to implement clean_relations(), either by 
>> checking 
>>    it's there first of defining a default implementation which pay just 
>> pass. 
>>    
>>    3. 
>>    
>>    If Model.clean_relations() fails (throws an exception), roll back, if 
>>    not commit. 
>>    
>> It's a rough outline that I think can work. And if it's good (which I 
>> await feedback on from the silent developer community) then there may even 
>> be a case for defaulting this setting to True, on new projects anyhow as it 
>> may be sensible to default to False on any existing site (not introduce a 
>> new transaction layer without warning on existing projects that upgrade 
>> Django - where there may well be a transaction system in place already).
>>
>> I mean if it's a good plan, and it actually gets some feedback to that 
>> efffect or that help it evolve into a good plan, thus far this looks 
>> eminently like something I could implement and submit as a PR (Pull 
>> Request), but I'm just as likely to code mine up and run as I am way way 
>> busy on other stuff ;-).
>>
>> Regards,
>>
>> Bernd.
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Django developers (Contributions to Django itself)" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected] <javascript:>.
>> To post to this group, send email to [email protected] 
>> <javascript:>.
>> Visit this group at https://groups.google.com/group/django-developers.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-developers/239d7900-94a8-4491-b973-50e8731b3957%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/django-developers/239d7900-94a8-4491-b973-50e8731b3957%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/fe02fea4-a4c4-47c8-9075-fbcc1f8edc1c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to