How does Django's nested Meta class work?
Asked Answered
E

7

259

I am using Django which allows people to add extra parameters to a class by using class Meta.

class FooModel(models.Model):
    ...
    class Meta:
        ...

The only thing I found in Python's documentation was:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

However, I don't think this is the same thing.

Emeric answered 27/4, 2012 at 2:59 Comment(2)
Title asks about Python meta, but question seems to ask about Django meta - which one are you asking about?Thionic
@Thionic he is confused due to the absurd decision (IMO) to call a nested class "Meta", which is very misleading; to beginners, about Python's metaclasses, and to more experienced users that have never seen it, about its purpose a priori (instead of using class attributes or real metaclasses)Arthropod
O
311

You are asking a question about two different things:

  1. Meta inner class in Django models:

    This is just a class container with some options (metadata) attached to the model. It defines such things as available permissions, associated database table name, whether the model is abstract or not, singular and plural versions of the name etc.

    Short explanation is here: Django docs: Models: Meta options

    List of available meta options is here: Django docs: Model Meta options

    For latest version of Django: Django docs: Model Meta options

  2. Metaclass in Python:

    The best description is here: What are metaclasses in Python?

Older answered 27/4, 2012 at 3:4 Comment(4)
Are these two things related at all? i.e., does Django's Meta inner class prevent you from using Python's builtin metaclass features?Treatise
@nnyby: There are two things that create relation between these two concepts: name and confusion many users have (as OP had it in original question). I believe addressing that common confusion is significant advantage of this topi. Don't you agree?Older
What is "a class container"? I thought I understood class and container data types in Python, but I don't understand what the "class container" concept you mention is?Phenomena
@Phenomena When Python encounters a class definition, it creates a namespace for any variable definitions or function definitions (or class definitions) found within. I believe he is referring to a nested class definition as a "container of attributes" (like a dict).Neutrophil
B
69

Extending on Tadeck's Django answer above, the use of 'class Meta:' in Django is just normal Python too.

The internal class is a convenient namespace for shared data among the class instances (hence the name Meta for 'metadata' but you can call it anything you like). While in Django it's generally read-only configuration stuff, there is nothing to stop you changing it:

In [1]: class Foo(object):
   ...:     class Meta:
   ...:         metaVal = 1
   ...:         
In [2]: f1 = Foo()
In [3]: f2 = Foo()
In [4]: f1.Meta.metaVal
Out[4]: 1
In [5]: f2.Meta.metaVal = 2
In [6]: f1.Meta.metaVal
Out[6]: 2
In [7]: Foo.Meta.metaVal
Out[7]: 2

You can explore it in Django directly too e.g:

In [1]: from django.contrib.auth.models import User
In [2]: User.Meta
Out[2]: django.contrib.auth.models.Meta
In [3]: User.Meta.__dict__
Out[3]: 
{'__doc__': None,
 '__module__': 'django.contrib.auth.models',
 'abstract': False,
 'verbose_name': <django.utils.functional.__proxy__ at 0x26a6610>,
 'verbose_name_plural': <django.utils.functional.__proxy__ at 0x26a6650>}

However, in Django you are more likely to want to explore the _meta attribute which is an Options object created by the model metaclass when a model is created. That is where you'll find all of the Django class 'meta' information. In Django, Meta is just used to pass information into the process of creating the _meta Options object.

Biddick answered 8/8, 2013 at 4:23 Comment(9)
This doesn't work on user-defined models: >>>from myapp.models import MyModel >>>MyModel.Meta Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: type object 'MyModel' has no attribute 'meta'Wall
You need the underscore e.g. MyUser.objects.get(pk=1)._metaBiddick
Right, but that doesn't access the Model's class's inner Meta class. That accesses the _meta options for that Model's instance...there doesn't appear to be a way to access the inner Meta class itself. The use case for me was subclassing a proxy MyModelProxy class from MyModel in a way where MyModelProxy can inherit MyModel's inner Meta class.Wall
I'm not entirely clear on what you mean by the model's 'inner Meta class' but you can always work directly with the instance's class e.g type(MyUser.objects.get(pk=1)).MetaBiddick
OK what I meant is: I wrote a class MyModel, which inherits from django's base Model class. MyModel has an inner class named 'Meta'. MyModelProxy is a sublcass of MyModel, but I want it to inherit MyModel's Meta class MyModel._meta is NOT the Meta class object itself, but an instance var built from Meta. I suspect because MyModel inherits from models.Model, instead of django's User model:Wall
>>>from django.contrib.auth.models import User >>>User.meta <class 'django.contrib.auth.models.AbstractUser.Meta'> >>>from myapp.models import MyModel >>>MyModel.Meta Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: type object 'MyModel' has no attribute 'Meta'Wall
I think you might need to make your MyModel metaclass AbstractUser to deal with this issue.Biddick
"convenient namespace for shared data among the class instances" That line did it for me.Discreditable
@Wall To understand what happens to it exactly, you'd need to understand how __new__ works in Python's metaclasses. Basically, they call .pop on the classdict (removing Meta from the class), then (eventually) initialize the Options class as the _meta attribute.Soekarno
B
29

Django's Model class specifically handles having an attribute named Meta which is a class. It's not a general Python thing.

Python metaclasses are completely different.

Brick answered 27/4, 2012 at 3:2 Comment(1)
I think your answer is not clear enough - could you elaborate on how Meta class works? I believe OP asked specifically about that.Older
V
16

Answers that claim Django model's Meta and metaclasses are "completely different" are misleading answers.

The construction of Django model class objects, that is to say the object that stands for the class definition itself (yes, classes are also objects), are indeed controlled by a metaclass called ModelBase, and you can see that code here.

And one of the things that ModelBase does is to create the _meta attribute on every Django model which contains validation machinery, field details, save logic and so forth. During this operation, the stuff that is specified in the model's inner Meta class is read and used within that process.

So, while yes, in a sense Meta and metaclasses are different 'things', within the mechanics of Django model construction they are intimately related; understanding how they work together will deepen your insight into both at once.

This might be a helpful source of information to better understand how Django models employ metaclasses.

https://code.djangoproject.com/wiki/DevModelCreation

And this might help too if you want to better understand how objects work in general.

https://docs.python.org/3/reference/datamodel.html

Virago answered 15/12, 2017 at 18:40 Comment(0)
M
5

Inner Meta Class Document:

This document of django Model metadata is “anything that’s not a field”, such as ordering options (ordering), database table name (db_table), or human-readable singular and plural names (verbose_name and verbose_name_plural). None are required, and adding class Meta to a model is completely optional. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Mauramauralia answered 11/3, 2019 at 10:53 Comment(0)
A
1

In Django, it acts as a configuration class and keeps the configuration data in one place!!

Adventurism answered 21/5, 2020 at 16:55 Comment(0)
W
1

Class Meta is the place in your code logic where your model.fields MEET With your form.widgets. So under Class Meta() you create the link between your model' fields and the different widgets you want to have in your form.

Wells answered 4/10, 2020 at 22:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.