I have a class that other classes herit from:
class BaseManager:
model = Base
#classmethod
def get_by_id(cls, db: Session, id: int):
return db.query(cls.model).filter(cls.model.id == id).one()
class UserManager(BaseManager):
model = User
And it is used this way:
user = UserManager.get_by_id(db=db, id=user_id)
But the UserManager is ignoring the model defined in it, using the Base defined on BaseManager. How can I proceed?
I have already saw implementations such as django forms using metaclass and for example this question over here Access child class variable in parent class but I think that they don't apply to this context, i tried and did not succeed.
Related
I have a table to store view events, that is, if a user views an entity, a record will be stored into that table. This table is represented by a model that has a generic relation, that is, it can be related to any other model.
I have defined a mixin ViewTracked that should be extended by any model that can be tracked (i.e. class SomeModel(ViewTracked)).
I want to have a custom method for queryset of objects manager called custom_method for example. I know that I can define a custom Manager and override the objects manager with it easily, but the problem is that the tracked model can already have a custom manager that has his own custom queryset, so I can't simply override it and lose the custom queryset that it has.
Unfortunately, I couldn't find a proper way of doing this, so I tried to add a metaclass to override the manager's get_queryset and add my custom method to it, but for some reason, when I call SomeModel.objects it always returns None.
Here's what I tried:
# Meta class
class ViewTrackedMeta(ModelBase):
def __new__(mcs, class_name, base_classes, attributes_dict):
# let ModelBase do its magic
new_class = super().__new__(mcs, class_name, base_classes, attributes_dict)
if hasattr(new_class, 'objects'):
objects_manager = new_class.objects
if isinstance(objects_manager, Manager):
queryset = objects_manager.get_queryset()
def custom_method(queryset):
return queryset.filter(...)
def get_extended_queryset(manager):
queryset.custom_method = types.MethodType(custom_method, queryset)
objects_manager.get_queryset = types.MethodType(get_extended_queryset, objects_manager)
return new_class
# Mixin
class ViewTracked(Model, metaclass=ViewTrackedMeta):
class Meta:
abstract = True
...
# Models
class SomeModel(ViewTracked):
objects = CustomManager()
class SomeOtherModel(ViewTracked):
... # default django objects manager
class SomeOtherModel(ViewTracked):
objects = OtherCustomManager()
Is there any other way I can achieve what I want? Why SomeModel.objects is always returning None?
Other than instaniating your manager classes, you should be using from_queryset. Here are the docs.
class CustomQuerySet(models.QuerySet):
def manager_and_queryset_method(self):
return
class MyModel(models.Model):
objects = models.Manager.from_queryset(CustomQuerySet)()
Now you can do:
MyModel.objects.manager_and_queryset_method()
as well as
MyModel.objects.filter(something="else").manager_and_queryset_method()
Some calculations became too complex to maintain inside my model, so I decided to move them out and break the code in several classes and modules.
There's a single class serving as a facade which I would like to have available in a model instance to pass data to it.
It is being constructed from model instance:
class Calculator:
def __init__(self, field1: date, field2: float):
self.field1= field1
self.field2 = field2
#classmethod
def from_django_model(cls, django_model_instance):
field1 = django_model_instance.field1
field2 = float(django_model_instance.field2)
Currently I call it inside each property on my model like so:
class DjangoModel(models.Model):
# initialize the calculator
def calculator(self, group):
return calculator.Calculator.from_django_model(self)
# use it
#cached_property
def calculated_field(self):
try:
return self.calculator().calculation_method
except AttributeError:
return "Field not set!"
I feel this is not a good solution, since now on multiple methods I'm initializing the calculator object multiple times.
I would like to construct it once when the model is initialized and then pass it to the model instance.
I tried doing this with model manager, but the model instance is not available with it.
I'm trying to wrap peewee models and classes into other interface and i want to dynamically assign model to database. I'm using peewee.Proxy class for this, but i don't want to use global variable for making initialization of this proxy available. I wanted to make class method for changing Meta (inner) class of base model, but i get following error:
AttributeError: type object 'BaseModel' has no attribute 'Meta'
Code that i have:
import peewee as pw
class BaseModel(pw.Model):
class Meta:
database = pw.Proxy()
#classmethod
def configure_proxy(cls, database: pw.Database):
cls.Meta.database.initialize(database)
Of course i could access this variable by calling BaseModel.Meta.database but it is less intuitive in my opinion.
Have you got any suggestions?
Peewee transforms the inner "Meta" class into an object accessible at "ModelClass._meta" after the class is constructed:
Change ".Meta" to "._meta":
class BaseModel(pw.Model):
class Meta:
database = pw.Proxy()
#classmethod
def configure_proxy(cls, database: pw.Database):
cls._meta.database.initialize(database)
I don't know exactly why you are having this problem, and I'd be interested in the full answer.
The problem is with the name Meta. I'm guessing there's something by that name defined in pw.Model but I haven't been through it all yet.
That said, this (for example) works:
import peewee as pw
class BaseModel(pw.Model):
class MyMeta:
database = pw.Proxy()
#classmethod
def configure_proxy(cls, database: pw.Database):
cls.MyMeta.database.initialize(database)
I have dozens of classes built in this fashion:
class playlist_type_1(radio):
'''child class'''
def __init__(self,user, type):
radio.__init__(self, user, type)
class playlist_type_2(radio):
'''child class'''
def __init__(self,user,type):
radio.__init__(self, user, type)
they inherit from:
class radio(self, user, type):
'''parent class'''
since I will have many users, I'm trying build a model for creating instances like so:
thom = playlist_type1('Thom Yorke', 'playlist_type_1')
the user himself, thom, will chose his playlist_type_n at command line via:
string = raw_input('Choose a playlist type> ')
and instance will be created and run:
thom = playlist_type1('Thom Yorke', string)
can this be implemented within class scope?
Create a mapping of names to classes and then instantiate the class based on that:
class PlaylistType1(Radio):
pass
class PlaylistType2(Radio):
pass
playlist_types = {
PlaylistType1.__name__: PlaylistType1,
PlaylistType2.__name__: PlaylistType2,
}
...
playlist = playlist_types[chosen_type](user)
I have some code like this for Django-Tastypie:
class SpecializedResource(ModelResource):
class Meta:
authentication = MyCustomAuthentication()
class TestResource(SpecializedResource):
class Meta:
# the following style works:
authentication = SpecializedResource.authentication
# but the following style does not:
super(TestResource, meta).authentication
I would like to know what would be the right method of accessing meta attributes of the superclass without hard-coding the name of the superclass.
In your example it seems that you are trying to override the attribute of the meta of the super class. Why not use meta inheritance?
class MyCustomAuthentication(Authentication):
pass
class SpecializedResource(ModelResource):
class Meta:
authentication = MyCustomAuthentication()
class TestResource(SpecializedResource):
class Meta(SpecializedResource.Meta):
# just inheriting from parent meta
pass
print Meta.authentication
Output:
<__main__.MyCustomAuthentication object at 0x6160d10>
so that the TestResource's meta are inheriting from parent meta (here the authentication attribute).
Finally answering the question:
If you really want to access it (for example to append stuff to a parent list and so on), you can use your example:
class TestResource(SpecializedResource):
class Meta(SpecializedResource.Meta):
authentication = SpecializedResource.Meta.authentication # works (but hardcoding)
or without hard coding the super class:
class TestResource(SpecializedResource):
class Meta(SpecializedResource.Meta):
authentication = TestResource.Meta.authentication # works (because of the inheritance)