I have created a parent model, which has a Selection field.
This pattern must be inherited from classes that offer a service, so in the child classes I use fields.Selection(selection_add = ....). Is it possible to create, in the parent class, an "empty" selection that will only fill with the selection fields of the models that inherit it?
Ex
class GenericService(models.Model):
_name = 'generic.service'
selection_type = fields.Selection(
[('select_type', _("Select an Account")),],default='select_type',
string=_("Service Type"),
required=True
class SpecificService(model.Model):
_inherit = 'generic.service'
selection_type = fields.Selection(
selection_add=[('sftp','SFTP')],
)
I would like to avoid adding a default field on the generic model selection, my alternative is to create a method that controls the insertion, but I would like to know if it could be avoided.
If you inherit like that _inherit without _name. Then you end up only with 1 model generic.service And all selection_add=[] added selections.
If you add
class GenericService(models.Model):
_name = 'generic.service'
selection_types = fields.Selection([], string="Service Type")
class SpecificServiceA(model.Model):
_inherit = 'generic.service'
selection_type = fields.Selection(
selection_add=[('sftp','SFTP')], required=True
)
class SpecificServiceB(model.Model):
_inherit = 'generic.service'
selection_type = fields.Selection(
selection_add=[('https','HTTPS')], required=True
)
you end up with model named "generic.service" and selections [('sftp','SFTP'), ('https','HTTPS')]
I believe strings and selection names are added automatically to translation list. no need for _()
You can also use Odoo's mixin feature, which is a bit like abstract types/classes. Following an example in context of your requirments:
class ServiceMixin(models.AbstractModel):
_name = "service.mixin"
def _get_type_selection(self):
""" Returns a 2-tuple list for type_selection field
Meant to be extended by inheriting models."""
return []
type_selection = fields.Selection(
selection="_get_type_selection", string="Type")
class ServiceA(models.Model):
_name = "service.a"
_inherit = ["service.mixin"]
def _get_type_selection(self):
""" Returns a 2-tuple list for type_selection field"""
return [('a', 'A'), ('b', 'B')]
class ServiceB(models.Model):
_name = "service.b"
_inherit = ["service.mixin"]
def _get_type_selection(self):
""" Returns a 2-tuple list for type_selection field"""
return [('a', 'A'), ('c', 'C')]
In database that will lead to 2 new tables: service_a and service_b. So you have really 2 new Odoo models, which aren't dependend on eachother.
Related
I am using DRF for creating API, using basic APIView. Below are the models and views.
models.py
from django.db import models
from django.utils import timezone
class PizzaOrder(models.Model):
name = models.CharField(max_length=120)
size = models.CharField(default='MEDIUM')
customer_name = models.CharField(max_length=120)
customer_address = models.TextField()
ordered_time = models.DateTimeField(default=timezone.now)
Now, I need two things in that.
First - I want to set STATUS as 'open' in the database while ordering pizza. User isn't able to see the STATUS column while saving.
Second - I want to get all orders, but it should show STATUS to the user now.
view.py
class PizzaOrderView(APIView):
def get(self, request):
orders = PizzaOrder.objects.all()
serializer = ArticleSerializer(orders, many=True)
return Response({"orders": serializer.data})
def post(self, request):
orders = request.data.get('orders')
serializer = ArticleSerializer(data=orders)
if serializer.is_valid(raise_exception=True):
article_saved = serializer.save()
What should I do to get my all two requirements?
First of all if you want to save status in the database you must include it as one of the fields in your model. I would also suggest adding the choices enumeration so that nothing unwanted can end up in database as a status (note that you can add any other choice besides open and closed):
class PizzaOrder(models.Model):
...
OPEN = 'open'
CLOSED = 'closed'
TYPE_CHOICES = (
(OPEN, 'Open'),
(CLOSED, 'Closed'),
)
status = models.CharField(max_length=120, choices=STATUS_CHOICES, default=OPEN)
Next thing to know is that the way data is presented to the user depends mostly on your serializers (would be useful if you could include those in your question aswell). So for serializing the PizzaOrder data you can use two different serializers (one which includes the status field, and one which does not):
class PizzaOrderSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
fields = '__all__'
class PizzaOrderWithoutStatusSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
fields = ['name', 'size', 'customer_name', 'customer_address', 'ordered_time']
you can user one serializer just just using the one serializer
class PizzaOrderSerializer(serializers.ModelSerializer):
class Meta:
model = PizzaOrder
fields = '__all__'
read_only_fields = ('status',)
I have a class named detail_base, and two other classes name flight_detail and tour_detail, the last two classes inherits from the first one, like this:
class DetailBase(models.Model):
_name = 'detail_base'
fee = fields.Monetary('Fee')
passenger = fields.Char('Passenger')
class FlightDetail(models.Model):
_name = 'flight_detail'
_inherits = 'detail_base'
passport = fields.Char('Passport')
class TourDetail(models.Model):
_name = 'tour_detail'
_inherits = 'detail_base'
age = fields.Integer('Tourist Age')
The problem is when I call the flight_detail and tour_detail in the same view, the browser can't handle the common attributes of both classes, If I assign 5 to tour_detail.fee, that number will be stored into flight_detail.fee.
It seems the problem is related to the attributes with the same name of different objects being siblings.
I will appreciate any help.
You should either use _inherit
class DetailBase(models.AbstractModel):
_name = 'detail_base'
fee = fields.Monetary('Fee')
passenger = fields.Char('Passenger')
class FlightDetail(models.Model):
_name = 'flight_detail'
_inherit = 'detail_base'
passport = fields.Char('Passport')
class TourDetail(models.Model):
_name = 'tour_detail'
_inherit = 'detail_base'
age = fields.Integer('Tourist Age')
which should either create 3 database tables (detail_base as Model) or 2 database tables (AbstractModel).
Or you use _inherits like:
class DetailBase(models.Model):
_name = 'detail_base'
fee = fields.Monetary('Fee')
passenger = fields.Char('Passenger')
class FlightDetail(models.Model):
_name = 'flight_detail'
_inherits = {'detail_base': 'base_id'}
passport = fields.Char('Passport')
base_id = fields.Many2one('detail_base', required=True, ondelete='cascade')
class TourDetail(models.Model):
_name = 'tour_detail'
_inherit = {'detail_base': 'base_id'}
age = fields.Integer('Tourist Age')
base_id = fields.Many2one('detail_base', required=True, ondelete='cascade')
That will create 3 tables, and fee and passenger will be stored in detail_base table. Odoo will get it from there, because it is a sort of delegation inheritence.
use inherit:
1- inherit without _name :
inherit = 'model.name'
new_field = fields...
this add this field to the model.name
2- inherit with _name:
inherit = 'model.name'
_name = 'new.model'
here will create a new tabel in database with the same structure of model.name.
inherits: The delegation inheritance.
best example is res.users and res.partners user is a partener so when we create a res.users record we must create a res.partener that hold commun field like name, email, address ... and information related to users like passowrd and login are stored in res.users model and with type of inheritence you can access field of res.partener directly without having to create a related field. you can do user_record.name or .email or .address this will not be a problem.
i like to think of it as one2one relation.
_inherits = {model.name : many2one_field_id }
_name = 'new.model'
# m2o field should be required and ondelete = cascade
many2one_field_id = fields.Many2one('model.name', string='Label', required=True, ondelete="cascade")
so when you create a record of new.model all field that are in model.name will be stored in model.name.
I have model contains many to many assign_to_id, I want to modify that field in wizard form through escalte_to method when user trigger escalate button
Model:
class Incident(models.Model):
_name = 'itmangement.incident'
assigned_to_id = fields.Many2one('hr.employee', string="Assigned To",domain="[('department_id', '=', dep_id)]",required=True)
Wizard model
class Escalate(models.TransientModel):
escalated_to = fields.Many2one('hr.employee', string="Escalated To", required=True)
#api.one
def escalate(self):
incident_obj = self.env['itmangement.incident']
record = incident_obj.browse(self._context.get('active_ids'))
record.write({'state': 'escalated'})
class Escalate(models.TransientModel):
escalated_to = fields.Many2one('hr.employee', string="Escalated To", required=True)
#api.one
def escalate(self):
object_id = self.env.context.get('active_id')
for object in self.env['itmangement.incident'].browse(object_id) and self.escalated_to:
object.assigned_to_id = self.escalated_to.id
I need help to set default value of purchase_ok field at product_template class in purchase module
thanks
You can simply set the default attribute like this:
class ProductTemplate(models.Model):
_inherit = 'product.template'
purchase_ok = fields.Boolean(
string='Selectable on purchase operations',
default=True,
)
Or you can use a lambda function like this:
class ProductTemplate(models.Model):
_inherit = 'product.template'
purchase_ok = fields.Boolean(
string='Selectable on purchase operations',
default=lambda self: self._get_default_purchase_ok(),
)
#api.model
def _get_default_purchase_ok(self):
value = True
# some operations
return value
Is there a way to access child model class object from parent model class object or now what child model class does this parent model class object has?
Here are my model classes:
class Content(models.Model):
_name = 'content'
title = fields.Char(string='Title', required=False)
summary = fields.Char(string='Summary', required=False)
description = fields.Char(string='Description', required=False)
class Video(models.Model):
_name = 'video'
_inherits = {'content': 'content_id'}
duration = fields.Float(string='Duration', required=False)
class Image(models.Model):
_name = 'image'
_inherits = {'content': 'content_id'}
width = fields.Float(string='Width', required=False)
height = fields.Float(string='Height', required=False)
If I have an object of "Content" class say "content1" that has a child object "image1", is there a way to access that "image1" object from "content1" object or now that type of "content1" is "Image"?
Content can have many child classes in future so I don't want to query all the child classes.
In Odoo you can travel bi-direction but your models should have configured like that,
class Content(models.Model):
_name = 'content'
_rec_name='title'
title = fields.Char(string='Title', required=False)
summary = fields.Char(string='Summary', required=False)
description = fields.Char(string='Description', required=False)
video_ids : fields.One2many('video','content_id','Video')
image_ids : fields.One2many('image','content_id','Video')
class Video(models.Model):
_name = 'video'
_inherit = 'content'
duration = fields.Float(string='Duration', required=False)
content_id = fields.Many2one('content','Content')
class Image(models.Model):
_name = 'image'
_inherit = 'content'
width = fields.Float(string='Width', required=False)
height = fields.Float(string='Height', required=False)
content_id = fields.Many2one('content','Content')
And you can access functionality of child classes by calling in this way.
for video in content1.video_ids:
## you can access properties of child classes like... video.duration
for image in content1.image_ids:
print image.width
Similarly you can call the method of child classes the same way.
If your aim is to do something else then specify it with example.