Transient use of Django Model instances - django

I have a use case where a particular class can either be transient or persistent. Transient instances are build from a JSON payload on a PUT call, and may either be persisted to the database or used during the server call and then either returned or discarded. What is best practice for this case? My options seem to be:
Write two classes, one of which is a models.Model subclass, and the other of which isn't, and make them implement the same API, or
Use the Model subclass, but be careful not to call save().
Is either of these preferable, according to conventional use of Django models?

You'll need both:
abstract = True is useful if inheritants still should be concrete models, so that no table should be created just for the parent class. It allows you to opt out of multi-table inheritance, and instead have the shared attributes duplicated to inheritants tables instead (abstract base inheritance).
managed = False is useful if the inheriting class should never be persisted at all. Django migrations and fixtures won't generate any database table for this.
class TransientModel(models.Model):
"""Inherit from this class to use django constructors and serialization but no database management"""
def save(*args, **kwargs):
pass # avoid exceptions if called
class Meta:
abstract = True # no table for this class
managed = False # no database management
class Brutto(TransientModel):
"""This is not persisted. No table app_brutto"""
#do more things here
pass

In order to remain as DRY as possible, you could have an abstract mock class deriving your model:
class A(models.Model):
# fields'n'stuff
class TransientA(A):
def save(*args, **kwargs):
pass # avoid exceptions if called
class Meta:
abstract = True # no table created
Now, even if you call save on it anywhere (even in methods inherited from A), you'll be shooting blanks.

Related

DJANGO - class Meta / varibales db_table

I would like to get a variable in my meta class
class Meta:
abstract = True
db_table = 'bikes_table'
managed = False
I want to get a variable from self like above :
class Meta:
abstract = True
db_table = 'bikes_table' if self.customers=True else 'cars_table'
managed = False
Is it possible de get variable ?
Thank you
As stated in the comments, the surface problem is that "self" won't be available at class definition time, of course.
Some of the fields in the Metadata could have values that could change at runtime, for each instance, those will accept callback functions instead of static values (but looking at the documentation, there seems to be none)
Now, the table corresponding to a certain Model is used by the ORM and will be bound at the class level. Doubly so because a lot of the queries dealing with a class have to issue database statements without having an instance, as is the case for any query. I mean, in your example, a vehicle.objects.all() would have to query both database tables and bring the results together in the same response.
It could be done by subclassing Django's internal Queryset databases, and carefully rewriting it to look at the "table" model meta data in a custom way, but it would be prone to error.
So, you'd rather rethink your design. It is easier to simply have a Vehicle base class, just use "Vehicle" on your forms and relations, and derive the Bicycle and Car classes from that - either a car or a bicycle could be used wherever a vehicle can. Django provides support for the relationship itself with Generic Relations

Converting attributes of class to a django models subclass

I have a bunch of classes that I'm now trying to incorporate into django.
For example, I have a Base class that all my other classes derive from:
class Base:
def __init__(self, label: str = 'Base'):
self.label = label
An example of a sublcass would be a Person class:
from typing import Any, Dict
class Person(Base):
def __init__(self, name: str, attributes_to_options: Dict[str, Any], **kwargs):
super().__init__(**kwargs)
self.name = name
self.attributes_to_options = attributes_to_options
I would use this as:
alex = Person(name='Alex', attributes_to_options={'age': 10, 'is_happy': True}, label='Person:Alex')
My question is, how do I incorporate such a class into django? Is it as simple as inheritting from models.Model? e.g.
from django.db import models
class Person(Base, models.Model):
def __init__(self, name: str, attributes_to_options: Dict[str, Any], **kwargs):
super().__init__(**kwargs)
self.name = name
self.attributes_to_options = attributes_to_options
But then how do I specify the models.CharField for the two attributes name and attributes_to_options?
Thanks for any help here.
Bear in mind that in general, any Django Model subclass corresponds to a database table. Inheriting from such a class ("concrete inheritance") means that another database table will be created with a one-to-one linkage between rows, and that every query will implicitly perform a join in the DB. This is bad for performance. But for tables with not very many rows or for tables queried infrequently, you possibly don't need to care.
Django provides two special cases that can be defined via the Meta class in the Model subclass. The first is an "Abstract Base Class" which allow you to define a bunch of stuff which will be present in any derived model. IN the case of fields, they are "copied" into the class that inherits them, rather than having their own DB table. The second is a "Proxy" class, which allows you to place a new set of methods on top of an existing database table, and which goes some way towards allowing polymorphic models. Careful reading of the Django doc. is a good idea.
I have experimentally established that one can also use mix-in classes in the same way as one uses them with class-based views. In other words,
class ExtraMethodsMixin( object): # NB must inherit from object
# NB no model field definitions allowed here
#property
def something_or_other(self):
return something_based_on_model_fields_defined_elsewhere
#etc.
and then
class Foo( ExtraMethodsMixin, models.Model): # NB mixin goes first
# define names and fields that the ExtraMethodsMixin uses
# (and anything else that a Foo needs)
...
The one snag I have found is that migrations do remember the dependency of Foo on ExtraMethodsMixin and so it's a PITA should you desire to completely remove the mixin at a later date. However, you can stub it out to a single pass statement without any problems, so this is probably not a significant worry. My other worry is that this usage is completely undocumented (other than as standard Python), so it's just about possible that it's trampling on Django internals in some very subtle way I've not yet spotted. So I'm definitely a bit short of recommending this technique.

