I want to override Classes in models.py to get call stacks at runtime.
I know that we can do following in Django in order to override manager and hence customize QuerySet API -
So, in models.py
class A(models.Model):
objects = SomeClass()
and in SomeClass
class B(Manager):
def get_query_set():
# override the way you want
But, in order to make things simpler I am thinking to use decorator to override the same - So,
in models.py
# decoratorForOverriding
class A(models.Model):
pass
in decorator.py
def decoratorForOverriding(cls):
cls.objects = SomeClass()
Error I get is
AttributeError: 'NoneType' object has no attribute '_meta'
Any idea what is going on?
Should I make the class A as an abstarct class? That did not do the trick either.
You mentioned that you were aware of how to override the Manager of a Model. I am having trouble imagining what the benefit of overriding the manager in a decorator vs as a property. as bruno desthuilliers mentions in his comment, Django does a bunch of stuff with the objects property at instantiation, the decorator probably will not work.
Do this the way Django core intended: https://docs.djangoproject.com/en/1.8/topics/db/managers/
doing otherwise is going to add technical debt for no real benefit (at least as far as I can tell). If there is something that cannot be achieved through a Manager lets tackle that problem.
Related
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.
Title says it all. I'll illustrate the question by showing what I'm trying to do.
I have extended Django's ModelForm class to create a ResourceForm, which has some functionality built into its clean() method for working with Resources, the details of which are unimportant. The ResourceForm is basically a library class, and there are no models in the app where the ResourceForm class is defined, so I can't just use an existing model from the app (e.g., mock.Mock(spec=SomeModel) is not an option).
I am trying to unit test ResourceForm, but I can't figure out the right way to mock a Django Model, which is required since ResourceForm inherits from ModelForm. This is one of several efforts I have tried (not using mock in this case, but it serves to illustrate what is being attempted):
class ResourceFormTestCase(TestCase):
class SampleModel(Model):
sample_field = CharField()
class SampleResourceForm(ResourceForm):
class Meta():
model = SampleModel
fields = ['sample_field']
def test_unsupported_field_raise_validation_error(self):
print('Test validation error is raised when unsupported field is provided')
form_data = {'sample_field': 'FooBar', 'unsupported_field': 'Baz'}
form = self.SampleResourceForm(data=form_data)
But that raises:
RuntimeError: Model class customer.tests.tests_lib_restless_ext.SampleModel doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
I'm open to suggestions if I'm way off-base in how I'm trying to test this.
The simplest thing that might work is to use the user model that comes with Django.
If that's not acceptable, I have successfully patched enough of the Django plumbing to make it shut up and run unit tests without a database connection. Look in the django_mock_queries project to see if any of that is helpful.
I want to implement a custom django.db.models.manager.Manager (let's call it MyManager) for MyModel.
The methods in MyManager needs to invoke filter methods on AnotherModel.
Is this possible ? I'm getting an ImportError because of this.
In your MyModel, you need to add your MyManager as an explicit manager.
class MyModel(models.Model):
objects = MyManager()
You can retain the standard Manager and have your manager both, by including this manager by another name.
class MyModel(models.Model):
myobjects = MyManager()
If you are using the django-admin, there are nuances involved in what manager's objects are picked up. You can find those and many other details from the awesome django documentation.
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.
This is a question about Python Mixins that might be useful in general. I'm just using Django models as that is the use-case I'm most familiar with.
Should a mixin inherit from the class it is designed to mix-in with or from 'object'?
Examples by code, what is more correct or better, or better depending on what you want to achieve?
This
class TaggingMixin(models.Model):
tag = models.ForeignKey(Tag)
class Meta:
abstract = True
class MyModel(models.Model, TaggingMixin):
title = models.CharField(max_length=100)
Or this:
class TaggingMixin(object):
tag = models.ForeignKey(Tag)
class Meta:
abstract = True
class MyModel(models.Model, TaggingMixin):
title = models.CharField(max_length=100)
I think inheriting from object is the right way. But I'm seeing examples of the first case all over the net...
EDIT: I've moved my follow up question to a separate question: Django Abstract Models vs simple Python mixins vs Python ABCs
Django does a lot of meta magic when it comes to its model classes, so unfortunately the usual approach to mixins as suggested in Daniel Roseman's answer -- where they inherit from object -- does not work well in the Django universe.
The correct way to structure your mixins, using the example provided, would be:
class TaggingMixin(models.Model):
tag = models.ForeignKey(Tag)
class Meta:
abstract = True
class MyModel(TaggingMixin):
title = models.CharField(max_length=100)
Important points here being:
Mixins inherit from model.Model but are configured as an abstract class.
Because mixins inherit from model.Model, your actual model should not inherit from it. If you do, this might trigger a consistent method resolution order exception.
I would recommend that it inherits from object. That way you can ensure that it only provides those methods and attributes you actually define explicitly.
Also, you should always ensure that you put the mixin class first when defining your concrete class. Python's resolution rules mean that the superclasses are searched in order of their definition in the class declaration, and resolution stops when a matching attribute is found. So if your mixin defines a method that is also defined by the main superclass, your mixin method won't be found.
This looks like a job for an abstract model.
EDIT:
Those are not mixins per se. Or rather, they do not need to be. You can derive from an abstract model directly.
When you inherits from plain Python object South doesn't create a migration so you can't use this approach