Advertisement
Guest User

Untitled

a guest
Aug 3rd, 2016
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.81 KB | None | 0 0
  1. +def better_reference(field_name, field_string, selection=None, set_index=True):
  2. + class ReferenceMixin(ModelSQL):
  3. + '''
  4. + This mixin adds a new reference function field with the
  5. + "field_name" parameter as field name and "field_string" as string.
  6. + It uses "selection" as the selection method. If not set, it will
  7. + accept all models.
  8. + If "set_index" is True, an index on the id part will be created.
  9. + This index should be enough for most cases since filtering only on
  10. + the model part is not a standard use case, and there should not be
  11. + enough differente models to justify a composite index.
  12. +
  13. + It also create two "real fields" :
  14. +
  15. + - A char field to hold the model data
  16. + - An int field to store the target id
  17. +
  18. + This field has a getter / setter / searcher and should be usable
  19. + the same way standard reference fields are, except the database
  20. + model will be far easier to query.
  21. + '''
  22. + @classmethod
  23. + def setter_void(cls, *args, **kwargs):
  24. + pass
  25. +
  26. + if selection is None:
  27. + @classmethod
  28. + def get_models(cls):
  29. + return Pool().get('ir.property').models_get()
  30. +
  31. + setattr(ReferenceMixin, '_reference_mixin_get_all_models', get_models)
  32. + selection = '_reference_mixin_get_all_models'
  33. +
  34. + real_field = fields.Function(
  35. + fields.Reference(field_string, selection),
  36. + 'getter_%s' % field_name, 'setter_void',
  37. + 'searcher_%s' % field_name)
  38. + model_field = fields.Char(field_string + ' Model')
  39. + id_field = fields.Integer(field_string + ' Id', select=set_index)
  40. +
  41. + model_part = '%s_model' % field_name
  42. + id_part = '%s_id' % field_name
  43. +
  44. + def getter(self, name):
  45. + model = getattr(self, model_part, None)
  46. + if model is None:
  47. + return None
  48. + return '%s,%i' % (getattr(self, model_part), getattr(self, id_part))
  49. +
  50. + @classmethod
  51. + def searcher(cls, name, clause):
  52. + name, operator, value = clause[:3]
  53. + Operator = fields.SQL_OPERATORS[operator]
  54. + if '.' not in name:
  55. + # Simple char field. We could just generate the query by
  56. + # concatening model and id part, but this would not use any indexes
  57. + # so be less optimized
  58. + if clause[1:3] in (('=', ''), ('=', None)):
  59. + return (id_part, '=', None)
  60. + if clause[1:3] in (('!=', ''), ('!=', None)):
  61. + return (id_part, '!=', None)
  62. + if operator in ('like', 'ilike', 'not like', 'not ilike'):
  63. + table = cls.__table__()
  64. + return ('id', 'in', table.select(table.id,
  65. + where=Operator(Concat(
  66. + Concat(Column(table, model_part), ','),
  67. + Cast(Column(table, id_part), 'VARCHAR')),
  68. + value)))
  69. + if operator == '=':
  70. + operator = 'in'
  71. + if operator == '!=':
  72. + operator = 'not in'
  73. + if not isinstance(value, (list, tuple)):
  74. + value = [value]
  75. + if operator == 'in':
  76. + return ['OR'] + [[
  77. + (model_part, '=', x.split(',')[0]),
  78. + (id_part, '=', int(x.split(',')[1]))]
  79. + for x in value]
  80. + if operator == 'not in':
  81. + return [['OR',
  82. + (model_part, '!=', x.split(',')[0]),
  83. + (id_part, '!=', int(x.split(',')[1]))]
  84. + for x in value]
  85. + raise NotImplementedError
  86. +
  87. + # Actually easier, we just forward the query to the target model, then
  88. + # filter out the ids, see field/reference.py -> convert_domain
  89. + target = clause[3]
  90. + Target = Pool().get(target)
  91. + name, target_name = name.split('.', 1)
  92. + target_domain = [(target_name,) + tuple(clause[1:3]) +
  93. + tuple(clause[4:])]
  94. + if 'active' in Target._fields:
  95. + target_domain.append(('active', 'in', [True, False]))
  96. + query = Target.search(target_domain, order=[], query=True)
  97. + return [(model_part, '=', target), (id_part, 'in', query)]
  98. +
  99. + @classmethod
  100. + def create(cls, vlist):
  101. + for data in vlist:
  102. + if field_name in data:
  103. + value = data.pop(field_name)
  104. + if value in (None, ''):
  105. + data[model_part] = None
  106. + data[id_part] = None
  107. + continue
  108. + model, id = value.split(',')
  109. + data[model_part] = model
  110. + data[id_part] = int(id)
  111. + return super(ReferenceMixin, cls).create(vlist)
  112. +
  113. + @classmethod
  114. + def write(cls, *args):
  115. + actions = iter(args)
  116. + for _, data in zip(actions, actions):
  117. + if field_name in data:
  118. + value = data.pop(field_name)
  119. + if value in (None, ''):
  120. + data[model_part] = None
  121. + data[id_part] = None
  122. + continue
  123. + model, id = value.split(',')
  124. + data[model_part] = model
  125. + data[id_part] = int(id)
  126. + return super(ReferenceMixin, cls).write(*args)
  127. +
  128. + setattr(ReferenceMixin, field_name, real_field)
  129. + setattr(ReferenceMixin, model_part, model_field)
  130. + setattr(ReferenceMixin, id_part, id_field)
  131. + setattr(ReferenceMixin, 'getter_%s' % field_name, getter)
  132. + setattr(ReferenceMixin, 'searcher_%s' % field_name, searcher)
  133. + setattr(ReferenceMixin, 'create', create)
  134. + setattr(ReferenceMixin, 'write', write)
  135. +
  136. + return ReferenceMixin
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement