Using for example
class model(models.Model)
....
def my_custom_method(self, *args, **kwargs):
#do something
When I try to call this method during pre_save, save, post_save etc, Python raises a TypeError; unbound method.
How can one add custom model methods which can be executed in the same way like model.objects.get(), etc?
Edit: tried using super(model, self).my_custom_method(*args, **kwargs) but in that case Python says that model does not have attribute my_custom_method
How are you calling this method? You have defined an instance method, which can only be called on an instance of the class, not the class itself. In other words, once you have an instance of model called mymodelinstance, you can do mymodelinstance.my_custom_method().
If you want to call it on the class, you need to define a classmethod. You can do this with the #classmethod decorator on your method. Note that by convention the first parameter to a classmethod is cls, not self. See the Python documentation for details on classmethod.
However, if what you actually want to do is to add a method that does a queryset-level operation, like objects.filter() or objects.get(), then your best bet is to define a custom Manager and add your method there. Then you will be able to do model.objects.my_custom_method(). Again, see the Django documentation on Managers.
If you are implementing a Signal for your model it does not necessarily need to be defined in the model class only. You can define it outside the class and pass the class name as the parameter to the connect function.
However, in your case you need the model object to access the method.
Related
I want to write a mock for a library object without inheriting from it in order to properly test, however without having to stub all non used functions of the original object.
To be specific I want to write a ContextMock for the invoke library.
class ContextMock:
...
The main problem here is that I therefor call a #task function which then calls my code that I want to test. However the #task decorator checks whether the context object is an instance of a Context, like this:
def __call__(self, *args, **kwargs):
# Guard against calling tasks with no context.
if not isinstance(args[0], Context):
err = "Task expected a Context as its first arg, got {} instead!"
# TODO: raise a custom subclass _of_ TypeError instead
raise TypeError(err.format(type(args[0])))
Therefor my question is, can I somehow change the isinstance function of my ContextMock, or make it look like its an instance of Context without inheriting its attributes?
Or would it be possible to somehow mock the isinstance function?
How does the default implementation of instancecheck work? Is there perhabs a baseclass attribute that can be overwritten?
I already tried to provide a custom metaclass with an custom instancecheck function, which of course does not work as the instancecheck of the Context is called, right?
Also Note that I'm well aware that any hacky solution should not belong in production code, and is only used for testing.
Edit:
To add a generic example of what I want to archive:
class Context:
pass
class ContextMock:
pass
mock = ContextMock
... do magic with mock
assert isinstance(mock, Context)
This is supposed to be a Django-specific, but I guess it's Python anyway.
Basically, I don't want to override the work of the original method in the class I am inheriting (could be a Model class), but I'd like to add additional validation. Is this possible? Any hint?
class MyUserAdminForm(forms.ModelForm):
class Meta:
model = User
def clean(self):
// do some additional work even though it's cleaned by parent's clean method
Call the super classes clean method:
def clean(self):
super(MyUserAdminForm, self).clean()
# more cleaning
This is a common python thing to do when you subclass something and redefine functionaly but want to make sure you keep the super class functionality. Extremely common when you do an init method, as you always need to ensure the super class constructor gets called to set up the instance.
class ContactForm(forms.Form):
message = forms.CharField()
def clean_message(self):
num_words = len(message.split())
if num_words<4:
raise forms.ValidationError("Too short a message!")
return message
This is the way you add a validation method on a field, and this does ensure that the default cleanup happens. There is no need to call the default cleanup method again.
Source: www.djangobook.com
How it works:
When is_valid() is called on the form object, the system looks for any methods in the class that begin with clean_ and ends with an attribute name. If they do, it runs them after running the default cleanup methods.
As might be familiar to most of you, this is from Mark Pilgrim's book DIP, chapter 5
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
Well I am new to python, coming from basic C background and having confusion understanding it. Stating what I understand, before what I don't understand.
Statement 0: FileInfo is inheriting from class UserDict
Statement 1: __init__ is not a constructor, however after the class instantiates, this is the first method that is defined.
Statement2: self is almost like this
Now the trouble:
as per St1 init is defined as the first function.
UserDict.__init__(self)
Now within the same function __init__ why is the function being referenced, there is no inherent recursion I guess. Or is it trying to override the __init__ method of the class UserDict which the class FileInfo has inherited and put an extra parameter(key value pair) of filename and reference it to the filename being passed to __init__ method.
I am partly sure, I have answered my question, however as you can sense there is confusion, would be great if someone can explain me how to rule this confusion out with some more advanced use case and detailed example of how generally code is written.
You're correct, the __init__ method is not a constructor, it's an initializer called after the object is instantiated.
In the code you've presented, the __init__ method on the FileInfo class is extending the functionality of the __init__ method of the base class, UserDict. By calling the base __init__ method, it executes any code in the base class's initialization, and then adds its own. Without a call to the base class's __init__ method, only the code explicitly added to FileInfo's __init__ method would be called.
The conventional way to do this is by using the super method.
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
super(UserDict, self).__init__()
self["name"] = filename
A common use case is returning extra values or adding additional functionality. In Django's class based views, the method get_context_data is used to get the data dictionary for rendering templates. So in an extended method, you'd get whatever values are returned from the base method, and then add your own.
class MyView(TemplateView):
def get_context_data(self, **kwargs):
context = super(MyClass, self).get_context_data(**kwargs)
context['new_key'] = self.some_custom_method()
return kwargs
This way you do not need to reimplement the functionality of the base method when you want to extend it.
Creating an object in Python is a two-step process:
__new__(self, ...) # constructor
__init__(self, ...) # initializer
__new__ has the responsibility of creating the object, and is used primarily when the object is supposed to be immutable.
__init__ is called after __new__, and does any further configuration needed. Since most objects in Python are mutable, __new__ is usually skipped.
self refers to the object in question. For example, if you have d = dict(); d.keys() then in the keys method self would refer to d, not to dict.
When a subclass has a method of the same name as its parent class, Python calls the subclass' method and ignores the parent's; so if the parent's method needs to be called, the subclass method must call it.
"Or is it trying to override the init method of the class UserDict which the class FileInfo has inherited and put an extra parameter(key value pair) of filename and reference it to the filename being passed to init method."
It's exactly that. UserDict.__init__(self) calls the superclass init method.
Since you come from C, maybe you're not well experienced with OOP, so you could read this article : http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming) to understand the inheritance principle better (and the "superclass" term I used).
.. the self variable represents the instance of the object itself. In python this is not a hidden parameter as in other languages. You have to declare it explicitly. When you create an instance of the FileInfo class and call its methods, it will be passed automatically,
The __init__ method is roughly what represents a constructor in Python.
The __init__ method of FileInfo is overriding the __init__ method of UserDict.
Then FileInfo.__init__ calls UserDict.__init__ on the newly created FileInfo instance (self). This way all properties and magic available to UserDict are now available to that FileInfo instance (ie. they are inherited from UserDict).
The last line is the reason for overriding UserDict.__init__ : UserDict does not create the wanted property self.filename.
When you call __init__ method for a class that is inheriting from a base class, you generally modify the ancestor class and as a part of customization, you extend the ancestor's init method with proper arguements.
__init__ is not a constructor, however after the class instantiates, this is the first method that is defined.
This method is called when an instance is being initialized, after __new__ (i.e. when you call ClassName()). I'm not sure what difference there is as opposed to a constructor.
Statement2: self is almost like this
Yes but it is not a language construct. The name self is just convention. The first parameter passed to an instance method is always a reference to the class instance itself, so writing self there is just to name it (assign it to variable).
UserDict.__init__(self)
Here you are calling the UserDict's __init__ method and passing it a reference to the new instance (because you are not calling it with self.method_name, it is not passed automatically. You cannot call an inherited class's constructor without referencing its name, or using super). So what you are doing is initializing your object the same way any UserDict object would be initialized.
I have a module (db.py) which loads data from different database types (sqlite,mysql etc..) the module contains a class db_loader and subclasses (sqlite_loader,mysql_loader) which inherit from it.
The type of database being used is in a separate params file,
How does the user get the right object back?
i.e how do I do:
loader = db.loader()
Do I use a method called loader in the db.py module or is there a more elegant way whereby a class can pick its own subclass based on a parameter? Is there a standard way to do this kind of thing?
Sounds like you want the Factory Pattern. You define a factory method (either in your module, or perhaps in a common parent class for all the objects it can produce) that you pass the parameter to, and it will return an instance of the correct class. In python the problem is a bit simpler than perhaps some of the details on the wikipedia article as your types are dynamic.
class Animal(object):
#staticmethod
def get_animal_which_makes_noise(noise):
if noise == 'meow':
return Cat()
elif noise == 'woof':
return Dog()
class Cat(Animal):
...
class Dog(Animal):
...
is there a more elegant way whereby a class can pick its own subclass based on a parameter?
You can do this by overriding your base class's __new__ method. This will allow you to simply go loader = db_loader(db_type) and loader will magically be the correct subclass for the database type. This solution is mildly more complicated than the other answers, but IMHO it is surely the most elegant.
In its simplest form:
class Parent():
def __new__(cls, feature):
subclass_map = {subclass.feature: subclass for subclass in cls.__subclasses__()}
subclass = subclass_map[feature]
instance = super(Parent, subclass).__new__(subclass)
return instance
class Child1(Parent):
feature = 1
class Child2(Parent):
feature = 2
type(Parent(1)) # <class '__main__.Child1'>
type(Parent(2)) # <class '__main__.Child2'>
(Note that as long as __new__ returns an instance of cls, the instance's __init__ method will automatically be called for you.)
This simple version has issues though and would need to be expanded upon and tailored to fit your desired behaviour. Most notably, this is something you'd probably want to address:
Parent(3) # KeyError
Child1(1) # KeyError
So I'd recommend either adding cls to subclass_map or using it as the default, like so subclass_map.get(feature, cls). If your base class isn't meant to be instantiated -- maybe it even has abstract methods? -- then I'd recommend giving Parent the metaclass abc.ABCMeta.
If you have grandchild classes too, then I'd recommend putting the gathering of subclasses into a recursive class method that follows each lineage to the end, adding all descendants.
This solution is more beautiful than the factory method pattern IMHO. And unlike some of the other answers, it's self-maintaining because the list of subclasses is created dynamically, instead of being kept in a hardcoded mapping. And this will only instantiate subclasses, unlike one of the other answers, which would instantiate anything in the global namespace matching the given parameter.
I'd store the name of the subclass in the params file, and have a factory method that would instantiate the class given its name:
class loader(object):
#staticmethod
def get_loader(name):
return globals()[name]()
class sqlite_loader(loader): pass
class mysql_loader(loader): pass
print type(loader.get_loader('sqlite_loader'))
print type(loader.get_loader('mysql_loader'))
Store the classes in a dict, instantiate the correct one based on your param:
db_loaders = dict(sqlite=sqlite_loader, mysql=mysql_loader)
loader = db_loaders.get(db_type, default_loader)()
where db_type is the paramter you are switching on, and sqlite_loader and mysql_loader are the "loader" classes.
I would like to add some methods to the datetime.datetime object. It seems that we can only do that by inheriting from it and adding this new method. The problem is that this method need to update the day/month/year values of the base class and that i can't call the base init method with the new parameters.
How can I do this?
You can call the base class __init__ method.
class Foo(datetime.datetime):
def __init__(self, argument):
datetime.datetime.__init__(self, argument)
The key point here is that you need to call the __init__ method explicitly and you need to manually supply the first self argument that Python normally supplies for you.
Also, don't forget about the * and ** calling techniques to catch arguments that you don't want to deal with manually but that you still want to be able to pass to the parent constructor.