field cannot be specified for model form as it is a non-editable field

7,782 views
Skip to first unread message

marcin....@gmail.com

unread,
May 8, 2017, 6:30:36 AM5/8/17
to Django users
Hi.

After upgrading to 1.11 I'm getting this error:

FieldError: created_at cannot be specified for <MyModel> model form as it is a non-editable field.

First of all, the model contains created_at field declared as DateTimeField(auto_now_add=True). Probably that's why it is non-editable. But I cannot set editable=True - the change has no effect.
My application allows overriding "created_at" value, because there are more than one separate input channels, and I have such cases. Other relies on auto_now_add. 

I want to leave auto_now_add=True as is, and have possibility to override it. 
How to achieve that? 

PS. Somebody asked me why I'm considering leaving Django, and this is a real example of worst changes in Django in last years. Breaking compatibility and blocking a dev to do what he want. There is nothing wrong with overriding such value.

Marcin

Tim Graham

unread,
May 8, 2017, 7:07:09 AM5/8/17
to Django users
From the docs for auto_now_add:

Automatically set the field to now when the object is first created. Useful for creation of timestamps. Note that the current date is always used; it’s not just a default value that you can override. So even if you set a value for this field when creating the object, it will be ignored. If you want to be able to modify this field, set the following instead of auto_now_add=True:


https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.DateField.auto_now_add

The change to raise FieldError for non-editable fields was meant to prevent bugs, not to block devs from doing what they want. See https://code.djangoproject.com/ticket/26238, and please try to be less antagonistic.

Melvyn Sopacua

unread,
May 8, 2017, 10:47:25 AM5/8/17
to django...@googlegroups.com

On Monday 08 May 2017 04:07:09 Tim Graham wrote:

 

 

> The change to raise FieldError for non-editable fields was meant to

> prevent bugs, not to block devs from doing what they want.

 

But auto_now_add without auto_now is not a reason to make the field non-editable. I should be able to use it in a model form, since the update case is unhandled.

 

However, this has always (at least 1.8.x and up) been the case for the field and as you say, it now exposes a bug.

--

Melvyn Sopacua

Tim Graham

unread,
May 8, 2017, 11:18:46 AM5/8/17
to Django users
If you have a patch in mind, I'll take a look, however, considering there's talk of deprecating those options [0] in favor the alternatives that the docs mentioned, I don't think we should spend much time reconsidering their semantics.

[0] https://code.djangoproject.com/ticket/22995

Melvyn Sopacua

unread,
May 8, 2017, 1:31:28 PM5/8/17
to django...@googlegroups.com

On Monday 08 May 2017 08:18:46 Tim Graham wrote:

> If you have a patch in mind, I'll take a look, however, considering

> there's talk of deprecating those options [0] in favor the

> alternatives that the docs mentioned, I don't think we should spend

> much time reconsidering their semantics.

 

Interesting read. No one stepped up in 3 years though and for good reason: The cure is worse then the disease IMHO.

 

I'll do some more reading to see what the challenges are for a real fix (my gut says, fix it at the database level, but for Postgres you'd have to install triggers).

 

Since pre_save only sets the value when appropreate, the patch would only be in __init__ and deconstruct.

 

The scope for DateField is like so:

 

diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init

index 0af100efd9..fa4932e670 100644

--- a/django/db/models/fields/__init__.py

+++ b/django/db/models/fields/__init__.py

@@ -1176,8 +1176,9 @@ class DateField(DateTimeCheckMixin, Field):

auto_now_add=False, **kwargs):

self.auto_now, self.auto_now_add = auto_now, auto_now_add

if auto_now or auto_now_add:

- kwargs['editable'] = False

kwargs['blank'] = True

+ if auto_now:

+ kwargs['editable'] = False

super(DateField, self).__init__(verbose_name, name, **kwargs)

 

def _check_fix_default_value(self):

@@ -1230,8 +1231,10 @@ class DateField(DateTimeCheckMixin, Field):

if self.auto_now_add:

kwargs['auto_now_add'] = True

if self.auto_now or self.auto_now_add:

- del kwargs['editable']

del kwargs['blank']

+

+ if self.auto_now:

+ del kwargs['editable']

return name, path, args, kwargs

 

def get_internal_type(self):

 

>

> [0] https://code.djangoproject.com/ticket/22995

>

