@@ -16,29 +16,18 @@ class M2xCreateEditOption(models.Model):
1616 domain = [("ttype" , "in" , ("many2many" , "many2one" ))],
1717 ondelete = "cascade" ,
1818 required = True ,
19- string = "Field" ,
2019 )
21-
22- field_name = fields .Char (
23- related = "field_id.name" ,
24- store = True ,
25- string = "Field Name" ,
26- )
27-
20+ field_name = fields .Char (related = "field_id.name" , store = True )
2821 model_id = fields .Many2one (
2922 "ir.model" ,
3023 ondelete = "cascade" ,
3124 required = True ,
32- string = "Model" ,
3325 )
34-
3526 model_name = fields .Char (
3627 compute = "_compute_model_name" ,
3728 inverse = "_inverse_model_name" ,
3829 store = True ,
39- string = "Model Name" ,
4030 )
41-
4231 option_create = fields .Selection (
4332 [
4433 ("none" , "Do nothing" ),
@@ -57,7 +46,6 @@ class M2xCreateEditOption(models.Model):
5746 required = True ,
5847 string = "Create Option" ,
5948 )
60-
6149 option_create_edit = fields .Selection (
6250 [
6351 ("none" , "Do nothing" ),
@@ -77,13 +65,6 @@ class M2xCreateEditOption(models.Model):
7765 string = "Create & Edit Option" ,
7866 )
7967
80- option_create_edit_wizard = fields .Boolean (
81- default = True ,
82- help = "Defines behaviour for 'Create & Edit' Wizard\n "
83- "Set to False to prevent 'Create & Edit' Wizard to pop up" ,
84- string = "Create & Edit Wizard" ,
85- )
86-
8768 _sql_constraints = [
8869 (
8970 "model_field_uniqueness" ,
@@ -94,87 +75,107 @@ class M2xCreateEditOption(models.Model):
9475
9576 @api .model_create_multi
9677 def create (self , vals_list ):
97- # Clear cache to avoid misbehavior from cached :meth:`_get()`
98- type (self )._get .clear_cache (self .browse ())
78+ self ._clear_caches ()
9979 return super ().create (vals_list )
10080
10181 def write (self , vals ):
102- # Clear cache to avoid misbehavior from cached :meth:`_get()`
103- type (self )._get .clear_cache (self .browse ())
82+ self ._clear_caches ()
10483 return super ().write (vals )
10584
10685 def unlink (self ):
107- # Clear cache to avoid misbehavior from cached :meth:`_get()`
108- type (self )._get .clear_cache (self .browse ())
86+ self ._clear_caches ()
10987 return super ().unlink ()
11088
89+ def _clear_caches (self , * cache_names ):
90+ """Clear registry caches
91+
92+ By default, clears caches to avoid misbehavior from cached methods:
93+ - ``m2x.create.edit.option._get()``
94+ - ``ir.ui.view._get_view_cache()``
95+ """
96+ self .env .registry .clear_cache (* self ._clear_caches_get_names (* cache_names ))
97+
98+ def _clear_caches_get_names (self , * cache_names ) -> list [str ]:
99+ """Retrieves registry caches names for clearance
100+
101+ By default, we want to clear caches:
102+ - "default": where ``m2x.create.edit.option._get()`` results get stored
103+ - "templates": where ``ir.ui.view._get_view_cache()`` results get stored
104+ """
105+ return list (cache_names ) + ["default" , "templates" ]
106+
111107 @api .depends ("model_id" )
112108 def _compute_model_name (self ):
113109 for opt in self :
114110 opt .model_name = opt .model_id .model
115111
116112 def _inverse_model_name (self ):
117113 getter = self .env ["ir.model" ]._get
118- for opt in self :
119- # This also works as a constrain: if ``model_name`` is not a
120- # valid model name, then ``model_id`` will be emptied, but it's
121- # a required field!
122- opt .model_id = getter (opt .model_name )
114+ for model_name , opts in self .grouped ("model_name" ).items ():
115+ if model := getter (model_name ):
116+ opts .model_id = model
117+ else :
118+ raise ValidationError (
119+ _ ("Invalid model name: '%(model_name)s'" , model_name = model_name )
120+ )
123121
124122 @api .constrains ("model_id" , "field_id" )
125123 def _check_field_in_model (self ):
126124 for opt in self :
127125 if opt .field_id .model_id != opt .model_id :
128- msg = _ ("'%s' is not a valid field for model '%s'!" )
129- raise ValidationError (msg % (opt .field_name , opt .model_name ))
126+ raise ValidationError (
127+ _ (
128+ "'%(fname)s' is not a valid field for model '%(mname)s'!" ,
129+ fname = opt .field_name ,
130+ mname = opt .model_name ,
131+ )
132+ )
130133
131134 @api .constrains ("field_id" )
132135 def _check_field_type (self ):
133- ttypes = ("many2many" , "many2one" )
134- if any ( o . field_id . ttype not in ttypes for o in self ):
135- msg = _ ("Only Many2many and Many2one fields can be chosen!" )
136- raise ValidationError ( msg )
136+ if any ( f . ttype not in ("many2many" , "many2one" ) for f in self . field_id ):
137+ raise ValidationError (
138+ _ ("Only Many2many and Many2one fields can be chosen!" )
139+ )
137140
138141 def _apply_options (self , node ):
139- """Applies options ``self`` to ``node``"""
142+ """Applies option ``self`` to ``node``"""
140143 self .ensure_one ()
141144 options = node .attrib .get ("options" ) or {}
142145 if isinstance (options , str ):
143146 options = safe_eval (options , dict (self .env .context or [])) or {}
144- for k in ("create" , "create_edit" ):
145- opt = self ["option_%s" % k ]
146- if opt == "none" :
147- continue
148- mode , val = opt .split ("_" )
149- if mode == "force" or k not in options :
150- options [k ] = val == "true"
147+ for key in ("create" , "create_edit" ):
148+ if (opt := self [f"option_{ key } " ]) != "none" :
149+ mode , val = opt .split ("_" )
150+ if mode == "force" or key not in options :
151+ options [key ] = val == "true"
151152 node .set ("options" , str (options ))
152- if not self .option_create_edit_wizard :
153- node .set ("can_create" , "false" )
154- node .set ("can_write" , "true" )
155153
156154 @api .model
157155 def get (self , model_name , field_name ):
158156 """Returns specific record for ``field_name`` in ``model_name``
159157
160158 :param str model_name: technical model name (i.e. "sale.order")
161159 :param str field_name: technical field name (i.e. "partner_id")
160+ :returns: the ``m2x.create.edit.option`` record for the given model/field couple
161+ :rtype: M2xCreateEditOption
162162 """
163163 return self .browse (self ._get (model_name , field_name ))
164164
165165 @api .model
166- @ormcache ("model_name" , "field_name" )
166+ @ormcache ("model_name" , "field_name" , cache = "default" )
167167 def _get (self , model_name , field_name ):
168168 """Inner implementation of ``get``.
169- An ID is returned to allow caching (see :class:`ormcache`); :meth:`get`
169+
170+ An ID is returned to allow caching (see :class:``ormcache``); :meth:``get``
170171 will then convert it to a proper record.
171172
172173 :param str model_name: technical model name (i.e. "sale.order")
173174 :param str field_name: technical field name (i.e. "partner_id")
175+ :returns: the ``m2x.create.edit.option`` ID for the given model/field couple,
176+ or None if there's no match
177+ :rtype: int|None
174178 """
175- dom = [
176- ("model_name" , "=" , model_name ),
177- ("field_name" , "=" , field_name ),
178- ]
179- # `_check_field_model_uniqueness()` grants uniqueness if existing
180- return self .search (dom , limit = 1 ).id
179+ dom = [("model_name" , "=" , model_name ), ("field_name" , "=" , field_name )]
180+ # ``_check_field_model_uniqueness()`` grants uniqueness if existing
181+ return self .search (dom , limit = 1 ).id or None
0 commit comments