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.
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.
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!
I have 2 models: a and b
I want to build a many to many relashionship and I will use the link model method, thus I need to create an a_to_b_membership model.
The question is:
Should I put the model class on the a model file?
The b model file?
Or create a new model file?
If I need to create a new model file, then how should I name it?
It makes absolutely no difference.
Firstly, however, you should realize that there's no need to have a separate file for each model. It's perfectly normal to have several model classes in one models.py file. The division is between separate apps, each of which group together related models.
Secondly, you should also realize that unless you have a specific need to add extra data on the many-to-many relationship, you don't need to create a link table. Django will take care of that for you once you define a ManyToManyField.
Does anyone can tell me if it's possible to create a Model class, with some model fields and some other fields taking their data from external data sources. The point is that I would like this model to be exploited the same way as another model by ModelForm for instance. I mean if I redefine "objects" Manager of the model by specifying the actions to get the datas for special fields (those who may not be linked to datas from the database), would the modelForm link the input with the fields not attached to the database ? Similar question about related objects. If I have a Model that has a relation with that special Model, can I get this Model instances through the classic way to get related objects (with both the classic model fields and the non-database fields) ?
Please tell me if I'm not clear, I'll reformulate.
Thanks.
EDIT: I tried to make a Model with custom fields, and then override the default Manager and its functions: all, get, ... to get objects like it would be with classical Model and Manager, it works. However, I don't use QuerySet, and it seems that the only way to get ModelForm, related objects and the admin functionnalities, working with it, is to build the QuerySet properly and let it being returned by the manager. That's why now I'm wondering if it's possible to properly and manually build a QuerySet with data got from external sources, or tell django-admin, model forms and related objects to take care of another class than queryset on this Model.
Thanks
The way is to define custom methods:
Define custom methods on a model to add custom "row-level"
functionality to your objects. Whereas Manager methods are intended to
do "table-wide" things, model methods should act on a particular model
instance.
This is a valuable technique for keeping business logic in one place
-- the model.
I have now a partial solution. I override the Manager and in particular its all() and get() functions (because I only need those functions for now). all() returns a queryset in which I added the result of some logics that give me objects build from external datas (taken through xmlrpc in my case). I added those objects to the qs through _result_cache attribute.
I think it's not clean and in fact my Model is now a custom Model and I don't have any database field. I may use it to fill database Models... However I can use it the same way as classic models: MyModel.objects.all() for example.
If anyone has another idea I'd really appreciate.
Regards
I have the Model where i have relations with 3 diff models.
Now i know that if i use
object.delete() , then child objects will also gets deleted.
Now the problem is that in my whole models classes i have the database column called DELETED which i want to set to 1 whenever someone deletes some object.
I can override the deleted function in class called BaseModel and and override the custom delete method of updating field to 1. But the problem is
If i do that way then i have to manually go through all the cascading relationships and manually call the delete ob every object.
Is there any way that by just calling object.delete(). It automatically traverses through child objects as well
Please look at Django: How can I find which of my models refer to a model.
You can use a Collector to get all references to all the necessary items using collect(). This is the code Django is using to simulate the CASCADE behavior. Once you have collected all the references, for each of those items you can update the DELETED column.
More info in the code.
Good luck.