> On Monday, May 8, 2017 at 10:47:25 AM UTC-4, Melvyn Sopacua wrote:

> > On Monday 08 May 2017 04:07:09 Tim Graham wrote:

> > > The change to raise FieldError for non-editable fields was meant

> > > to

> > >

> > > prevent bugs, not to block devs from doing what they want.

> >

> > But auto_now_add without auto_now is not a reason to make the field

> > non-editable. I should be able to use it in a model form, since the

> > update case is unhandled.

> >

> >

> >

> > However, this has always (at least 1.8.x and up) been the case for

> > the field and as you say, it now exposes a bug.

> >

> >

> > Melvyn Sopacua

 

--

Melvyn Sopacua

James Schneider

unread,
May 8, 2017, 2:09:50 PM5/8/17
to django...@googlegroups.com


On May 8, 2017 3:30 AM, <marcin....@gmail.com> wrote:
Hi.

After upgrading to 1.11 I'm getting this error:

FieldError: created_at cannot be specified for <MyModel> model form as it is a non-editable field.

First of all, the model contains created_at field declared as DateTimeField(auto_now_add=True). Probably that's why it is non-editable. But I cannot set editable=True - the change has no effect.
My application allows overriding "created_at" value, because there are more than one separate input channels, and I have such cases. Other relies on auto_now_add. 

I want to leave auto_now_add=True as is, and have possibility to override it. 
How to achieve that? 

This feature is built for a standard use of tracking when an object is created. At a more basic level, this field is really tracking when the record in the DB is created. For most apps, these two values are the same, will never differentiate, and can be tracked transparently as the same field.

In your use case, these two values can be different. You really should have two fields to track this information. For example, a 'created_at' field would track when the object was created, which can be provided through some channel, or use the current time stamp as a default of it isn't provided. It would NOT use 'auto_now_add' because you don't want the system to control such behavior. Using a 'default' value in your situation of the current time stamp would be appropriate. It would allow you to override the value from another source, or keep it empty and emulate the behavior of 'auto_now_add', probably with no other code changes.

You would also have another field, such as 'record_created_at', which WOULD use 'auto_now_add because you would never need/want to change it for auditing purposes.

Any references to this object would use the 'created_on' field, as it probably does now. The other girls would only be used for reporting and auditing.


PS. Somebody asked me why I'm considering leaving Django, and this is a real example of worst changes in Django in last years. Breaking compatibility and blocking a dev to do what he want. There is nothing wrong with overriding such value.

In your use case, that's a bit of an unfair assessment. You're asking a built-in feature to support an atypical use case. Implementing the behavior you need should be trivial, and would likely better account for the various input channels for your data. 

I'd challenge your assertion that there is nothing wrong with updating this field. Audit fields that track this information should not be easily updated (otherwise you can't trust your audit trail), and it should be a deliberate design decision to be able to do so.

Note that the Django devs don't 'block' you from doing anything, given that you can write code to do anything you want. You may encounter restrictions with the built-in functionality, but generally those restrictions are there for a good reason. If you're hitting those walls, it would be wise to determine why. 

I've found that the intentional limitations imposed by the Django devs lead to a much better design pattern, and those limitations are not imposed without extensive discussion on the dev mailing list or ticket tracker.

-James

marcin....@gmail.com

unread,
May 9, 2017, 4:57:54 AM5/9/17
to Django users
Thank you for all replies.


@James

Your proposal about design change is generally OK, but while doing the upgrade I definitely DO NOT want to change the implementation. It is just too risky. 


@Tim

Sorry for hostile sounding, but I'm just tired of such drastic changes. For a x-years long project it is a quite big issue. 
The most important thing is not to destroy the data and to have a security patches applied. The rest should remain untouched. 
The big problem with Django lies somewhere in between - to get recent patches you must accept whole set of changes, incl. breaking compat ones. 

I'm considering upgrade just because 1.8 is not supported AND it has some serious drawbacks (here -- automatic removal of contenttypes).
Where I am doing one step forward, the upgrade takes me "two" steps back.
    
I was quite happy when more freedom was left to the developer. It was from v0.96 up to v1.4. 
The things started getting "worse" when builtin migrations and system checks framework were introduced. 
And the "worse" word is very subjective here.  

Anyway, thank you for a quick response and hint about changing auto_now_add to the `default` attr.

Marcin
Reply all
Reply to author
Forward
0 new messages