How to modify Django's Manager QuerySet create() method?

I have two models, Invoice and InvoiceItems, which have a one-to-many relationship.
Throughout the code base we're creating InvoiceItems for a given Invoice using the Manager object as:
invoice.invoice_items.create(...)
The thing is, now we have a validation that has to take place before trying to create an InvoiceItem, and going through the codebase, refactoring all the creation pieces would be a headache.
I wonder if there's a way to override the create method itself or should we go for the model's save()?
To modify a Manager's method you need to create your own. Given the following case:
# models
class MyModel(models.Model):
# ... fields
objects = MyManager()
class MyManager(models.Manager):
def create(self):
# write your own code here
pass
Do not worry about the others methods (filter, delete, etc.) all of them will work as usual.
You can find more about custom managers here

Django: multiple table inheritance doesnt allow me to access derived class from base class

I want to get a derived modelclass instance from an instanciated base modelclass.
I have the following model class hierarchy:
class AlfrescoPFCModel(models.Model):
#some fields and methods
class Meta:
abstract = True
class Contenido(AlfrescoPFCModel):
#some fields and methods
class Proyecto(Contenido):
#some fields and methods
class ProyectoCalificado(Proyecto):
#some fields and methods
class ProyectoArchivado(ProyectoCalificado):
#some fields and methods
And I instantiate a Proyecto class in this way:
proyecto = proyecto_form.save(commit=False)
#do some stuff with some fields that dont appear on the form
proyecto.save
In another view I try to access the derived class ProyectoCalificado from the base class Proyecto previously instanciated and saved in the database doing:
pc = ProyectoCalificado.objects.get(pk=id)
and i get: ProyectoCalificado matching query does not exist.
I also tried:
p = get_object_or_404(Proyecto, id=id)
pc = p.proyectocalificado
but it get the same error in the second line.
Reading the documentation i should be allowed to do that:
#multi-table-inheritance
What i want to do is to incrementally complete the data associated to a Proyecto (project) following this workflow: Proyecto -> ProyectoCalificado -> ProyectoArchivado.
I have 3 different forms for each step. I need 3 different models because I need to save them in the database without filling all the mandatory fields at once.
Thanks!
Use Form Wizards (https://docs.djangoproject.com/en/dev/ref/contrib/formtools/form-wizard/).
UPDATE
If you can't use Form Wizards because of the situation you describe, then you should make the models fields blank or nullable at the database level and then only enforce field requirements on each individual form. Creating three levels of inheritance solely for the purpose of the single-time set of forms required to create it is absolutely the wrong approach. It only fragments your data across additional tables and makes querying more complicated with no long-term benefit.
So, for example. Set the model itself up as though nothing (or only the items in the first form) are required. Then, in your first form, only make the fields necessary for that particular stage required. You can do this easily by overriding the __init__:
class FirstForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(FirstForm, self).__init__(*args, **kwargs)
self.fields['some_required_field'].required = True
# rinse and repeat
Do the same in your second and third forms, again making on the actual fields that are required for that particular form, required.
Then, call it day and have a drink.
If you have the child instance, it should have a <base class name>_ptr member which points to the instance of its superclass. You can use this as the basis of a filter query to retrieve the child.
You can also just assume that instances of the base and derived class will have the same id if you haven't done anything to affect how ids are allocated.

How to go from a Model base to derived class in Django?

Assuming a simple set of inherited Model classes, like this:
class BaseObject(models.Model):
some_field = models.SomeField(...)
class AwesomeObject(BaseObject):
awesome_field = models.AwesomeField(...)
class ExcellentObject(BaseObject):
excellent_field = models.ExcellentField(...)
and a query that looks like this:
found_objects = BaseObject.objects.filter(some_field='bogus')
What's the best way to take each found object and turn it back into it's derived class? The code I'm using now is like this:
for found in found_objects:
if hasattr(found, 'awesomeobject'):
ProcessAwesome(found.awesomeobject)
elif hasattr(found, 'excellentobject'):
ProcessExcellent(found.excellentobject):
But, it feels like this is an abuse of "hasattr". Is there a better way to do this without creating an explicit "type" field on the base class?
For this specific problem, there is django-polymorphic. It works by using the content type framework in Django to store the model ID which the derived table points to. When you evaluate the queryset, it will upcast all models their specific type.
You'll get:
>>> BaseProject.objects.all()
[ <AwesomeObject>, <ExcellentObject>, <BaseObject>, <AwesomeObject> ]
That's the best way that I know of. Unfortunately, inheritance is a little clunky in this regard. Multiple table inheritance is basically just a one-to-one relationship between the parent model and the extra fields the child adds, which is why that hasattr trick works. You can think of each of those as a OneToOneField attribute on your parent model. When you think of it that way, Django has no way of knowing which child to return or even if to return a child, so you have to handle that logic yourself:
I tend to create a method on the parent such as get_child, which simply cycles through the attributes and returns the one that pops:
class BaseObject(models.Model):
some_field = models.SomeField(...)
def get_child(self):
if hasattr(self, 'awesomeobject'):
return ProcessAwesome(found.awesomeobject)
elif hasattr(self, 'excellentobject'):
return ProcessExcellent(found.excellentobject):
else:
return None
At least then, you can just call found.get_child(), and maybe forget about the hackery that gets you there.
Going from a base class to a derived class is generally a sign of bad design in a program. The method you propose, using hasattr, can be a serious problem. I'll show you:
# defined in some open source library
class MyObject(object):
def what_is_derived(self):
if hasattr(self, 'derived1'):
return 'derived1'
elif hasattr(self, 'derived2'):
return 'derived2'
else:
return 'base'
Let's pretend that classes Derived1 and Derived2 are defined in that same library. Now, you want to use the features of MyObject, so you derive from it in your own code.
# defined in your own code
class MyBetterObject(MyObject):
pass
better_object = MyBetterObject()
better_object.what_is_derived() # prints 'base'
The whole point of polymorphism is that you can have many derived classes without the base class having to change. By making the base class aware of all of it's derived classes, you severely reduce the usefulness of such a class. You can't create a derived class without changing the base class.
Either you want to work with a derived class, or you don't care what the specific class is and all you need are the properties/methods of the base class. It is the same in all OOP languages. There are facilities for finding out what the derived class is, but usually it's a bad idea.
From a django models perspective, I usually use inheritance in such a way:
class Address(models.Model):
# fields...
class Person(Address):
# fields...
class Business(Address):
# fields...
Address.objects.all() # find all addresses for whatever reason
Person.objects.all() # im only interested in people
Business.objects.all() # need to work with businesses
# need to show all addresses in a postcode, and what type of address they are?
businesses = Business.objects.filter(postcode='90210')
people = Person.objects.filter(postcode='90210')
# use the address properties on both
Deeply nested inheritance chains with django models are awkward. They are also pretty unnecessary in most cases. Instead of polluting your base class with hasattr checks, define a helper method which is capable of querying the required derived classes if such a thing is called for. Just don't define it on the Base class.
I use introspection ;
class Base(models.Model):
[ we have some unique 'key' attribute ]
class_name = models.CharField(..., editable=False)
def get_base(self):
if self.__class__ == Base:
return self
# if we are not an instance of Base we 'go up'
return Base.objects.get(key=self.key)
def get_specific(self):
if self.__class__ != Base:
return self
# if we are an instance of Base we find the specific class
class_type = getattr(sys.modules["project.app.models"],
self.class_name)
return class_type.objects.get(key=self.key)
You need some factory to create the specific classes so you are sure to correctly save str(self.class) in class_name
You can also use InheritanceQuerySet from django-model-utils in case you want to explicitly state which queries to affect, like this:
from model_utils.managers import InheritanceQuerySet
class UserManager([...]):
def get_queryset(self):
return InheritanceQuerySet(self.model).select_subclasses()
(code from https://stackoverflow.com/a/25108201)