Opened 17 years ago

Last modified 2 weeks ago

#5793 assigned New feature

Allow custom attributes in Meta classes

Reported by: eikke@… Owned by:
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Loic Bistuer, jamespic@…, Ryan Hiebert, Rich Rauenzahn, Carlos Palol, Sardorbek Imomaliev, Gordon Wrigley, omelched, bcail, Piotr Kubiak, Clifford Gama Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

In some cass it is useful to be able to store meta information on models inside the model class. In Django the Meta subclass is used to achieve this. Trying to add a custom attribute to a model's Meta inner class results in an exception though, thrown from django.db.models.options, which does indeed check any valid attribute names and raises an exception when unknown names are found.
Is there any reason for this somewhat strange behaviour, not to allow a developer to add non-standard meta information to a model class (which can later on be used in eg view code)?

Thanks!

Change History (31)

comment:1 by James Bennett, 17 years ago

Resolution: wontfix
Status: newclosed

I'm going to call this a wontfix; Meta exists to set up a lot of "internal use" APIs, and the validation has to be strict to ensure that potential errors in that process are caught (e.g., if your Meta contains an attribute order, how can the validator tell whether you meant to add your own custom info or actually wanted ordering?).

And given that Django models are simply Python classes, and you're free to set up any attributes on them you like and then make use of them, I'm not sure that the use case of adding custom information in Meta is compelling enough.

comment:2 by miracle2k, 15 years ago

Resolution: wontfix
Status: closedreopened

I'd like to ask this be given another thought.

I'm not really convinced by the validation argument; first, this seems a more basic problem at it's core, particular in scripting languages. There are lots of places where a typo could lead to an API silently not being activated (think certain kwargs-scenarios, or a typo in the name of subclass methods etc). At some point you just need to actually check whether the code you've written actually does what its supposed to.

Secondly, if one really wants meta-validation, there is a middle ground: Require custom meta attributes to be pre-registered.

I just think this would be really nice for libraries that provide model base classes to accept configuration. Say for example django-treebeard and it's node_order_by (which is currently simply added to the class itself, which works, yes, but there's a reason why we have Meta in the first place).

comment:3 by James Bennett, 15 years ago

Resolution: wontfix
Status: reopenedclosed

If you disagree with a wontfix designation, the correct place to bring it up is on the django-developers list.

comment:4 by miracle2k, 15 years ago

For those Googling, it turns out there is a way to work around this using a custom model metaclass:

http://bitbucket.org/fivethreeo/django-easytree/src/7ab11cd55b09/easytree/models.py

comment:5 by robmadole, 15 years ago

Inspired by the django-easytree code, I've created django-immutablefield for anyone interested.

http://pypi.python.org/pypi/django-immutablefield

comment:6 by Russell Keith-Magee, 11 years ago

Easy pickings: unset
Resolution: wontfix
Severity: Normal
Status: closednew
Triage Stage: UnreviewedAccepted
Type: New feature
UI/UX: unset

