entity.py
changeset 4835 13b0b96d7982
parent 4831 c5aec27c1bf7
child 4848 41f84eea63c9
equal deleted inserted replaced
4834:b718626a0e60 4835:13b0b96d7982
    18 
    18 
    19 from cubicweb import Unauthorized, typed_eid
    19 from cubicweb import Unauthorized, typed_eid
    20 from cubicweb.rset import ResultSet
    20 from cubicweb.rset import ResultSet
    21 from cubicweb.selectors import yes
    21 from cubicweb.selectors import yes
    22 from cubicweb.appobject import AppObject
    22 from cubicweb.appobject import AppObject
       
    23 from cubicweb.req import _check_cw_unsafe
    23 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint
    24 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint
    24 from cubicweb.rqlrewrite import RQLRewriter
    25 from cubicweb.rqlrewrite import RQLRewriter
    25 
    26 
    26 from cubicweb.uilib import printable_value, soup2xhtml
    27 from cubicweb.uilib import printable_value, soup2xhtml
    27 from cubicweb.mixins import MI_REL_TRIGGERS
    28 from cubicweb.mixins import MI_REL_TRIGGERS
   529         if selected:
   530         if selected:
   530             # select V, we need it as the left most selected variable
   531             # select V, we need it as the left most selected variable
   531             # if some outer join are included to fetch inlined relations
   532             # if some outer join are included to fetch inlined relations
   532             rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected),
   533             rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected),
   533                                     ','.join(rql))
   534                                     ','.join(rql))
   534             execute = getattr(self._cw, 'unsafe_execute', self._cw.execute)
   535             rset = self._cw.execute(rql, {'x': self.eid}, 'x',
   535             rset = execute(rql, {'x': self.eid}, 'x', build_descr=False)[0]
   536                                     build_descr=False)[0]
   536             # handle attributes
   537             # handle attributes
   537             for i in xrange(1, lastattr):
   538             for i in xrange(1, lastattr):
   538                 self[str(selected[i-1][0])] = rset[i]
   539                 self[str(selected[i-1][0])] = rset[i]
   539             # handle relations
   540             # handle relations
   540             for i in xrange(lastattr, len(rset)):
   541             for i in xrange(lastattr, len(rset)):
   558             value = self[name]
   559             value = self[name]
   559         except KeyError:
   560         except KeyError:
   560             if not self.is_saved():
   561             if not self.is_saved():
   561                 return None
   562                 return None
   562             rql = "Any A WHERE X eid %%(x)s, X %s A" % name
   563             rql = "Any A WHERE X eid %%(x)s, X %s A" % name
   563             # XXX should we really use unsafe_execute here? I think so (syt),
       
   564             # see #344874
       
   565             execute = getattr(self._cw, 'unsafe_execute', self._cw.execute)
       
   566             try:
   564             try:
   567                 rset = execute(rql, {'x': self.eid}, 'x')
   565                 rset = self._cw.execute(rql, {'x': self.eid}, 'x')
   568             except Unauthorized:
   566             except Unauthorized:
   569                 self[name] = value = None
   567                 self[name] = value = None
   570             else:
   568             else:
   571                 assert rset.rowcount <= 1, (self, rql, rset.rowcount)
   569                 assert rset.rowcount <= 1, (self, rql, rset.rowcount)
   572                 try:
   570                 try:
   593             return self.related_cache(rtype, role, entities, limit)
   591             return self.related_cache(rtype, role, entities, limit)
   594         except KeyError:
   592         except KeyError:
   595             pass
   593             pass
   596         assert self.has_eid()
   594         assert self.has_eid()
   597         rql = self.related_rql(rtype, role)
   595         rql = self.related_rql(rtype, role)
   598         # XXX should we really use unsafe_execute here? I think so (syt),
   596         rset = self._cw.execute(rql, {'x': self.eid}, 'x')
   599         # see #344874
       
   600         execute = getattr(self._cw, 'unsafe_execute', self._cw.execute)
       
   601         rset = execute(rql, {'x': self.eid}, 'x')
       
   602         self.set_related_cache(rtype, role, rset)
   597         self.set_related_cache(rtype, role, rset)
   603         return self.related(rtype, role, limit, entities)
   598         return self.related(rtype, role, limit, entities)
   604 
   599 
   605     def related_rql(self, rtype, role='subject', targettypes=None):
   600     def related_rql(self, rtype, role='subject', targettypes=None):
   606         rschema = self._cw.vreg.schema[rtype]
   601         rschema = self._cw.vreg.schema[rtype]
   798         except AttributeError:
   793         except AttributeError:
   799             pass
   794             pass
   800 
   795 
   801     # raw edition utilities ###################################################
   796     # raw edition utilities ###################################################
   802 
   797 
   803     def set_attributes(self, _cw_unsafe=False, **kwargs):
   798     def set_attributes(self, **kwargs):
   804         assert kwargs
   799         assert kwargs
       
   800         _check_cw_unsafe(kwargs)
   805         relations = []
   801         relations = []
   806         for key in kwargs:
   802         for key in kwargs:
   807             relations.append('X %s %%(%s)s' % (key, key))
   803             relations.append('X %s %%(%s)s' % (key, key))
   808         # update current local object
   804         # update current local object
   809         self.update(kwargs)
   805         self.update(kwargs)
   810         # and now update the database
   806         # and now update the database
   811         kwargs['x'] = self.eid
   807         kwargs['x'] = self.eid
   812         if _cw_unsafe:
   808         self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations),
   813             self._cw.unsafe_execute(
   809                          kwargs, 'x')
   814                 'SET %s WHERE X eid %%(x)s' % ','.join(relations), kwargs, 'x')
   810 
   815         else:
   811     def set_relations(self, **kwargs):
   816             self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations),
       
   817                              kwargs, 'x')
       
   818 
       
   819     def set_relations(self, _cw_unsafe=False, **kwargs):
       
   820         """add relations to the given object. To set a relation where this entity
   812         """add relations to the given object. To set a relation where this entity
   821         is the object of the relation, use 'reverse_'<relation> as argument name.
   813         is the object of the relation, use 'reverse_'<relation> as argument name.
   822 
   814 
   823         Values may be an entity, a list of entity, or None (meaning that all
   815         Values may be an entity, a list of entity, or None (meaning that all
   824         relations of the given type from or to this object should be deleted).
   816         relations of the given type from or to this object should be deleted).
   825         """
   817         """
   826         if _cw_unsafe:
       
   827             execute = self._cw.unsafe_execute
       
   828         else:
       
   829             execute = self._cw.execute
       
   830         # XXX update cache
   818         # XXX update cache
       
   819         _check_cw_unsafe(kwargs)
   831         for attr, values in kwargs.iteritems():
   820         for attr, values in kwargs.iteritems():
   832             if attr.startswith('reverse_'):
   821             if attr.startswith('reverse_'):
   833                 restr = 'Y %s X' % attr[len('reverse_'):]
   822                 restr = 'Y %s X' % attr[len('reverse_'):]
   834             else:
   823             else:
   835                 restr = 'X %s Y' % attr
   824                 restr = 'X %s Y' % attr
   837                 execute('DELETE %s WHERE X eid %%(x)s' % restr,
   826                 execute('DELETE %s WHERE X eid %%(x)s' % restr,
   838                         {'x': self.eid}, 'x')
   827                         {'x': self.eid}, 'x')
   839                 continue
   828                 continue
   840             if not isinstance(values, (tuple, list, set, frozenset)):
   829             if not isinstance(values, (tuple, list, set, frozenset)):
   841                 values = (values,)
   830                 values = (values,)
   842             execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % (
   831             self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % (
   843                 restr, ','.join(str(r.eid) for r in values)),
   832                 restr, ','.join(str(r.eid) for r in values)),
   844                     {'x': self.eid}, 'x')
   833                              {'x': self.eid}, 'x')
   845 
   834 
   846     def delete(self):
   835     def delete(self, **kwargs):
   847         assert self.has_eid(), self.eid
   836         assert self.has_eid(), self.eid
   848         self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema,
   837         self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema,
   849                          {'x': self.eid})
   838                          {'x': self.eid}, **kwargs)
   850 
   839 
   851     # server side utilities ###################################################
   840     # server side utilities ###################################################
   852 
   841 
   853     def set_defaults(self):
   842     def set_defaults(self):
   854         """set default values according to the schema"""
   843         """set default values according to the schema"""