How to access the meta attributes of a superclass in Python? - python

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)

Related

Access child class variable in parent class with no instances

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.

Can I extend parent's class list attribute on class level?

Suppose, I have the following parent class:
class Parent:
permissions = ['CanEdit', 'CanCreate']
I need to extend permissions attribute in my child class without changing the initial contents and so that this change would be on the class level, not instance, meaning:
print(Parent.permissions)
Output:
['CanEdit', 'CanCreate']
And I need the something like this in my child class:
class Child(Parent):
permissions += ['CanManage']
print(Child.permissions)
With the output:
['CanEdit', 'CanCreate', 'CanManage']
Is this even possible to implement?
You can use permissions = Parent.permissions + ['CanManage'].

django dynamic custom queryset

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()

Access peewee's Meta subclass in Model's outer class method

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)

How to detect parent class fields

I have a parent class and a child class which inherits parent. In a child class object, I need to differentiate between parent class fields and child class fields.
Is this information available? If so, where. Need solution in Python, specifically Django.
First of all, avoid any design where you need to do this. Perhaps you should be getting separate parent objects?
However, you can do this by examining the ._meta.fields property of any django model instance.
Consider such a parent and child model:
class Parent(models.Model):
parent_field = models.CharField(max_length=100)
class Child(Parent):
child_field = models.CharField(max_length=100)
To make a function that determines if a field is defined in one of the parent, we should iterate over the class.__bases__, and try baseclass._meta.get_field for each
def is_attr_defined_on_parent(child, attr):
for parent in child.__bases__:
try:
parent._meta.get_field(attr)
except models.FieldDoesNotExist:
continue
else:
return True
return False
Now:
is_attr_defined_on_parent(Child, 'parent_field') returns True,
is_attr_defined_on_parent(Child, 'child_field') returns False.

Categories

Resources