This ticket was raised on Django-developers in response to a duplicated report (#21081). The devil is in the details, but I can at least see that there is a use case here. I share @ubernostrum's concern about Meta becoming a dumping ground for flags that shouldn't be kept on Meta, but it doesn't follow that there is no reason why an end-user would want to define an extension to the built-in set.

comment:7 by Shai Berger, 11 years ago

On the list, Tim Chase gave this example:

class MyModel(Model):
  class Meta:
    ...
    class MyApp:
      secure_fields = ["cc_num", "ssn"]

The idea was that app-specific properties should be namespaced to avoid clashes. I think the approach is fine, I just don't see why these classes need to be in Meta; I see nothing wrong with

class MyModel(Model):
  class Meta:
    ...
  class MyApp:
    secure_fields = ["cc_num", "ssn"]

This leaves the app-specific metadata separate from fields and methods, so the "API" is clean enough; it avoids clashes reasonably well; and it requires no changes in Django.

Note that this was the approach taken by Admin at first -- and my impression (though I wasn't "there" at the time) is that it changed because Admin classes became too large for comfort as nested classes, not because the first idea was considered so bad.

I think for most use-cases -- in particular, including the two noted on the list, marking fields as "to be published" or "to be censored", this can work well.

The point about extending the ORM stands, but this does not seem to be the use-case that motivates the current requests.

in reply to:  7 comment:8 by Shai Berger, 11 years ago

Replying to shai:

The point about extending the ORM stands, but this does not seem to be the use-case that motivates the current requests.

I have to take that back -- it is true as far as the requests on the mailing list postings are concerned, but #21081 actually is about extending the ORM.

comment:11 by Simon Litchfield, 9 years ago

Cc: Simon Litchfield added

+1 - it's kinda daft to encourage the ORM to be extendable, while at the same time restricting what Meta options we're allowed

Why not just move DEFAULT_NAMES into the Model class? problem solved, zero breakage.

comment:12 by Simon Litchfield, 9 years ago

Cc: Simon Litchfield removed
Easy pickings: set

comment:13 by Tim Graham, 9 years ago

Component: MetasystemDatabase layer (models, ORM)
Easy pickings: unset

comment:14 by Loic Bistuer, 8 years ago

Cc: Loic Bistuer added

How about an API to register new model options (e.g. models.Options.register_option('mptt_manager_name')).

The AppConfig.ready() comes in too late to register this, but AppConfig.__init__() should work.

comment:15 by James Pic, 8 years ago

Cc: jamespic@… added

comment:16 by James Pic, 8 years ago

Question: is this ticket just about Model.Meta or also for ModelForm.Meta ? /me wondering if another, similar ticket could be opened about ModelForm.Meta

comment:17 by Adam Johnson, 8 years ago

James I think this ticket is about Model.Meta but whatever the API it ends up with could be copied over to ModelForm.Meta, so idk if it makes sense to create a second ticket for that yet

comment:18 by Maxime Vdb, 8 years ago

It would be indeed very useful: I have a custom database backend (for Redshift) and I would like to support advanced options for this backend (these options would modify the SQL for table creation for instance). There is apparently no other way than defining that on the Meta dict (due to the migration system) but it is not possible to define custom options.

Did you guys agree on the design yet?

comment:19 by Dylan Young, 7 years ago

This would actually enable users to develop on Django much more easily; I imagine you would get a slew of new ORM developments coming in quite quickly.

Some thoughts:

1) How to hook into the migration system for database changes? i.e. If I wanted to add partial indices and have the migrations autogenerate from my custom Meta option for this. The 'register_option' idea is probably good for this.

2) How to play nice with migrations for state changes?

comment:20 by Ryan Hiebert, 6 years ago

Cc: Ryan Hiebert added

comment:21 by Rich Rauenzahn, 6 years ago

Cc: Rich Rauenzahn added

comment:22 by Carlos Palol, 6 years ago

Cc: Carlos Palol added

comment:23 by Sardorbek Imomaliev, 5 years ago

Cc: Sardorbek Imomaliev added

comment:24 by Gordon Wrigley, 4 years ago

Cc: Gordon Wrigley added

comment:25 by omelched, 3 years ago

Cc: omelched added

comment:26 by Saeed Hasani Borzadaran, 2 years ago

Owner: changed from nobody to Saeed Hasani Borzadaran
Status: newassigned

comment:27 by Mariusz Felisiak, 2 years ago

Saeed, I removed your comment because you remove the ticket description. Please don't do this.

comment:28 by Loic Bistuer, 2 years ago

Dear Saeed, typically that would be intended for reusable 3rd party apps to pick up rather than ordinary apps, but yes the idea is not to be limited to the built-in attributes.

The main challenge is to find an elegant way to register new attributes (so the system that reports typos still works) and that kicks in at the right time to be useful, I mentioned above that I suspect AppConfig.__init__() will work but that would have to be checked.

As Dylan mentioned, we also need to see how this interacts with the migration framework, especially the ORM inside RunPython.

comment:29 by Saeed Hasani Borzadaran, 2 years ago

About AppConfig.__init__() , I honestly didn't understand and I need your guidance.
Do you have enough time to explain more? Can you give me an example to implement it?

Last edited 2 years ago by Saeed Hasani Borzadaran (previous) (diff)

in reply to:  27 comment:31 by Saeed Hasani Borzadaran, 2 years ago

Dear Mariusz
This would be a very cool feature to add to Django.
I have enough time to do this and I am very eager to do it.
Can you give me more guidance to get a good result (about connecting custom attributes to the migration framework)

comment:32 by bcail, 11 months ago

Cc: bcail added

comment:33 by Piotr Kubiak, 6 weeks ago

Cc: Piotr Kubiak added

comment:34 by Clifford Gama, 2 weeks ago

Cc: Clifford Gama added
Note: See TracTickets for help on using tickets.
Back to Top