ODOO入门 | 源码 | name_search

name_search


简介

用于通过在网页界面的输入框输入的文字,进行记录匹配并范围匹配的数据记录集((id1,name1),(id2,name2))结构的结果集。

源码

@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
    """ name_search(name='', args=None, operator='ilike', limit=100) -> records

    Search for records that have a display name matching the given
    ``name`` pattern when compared with the given ``operator``, while also
    matching the optional search domain (``args``).

    This is used for example to provide suggestions based on a partial
    value for a relational field. Sometimes be seen as the inverse
    function of :meth:`~.name_get`, but it is not guaranteed to be.

    This method is equivalent to calling :meth:`~.search` with a search
    domain based on ``display_name`` and then :meth:`~.name_get` on the
    result of the search.

    :param str name: the name pattern to match
    :param list args: optional search domain (see :meth:`~.search` for
                      syntax), specifying further restrictions
    :param str operator: domain operator for matching ``name``, such as
                         ``'like'`` or ``'='``.
    :param int limit: optional max number of records to return
    :rtype: list
    :return: list of pairs ``(id, text_repr)`` for all matching records.
    """
    return self._name_search(name, args, operator, limit=limit)

@api.model
def _name_search(self,name='', args=None, operator='ilike', limit=100, name_get_uid=None):
    # private implementation of name_search, allows passing a dedicated user
    # for the name_get part to solve some access rights issues
    args = list(args or [])
    # optimize out the default criterion of ``ilike ''`` that matches everything
    if not self._rec_name:
        _logger.warning("Cannot execute name_search, no _rec_name defined on %s", self._name)
    elif not (name == '' and operator == 'ilike'):
        args += [(self._rec_name, operator, name)]
    access_rights_uid = name_get_uid or self._uid
    ids = self._search(args, limit=limit, access_rights_uid=access_rights_uid)
    recs = self.browse(ids)
    return lazy_name_get(recs.sudo(access_rights_uid))

@api.model
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
    """
    Private implementation of search() method, allowing specifying the uid to use for the access right check.
    This is useful for example when filling in the selection list for a drop-down and avoiding access rights errors,
    by specifying ``access_rights_uid=1`` to bypass access rights check, but not ir.rules!
    This is ok at the security level because this method is private and not callable through XML-RPC.

    :param access_rights_uid: optional user ID to use when checking access rights
                              (not for ir.rules, this is only for ir.model.access)
    :return: a list of record ids or an integer (if count is True)
    """
    self.sudo(access_rights_uid or self._uid).check_access_rights('read')

    if expression.is_false(self, args):
        # optimization: no need to query, as no record satisfies the domain
        return 0 if count else []

    query = self._where_calc(args)
    self._apply_ir_rules(query, 'read')
    order_by = self._generate_order_by(order, query)
    from_clause, where_clause, where_clause_params = query.get_sql()

    where_str = where_clause and (" WHERE %s" % where_clause) or ''

    if count:
        # Ignore order, limit and offset when just counting, they don't make sense and could
        # hurt performance
        query_str = 'SELECT count(1) FROM ' + from_clause + where_str
        self._cr.execute(query_str, where_clause_params)
        res = self._cr.fetchone()
        return res[0]

    limit_str = limit and ' limit %d' % limit or ''
    offset_str = offset and ' offset %d' % offset or ''
    query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + order_by + limit_str + offset_str
    self._cr.execute(query_str, where_clause_params)
    res = self._cr.fetchall()

    # TDE note: with auto_join, we could have several lines about the same result
    # i.e. a lead with several unread messages; we uniquify the result using
    # a fast way to do it while preserving order (http://www.peterbe.com/plog/uniqifiers-benchmark)
    def _uniquify_list(seq):
        seen = set()
        return [x for x in seq if x not in seen and not seen.add(x)]

    return _uniquify_list([x[0] for x in res])
    
def browse(self, arg=None, prefetch=None):
    """ browse([ids]) -> records

    Returns a recordset for the ids provided as parameter in the current
    environment.

    Can take no ids, a single id or a sequence of ids.
    """
    ids = _normalize_ids(arg)
    #assert all(isinstance(id, IdType) for id in ids), "Browsing invalid ids: %s" % ids
    return self._browse(ids, self.env, prefetch)
    
@classmethod
def _browse(cls, ids, env, prefetch=None, add_prefetch=True):
    """ Create a recordset instance.

    :param ids: a tuple of record ids
    :param env: an environment
    :param prefetch: an optional prefetch object
    """
    records = object.__new__(cls)
    records.env = env
    records._ids = ids
    if prefetch is None:
        prefetch = defaultdict(set)         # {model_name: set(ids)}
    records._prefetch = prefetch
    if add_prefetch:
        prefetch[cls._name].update(ids)
    return records
    
def lazy_name_get(self):
    """ Evaluate self.name_get() lazily. """
    # names
    names = tools.lazy(lambda: dict(self.name_get()))
    return [(rid, tools.lazy(operator.getitem, names, rid)) for rid in self.ids]

分析

  1. 首先被搜索的模型必须有name字段或者维护_rec_name属性。
  2. name_search 方法调用_name_search 方法,
  3. 在_name_search方法中传入name到args(domain)中。
  4. _name_search调用_search方法传入 args(domain),limit(默认80条),access_rights_uid(uid) ,首先进行Read单据记录权限校验,校验通过后通过各种SQL转换拼接进行有效记录查询,返回记录的ids。
  5. 接着通过browser搜索上面的ids获取到记录集。
  6. lazy_name_get简单理解为直接执行了一个 self.name_get()方法就好了。
  7. 所以可以看出 name_search最后的返回结果,其实是name_get()的返回值
    def name_search(*args,**kwargs):
    	...
    	return name_get(*args, **kwargs)
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

比特本特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值