I have a module that implements an onchange method on res.partner. If I create a new model that inherits res.partner, the onchange is not called. Is there a way to make the onchange general, so it's also called on inherited models?
Example:
class ResPartner(models.Model):
_inherit = 'res.partner'
#api.onchange('zip')
def _valid_zip(self):
print 'Validating zip...'
class ExtendedPartner(models.Model):
_name = 'extendedpartner'
_inherits = {'res.partner': 'partner_id'}
If I change the zip code on an extendedpartner, the onchange is not called.
You use delegation inheritance in the code above. Delegation inheritance does not work on model methods. It just simply delegates lookup of fields not found in current model to the "parent" model.
I think what you want is prototype inheritence:
class ExtendedPartner(models.Model):
_name = 'extendedpartner'
_inherit = 'res.partner'
The graphic below shows three types of inheritance available in Odoo:
You currently use the first one ("classic inheritance") in ResPartner (which inherits from res.partner) and the last one (delegation inheritance) in ExtendedPartner. I think the middle one (Prototype inheritance) would be more appropriate for ExtendedPartner. It basically works in a manner very similar to standard Python inheritance.
You can read more about different types of inheritance in the documentation (which is also the source of the image above).
Related
I have a base class BaseClass with multiple subclasses SubClass1, SubClass2. In practice the program only works with instances of one of the sub-classes. The sub-classes implement an interface with the save method. When loading a saved element, you do not know the class you are loading. Therefore I was considering having the load method in the base class, but this raised the question: how do I instantiate an element from one of the sub-classes in the base class ?
For clarity, here is some simple code:
class BaseClass:
def load(self):
#load element of subclass
return subclass_element
class myInterface:
__metaclass__ = ABCMeta
#abstractmethod
def save(self):
raise NotImplementedError
class SubClass1(BaseClass, myInterface):
def save(self):
#save the element
class SubClass2(BaseClass, myInterface):
def save(self):
#save the element
I'm also open to any suggestions in favor of a different design. I'm not sure I'm not implementing an anti-pattern.
EDIT 1: Adding a factory class
From my understanding of what #Vishal_Raja and #Gholamali-Irani suggested:
class SubClassLoader: #this is our factory class
registered_subclasses = {} #static dict of subclasses
#StaticMethod
def register(classname, class):
SubClassLoader.registered_subclasses[classname] = class
#StaticMethod
def get_instance(filepath):
classname, arguments = get_classname(filepath)
if classname in SubClassLoader.registered_subclasses:
return SubClassLoader.registered_subclasses[classname](arguments)
else:
raise TypeError("Unknown class %s" % classname)
class BaseClass:
pass
class myInterface:
__metaclass__ = ABCMeta
#abstractmethod
def save(self):
raise NotImplementedError
class SubClass1(BaseClass, myInterface):
def save(self):
#save the element
class SubClass2(BaseClass, myInterface):
def save(self):
#save the element
First of all:It is bad design to make a dependency from parent to child. Inheritance (of child from parent) is a type of dependency. If you add another dependency from parent to child, you make a circular dependency and it's very hard to maintain and extendable.
In Object Oriented Design Heuristics we have:
Heuristic 5.1: Derived classes must have knowledge of their base class by definition,
but base classes should not know anything about their derived classes.
Why?
If base classes have knowledge of their derived classes, then it is
implied that if a new derived class is added to a base class, the code
of the base class will need modification. This is an undesirable
dependency between the abstractions captured in the base and derived
classes. We will see a much better solution to these types of
dependencies when we discuss the topic of polymorphism later in this
chapter. see reference
Therefore, it is bad design to put Load() into parent.
Secondly: you said:
when loading a saved element, you do not know the class you are loading.
So, your client only depend on Save() method. Therefore, their is not dependency between your client and parent. Your client only depend on the myIntrface.
Finally: your client should define an attribute from myInterface. Then you only need another class that inject the object to your client attribute. (like Factory class -as #VishalRaja's answer- or Dependency Injector class). Then you can put all desired configuration in it to decide which class instances should be passed.
Why don't you create a separate factory class which ensures the right save implementation depending on the subclass type?
I try to follow OOP and S.O.L.I.D for my code and came across a topic where I'm not sure what's the best way to align it with OOP.
When I have an Object with different properties, what's the ideal way to populate those properties?
Should the Object if possible populate them?
Should separate code assign the values to the properties?
I have the following example (Python), which I created based on how I think is the best way.
The Object has methods that will populate the properties so if you instantiate the Object, in this case an Account with and Id, it should automatically populate the properties since they can be retrieved with the ID using DB and API.
class Account:
def __init__(self, account_id):
self.id = account_id
self.name = None
self.page = Page(self.id)
def populate(self):
self.get_name()
def get_name(self):
''' Code to retrieve Account name from DB with account_id '''
self.name = <NAME>
class Page:
def __init__(self, account_id):
self.id = 0
self.name = None
self.user_count = 0
self.populate()
def populate():
self.get_id()
self.get_name()
self.get_user_count()
def get_id(self):
''' Code to retrieve Page Id from DB with account_id '''
self.id = <Page_ID>
def get_name(self):
''' Code to retrieve Account name from DB with account_id '''
self.name = <NAME>
def get_user_count(self):
''' Code to retrieve user_count from API with page_id '''
self.user_count = <user_count>
So instead of doing something like:
account = Account()
account.id = 1
account.name = function.to.get.account.name()
account.page = Page()
account.page.id = 1
I will have it managed by the class itself.
The problem I could see with this is the dependency on the DB and API classes/methods which go against S.O.L.I.D (D - Dependency Inversion Principle) as I understand.
For me it makes sense to have the class handle this, today I have some similar code that would describe the Object and then populate the Object properties in a separate Setup class, but I feel this is unnecessary.
The articles I found for OOP/S.O.L.I.D did not cover this and I didn't really find any explanation on how to handle this with OOP.
Thanks for your help!
Michael
Your design seems fairly ok. Try having a look # Builder Pattern and Composite pattern. And for your question on violation of D principle.
The problem I could see with this is the dependency on the DB and API classes/methods which go against S.O.L.I.D (D - Dependency Inversion Principle) as I understand.
The dependencies are already abstracted into separate components I guess. It is the responsibility of that component to give the data you needed per the contract. Your implementation should be independent of the what that component internally does. A DAO layer for accessing DB and Data APIs can help you achieve this.
The dependency then your system will have is the DAO component. That can be injected with different ways. There are frameworks available to help you here or you can control the creation of objects and injections when needed with some combinations of factory, builder and singleton patterns. If it is single DB instance or LogFile you may also consider using Singleton to get the component.
Hope it helps!
In looking at SOLID and OOP the key is to analyze what it is your doing and separate out the various elements to make sure that they do not end up mixed together. If they do the code tends to become brittle and difficult to change.
Looking at the Account class several questions need to be answered when considering the SOLID principles. The first is what is the responsibility of the Account class? The Single Responsibility Principle would say there should be one and only one reason for it to change. So does the Account class exist to retrieve the relevant information from the DB or does it exist for some other purpose? If for some other purpose then it has multiple responsibilities and the code should be refactored so that the class has a single responsibility.
With OOP typically when retrieving data from a DB a repository class is used to retrieve information from the DB for an object. So in this case the code that is used to retrieve information from the DB would be extracted out form the Account class and put in this repository class: AccountRepository.
Dependency Inversion means that the Account class should not depend explicitly on the AccountRepository class, instead the Account class should depend on the abstraction. The abstraction would be an interface or abstract class with no implementation. In this case we could use an interface called IAccountRepository. Now the Account class could use either an IoC container or a factory class to get the repository instance while only having knowledge of IAccountRepository
I have created a generic base class for keeping track of open forms (router) of a specific form type that also has a generic base. The problem arises when I need to call a unique derived form method from the derived router class. Is there anyway to do this?
Form router base class has
Dictionary(Of String, Forms)
Derived Form router needs to call unique methods of the derived forms stored in this dictionary. The problem is that visual studio sees the type in the dictionary as the base form class, not the derived form class (but if I do a get type during run time, the object is of the derived form class).
I've tried creating overrideable properties and functions, but the type must be specified in the base class and just using "Object" does not work.
I can post code if need be, but I'm trying to keep this simple and generic.
Thanks!
Cast the value from the dictionary to the derived type:
Dim frmDerivedForm As YourDerivedForm = CType(yourDictionary("yourKey"), YourDerivedForm)
frmDerivedForm.DerivedFormMembers()
Have you tried just casting them? (This is not tested)
Form form;
if(form is DerivedForm)
(form as DerivedForm).DerivedField = "asdf";
Form form;
if(form is DerivedForm)
((DerivedForm)form).DerivedField = "asdf";
Create a protected Overridable (virtual) method in your base class that accepts the data that you need to send to the derived class and returns the data that you need to get from the derived class and then override it in the derived (inherited) class and do what you need.
I am new in openERP and have an interview. Please explain the idea of different types of inheritance in openERP, i think it total 3 types. please explain it in very simple way from the perspective of interview.
P.S: I am familiar with the concept of simple inheritance.
Inheritance :
Inheritance mechanism is used to create idea of re usability.there re usability means that reuse the code of the parent class in any Object Oriented Programming.
Advantages :
Reduce code redundancy.
Provides code reusability.
Reduces source code size and improves code readability.
Code is easy to manage and divided into parent and child classes.
Supports code extensibility by overriding the base class
functionality within child classes.
Disadvantages :
In Inheritance base class and child classes are tightly coupled.
Hence If you change the code of parent class, it will get affects to
the all the child classes.
In class hierarchy many data members remain unused and the memory
allocated to them is not utilized. Hence affect performance of your
program if you have not implemented inheritance correctly.
There are two way to inheritance in OpenERP.
1.Classical Using Pythonic Way :
It allows to add specific "generic" behavior to Model by inheriting classes that derive from orm.Model like geoModel that adds goegraphic support.
class Myclass(GeoModel, AUtilsClass):
Using _inherit :-
The main objective is to add new behaviors/extend existing models. For example you want to add a new field to an invoice and add a new method
class AccountInvoice(orm.Model):
_inherit = "account.invoice"
_column = {'my_field': fields.char('My new field')}
def a_new_func(self, cr, uid, ids, x, y, context=None):
# my stuff
return something
override the existing method :
def existing(self, cr, uid, ids, x, y, z, context=None):
parent_res = super(AccountInvoice, self).existing(cr, uid, ids, x, y, z, context=context)
# my stuff
return parent_res_plus_my_stuff
2.Polymorphic Way :-
Using _inherits :-
When using _inherits you will do a kind of polymorphic model in the database way.
For example product.product inherits product.template or res.users inherits res.partner. This mean we create a model that gets the know how of a Model but adds aditional data/columns in a new database table. So when you create a user, all partner data is stored in res_partner table (and a partner is created) and all user related info is stored in res_users table.
To do this we use a dict: _inherits = {'res.partner': 'partner_id'} The key corresponds to the base model and the value to the foreign key to the base model.
As same through XML you can do the inherit the Odoo views (like Form view,Tree view,Search View etc ..) and you can also change the behaviour from the view
Key point :
The above two method can be apply on the Odoo server side and which you can change the behaviour of existing view or any other things you can change in Odoo views the effect with on your client side.
I hope this should helpful for you ..:)
In lithium, document and record classes, or their superclasses/interfaces, have no save() method. Yet lithium's method for saving the record is as follows:
$record = Model::create()
$record->save()
I am not certain how this works, since record does not have save method (only Model has).
Document and Record extend from a base Entity class. The Entity class has a __call() magic method. See the api doc for Entity::__call over here: http://li3.me/docs/lithium/data/Entity::__call() That method obtains an instance of the Model class associated with the Entity and then calls the method passing the entity object in as the first argument. The Adding Functions To Models section of the Lithium manual also contains additional info related to this.