Can we say that Django models are considered dataclasses? I don't see #dataclass annotation on them or on their base class model.Models. However, we do treat them like dataclasses because they don't have constructors and we can create new objects by naming their arguments, for example MyDjangoModel(arg1= ..., arg2=...).
On the other hand, Django models also don't have init methods (constructors) or inherit from NamedTuple class.
What happens under the hood that I create new Django model objects?
A lot of the magic that happens with models, if not nearly all of it, is from its base meta class.
This can be found in django.db.models.ModelBase specifically in the __new__ function.
Regardless of an __init__ method being defined or not (which actually, it is as per Abdul's comment), doesn't mean it can or should be considered a dataclass.
As described very eloquently in this SO post by someone else;
What are data classes and how are they different from common classes?
Despite django models quite clearly and apparently seeming to have some kind of data stored in them, the models are more like an easy to use (and reuse) set of functions which leverage a database backend, which is where the real state of an object is stored, the model just gives access to it.
It's also worth noting that models don't store data, but simply retrieves it.
Take for example this simple model:
class Person(models.Model):
name = models.CharField()
And then we did something like this in a shell:
person = Person.objects.get(...)
print(person.name)
When we access the attribute, django is actually asking the database for the information and this generates a query to get the value.
The value isn't ACTUALLY stored on the model object itself.
With that in mind, inherently, django models ARE NOT dataclasses. They are plain old regular classes.
Django does not work with data classes. You can define a custom model field. But likely this will take some development work.
Related
I'm working on a django application, and I want to create a mixin that will always be applied to model definitions. The functionality added by the mixin isn't important for the question.
However, I need to be able to retrieve a list of all the class definitions that inherit from this mixin. These classes can be in different apps within the django project.
Possible answers I've found so far are:
How to find all the subclasses of a class given its name?
How to auto register a class when it's defined
I'm mostly wondering what the best method would be to accomplish this goal.
Typically the way you would get a list of all the classes that inherit a particular class would be by registering the classes with a meta-class (as is explained in one of the questions you have linked). Django models however use their own meta class to achieve a lot of what they do automatically. I wouldn't recommend adding another meta-class into the mix - things could go wrong here!!
Fortunately however, django has something called the content-types framework which is essentially a registry of all of your models in a particular project.
To get a list of all of your models you can do this:
from django.contrib.contenttypes.models import ContentType
content_types = ContentType.objects.all()
This won't get the actual models, but rather a queryset of ContentType instances. To then get the model classes from this you can do
models = [x.model_class() for x in content_types]
So we now have a list of models. Then we can just filter the list down to those models which inherit your mixin:
models_with_mixin = [x for x in models if issubclass(x, MyMixin)]
We can simplify all of the above into the following:
from django.contrib.contenttypes.models import ContentType
models_with_mixin = [
x.model_class()
for x in ContentType.objects.all()
if issubclass(x.model_class(), MyMixin)
]
In my project i have many models in multiple apps, all of them inherit from one abstract model. I would like to create a model that would hold the changes to the history for every one of my models, so that every model would have its own history model. Each model would also have one-to-many relation to its history model. All history models would be the same, except for the foreign key to their respective model.
My problem is that I do not want to write all the history models manually. Instead i would like to have the history model created for every model automatically, so I don't have to write all that boilerplate code. Can this be achieved?
There is a widely-used django package that I believe solves this exact problem called django-reversion with a nice API. I recommend using it if it fits your needs rather than building a custom solution.
Object version control is usually better solved by serializing your objects and storing the serialization every time they are edited (e.g. in the json format).
You may also want to keep track of when objects are deleted.
This way, you only need to store a reference to the serialized object. Versions of all objects can live in the same database table and reference their "source" object using Django's generic relations.
You can eventually create your classes dynamically with type()
There is many ways to do it, but you can do something as follows:
class SomeParentClass: pass
NewClass = type('NewClass', (SomeParentClass,), {'new_method': lambda self:
'foo' } )
new_class_instance = NewClass()
print(new_class_instance.new_method())
So you can create models dynamically, with a different name, inherit from a different class, new methods...
You can then use globals()[variable_name_to_store_class] to assign newly created classes to a dynamic variable name.
Hope its relavant for your problem.
I am trying to write an alternative way of creating models, other from the one Django uses (metaclasses that is).
Currently, Django uses a metaclass to put all field declarations from a user-declared model in a fields dictionary and then uses this dictionary to assign user-declared model attributes from the given kwarg list provided when instantiating this model.
What other methods of doing this are available? I thought about using decorators, but then I cannot subclass the base Model class (upon which the decorator acts) to create user-declared models. Thank you for pointing me in any direction!
Maybe my question is little childish. A django model is typically defined like this:
class DummyModel(models.Model):
field1 = models.CharField()
field2 = models.CharField()
As per my understanding, field1 and field2 are defined on the class level instead of instance level. So different instances will share the same field value. How can this be possible considering a web application should be thread safe? Am I missing something in my python learning curve?
You are correct that normally attributes declared at the class level will be shared between instances. However, Django uses some clever code involving metaclasses to allow each instance to have different values. If you're interested in how this is possible, Marty Alchin's book Pro Django has a good explanation - or you could just read the code.
Think of the models you define as specifications. You specify the fields that you want, and when Django hands you back an instance, it has used your specifications to build you an entirely different object that looks the same.
For instance,
field1 = models.CharField()
When you assign a value to field1, such as 'I am a field', don't you think it's strange that you can assign a string to a field that is supposed to be a 'CharField'? But when you save that instance, everything still works?
Django looks at the CharField, says "this should be a string", and hands it off to you. When you save it, Django checks the value against the specification you've given, and saves it if it's valid.
This is a very simplistic view of course, but it should highlight the difference between defining a model, and the actual instance you get to work with.
This is a question prompted by another question from me.
Django provides Abstract base classes functionality (which are not to same as ABC classes in Python?) so that one can make a Model (Django's models.Model) from which one can inherit, but without that Model having an actual table in the database. One triggers this behavior by setting the 'abstract' attribute in the Model's Meta class.
Now the question: why does Django solve it this way? Why the need for this special kind of 'Abstract base class' Model? Why not make a Model mixin by just inheriting from the object class and mixing that in with an existing Model? Or could this also by a task for Python ABCs? (mind you I'm not very familiar with ABC classes in Python, my ignorance might show here)
I'll try to be reasonably brief, since this can easily turn into a lengthy diatribe:
ABCs are out because they were only introduced in Python 2.6, and the Django developers have a set roadmap for Python version support (2.3 support was only dropped in 1.2).
As for object-inheriting mixins, they would be less Pythonic in more ways than just reducing readability. Django uses a ModelBase metaclass for Model objects, which actually analyses the defined model properties on initialisation, and populates Model._meta with the fields, Meta options, and other properties. It makes sense to reuse that framework for both types of models. This also allows Django to prevent abstract model fields from being overriden by inheriting models.
There's plenty more reasons I can think of, all of them minor in themself, but they add up to make the current implementation much more Pythonic. There's nothing inherently wrong with using object-inheriting mixins though.
One of the reasons is because of the way fields are defined on a model.
Fields are specified declaratively, in a way that a normal class would treat as class attributes. Yet they need to become instance attributes for when the class is actually instantiated, so that each instance can have its own value for each field. This is managed via the metaclass. This wouldn't work with a normal abstract base class.