thirdparty/google_appengine/google/appengine/ext/db/__init__.py
changeset 2309 be1b94099f2d
parent 1278 a7766286a7be
child 2413 d0b7dac5325c
equal deleted inserted replaced
2307:81c128f487e6 2309:be1b94099f2d
   267         raise DuplicatePropertyError('Duplicate property: %s' % attr_name)
   267         raise DuplicatePropertyError('Duplicate property: %s' % attr_name)
   268       defined.add(attr_name)
   268       defined.add(attr_name)
   269       model_class._properties[attr_name] = attr
   269       model_class._properties[attr_name] = attr
   270       attr.__property_config__(model_class, attr_name)
   270       attr.__property_config__(model_class, attr_name)
   271 
   271 
       
   272   model_class._unindexed_properties = frozenset(
       
   273     name for name, prop in model_class._properties.items() if not prop.indexed)
       
   274 
   272 
   275 
   273 class PropertiedClass(type):
   276 class PropertiedClass(type):
   274   """Meta-class for initializing Model classes properties.
   277   """Meta-class for initializing Model classes properties.
   275 
   278 
   276   Used for initializing Properties defined in the context of a model.
   279   Used for initializing Properties defined in the context of a model.
   334        title = db.StringProperty()
   337        title = db.StringProperty()
   335   """
   338   """
   336 
   339 
   337   creation_counter = 0
   340   creation_counter = 0
   338 
   341 
   339   def __init__(self, verbose_name=None, name=None, default=None,
   342   def __init__(self,
   340                required=False, validator=None, choices=None):
   343                verbose_name=None,
       
   344                name=None,
       
   345                default=None,
       
   346                required=False,
       
   347                validator=None,
       
   348                choices=None,
       
   349                indexed=True):
   341     """Initializes this Property with the given options.
   350     """Initializes this Property with the given options.
   342 
   351 
   343     Args:
   352     Args:
   344       verbose_name: User friendly name of property.
   353       verbose_name: User friendly name of property.
   345       name: Storage name for property.  By default, uses attribute name
   354       name: Storage name for property.  By default, uses attribute name
   346         as it is assigned in the Model sub-class.
   355         as it is assigned in the Model sub-class.
   347       default: Default value for property if none is assigned.
   356       default: Default value for property if none is assigned.
   348       required: Whether property is required.
   357       required: Whether property is required.
   349       validator: User provided method used for validation.
   358       validator: User provided method used for validation.
   350       choices: User provided set of valid property values.
   359       choices: User provided set of valid property values.
       
   360       indexed: Whether property is indexed.
   351     """
   361     """
   352     self.verbose_name = verbose_name
   362     self.verbose_name = verbose_name
   353     self.name = name
   363     self.name = name
   354     self.default = default
   364     self.default = default
   355     self.required = required
   365     self.required = required
   356     self.validator = validator
   366     self.validator = validator
   357     self.choices = choices
   367     self.choices = choices
       
   368     self.indexed = indexed
   358     self.creation_counter = Property.creation_counter
   369     self.creation_counter = Property.creation_counter
   359     Property.creation_counter += 1
   370     Property.creation_counter += 1
   360 
   371 
   361   def __property_config__(self, model_class, property_name):
   372   def __property_config__(self, model_class, property_name):
   362     """Configure property, connecting it to its model.
   373     """Configure property, connecting it to its model.
   486 
   497 
   487     Returns:
   498     Returns:
   488       The value converted for use as a model instance attribute.
   499       The value converted for use as a model instance attribute.
   489     """
   500     """
   490     return value
   501     return value
       
   502 
       
   503   def _require_parameter(self, kwds, parameter, value):
       
   504     """Sets kwds[parameter] to value.
       
   505 
       
   506     If kwds[parameter] exists and is not value, raises ConfigurationError.
       
   507 
       
   508     Args:
       
   509       kwds: The parameter dict, which maps parameter names (strings) to values.
       
   510       parameter: The name of the parameter to set.
       
   511       value: The value to set it to.
       
   512     """
       
   513     if parameter in kwds and kwds[parameter] != value:
       
   514       raise ConfigurationError('%s must be %s.' % (parameter, value))
       
   515 
       
   516     kwds[parameter] = value
   491 
   517 
   492   def _attr_name(self):
   518   def _attr_name(self):
   493     """Attribute name we use for this property in model instances.
   519     """Attribute name we use for this property in model instances.
   494 
   520 
   495     DO NOT USE THIS METHOD.
   521     DO NOT USE THIS METHOD.
   683       self._entity or a new Entity which is not stored on the instance.
   709       self._entity or a new Entity which is not stored on the instance.
   684     """
   710     """
   685     if self.is_saved():
   711     if self.is_saved():
   686       entity = self._entity
   712       entity = self._entity
   687     else:
   713     else:
       
   714       kwds = {'_app': self._app,
       
   715               'name': self._key_name,
       
   716               'unindexed_properties': self._unindexed_properties}
       
   717 
   688       if self._parent_key is not None:
   718       if self._parent_key is not None:
   689         entity = _entity_class(self.kind(),
   719         kwds['parent'] = self._parent_key
   690                                parent=self._parent_key,
       
   691                                name=self._key_name,
       
   692                                _app=self._app)
       
   693       elif self._parent is not None:
   720       elif self._parent is not None:
   694         entity = _entity_class(self.kind(),
   721         kwds['parent'] = self._parent._entity
   695                                parent=self._parent._entity,
   722       entity = _entity_class(self.kind(), **kwds)
   696                                name=self._key_name,
       
   697                                _app=self._app)
       
   698       else:
       
   699         entity = _entity_class(self.kind(),
       
   700                                name=self._key_name,
       
   701                                _app=self._app)
       
   702 
   723 
   703     self._to_entity(entity)
   724     self._to_entity(entity)
   704     return entity
   725     return entity
   705 
   726 
   706   def delete(self):
   727   def delete(self):
   930         entity.put()
   951         entity.put()
   931       return entity
   952       return entity
   932     return run_in_transaction(txn)
   953     return run_in_transaction(txn)
   933 
   954 
   934   @classmethod
   955   @classmethod
   935   def all(cls):
   956   def all(cls, **kwds):
   936     """Returns a query over all instances of this model from the datastore.
   957     """Returns a query over all instances of this model from the datastore.
   937 
   958 
   938     Returns:
   959     Returns:
   939       Query that will retrieve all instances from entity collection.
   960       Query that will retrieve all instances from entity collection.
   940     """
   961     """
   941     return Query(cls)
   962     return Query(cls, **kwds)
   942 
   963 
   943   @classmethod
   964   @classmethod
   944   def gql(cls, query_string, *args, **kwds):
   965   def gql(cls, query_string, *args, **kwds):
   945     """Returns a query using GQL query string.
   966     """Returns a query using GQL query string.
   946 
   967 
  1298 
  1319 
  1299 
  1320 
  1300 class _BaseQuery(object):
  1321 class _BaseQuery(object):
  1301   """Base class for both Query and GqlQuery."""
  1322   """Base class for both Query and GqlQuery."""
  1302 
  1323 
  1303   def __init__(self, model_class):
  1324   def __init__(self, model_class, keys_only=False):
  1304     """Constructor."
  1325     """Constructor.
  1305 
  1326 
  1306       Args:
  1327     Args:
  1307         model_class: Model class from which entities are constructed.
  1328       model_class: Model class from which entities are constructed.
       
  1329       keys_only: Whether the query should return full entities or only keys.
  1308     """
  1330     """
  1309     self._model_class = model_class
  1331     self._model_class = model_class
       
  1332     self._keys_only = keys_only
       
  1333 
       
  1334   def is_keys_only(self):
       
  1335     """Returns whether this query is keys only.
       
  1336 
       
  1337     Returns:
       
  1338       True if this query returns keys, False if it returns entities.
       
  1339     """
       
  1340     return self._keys_only
  1310 
  1341 
  1311   def _get_query(self):
  1342   def _get_query(self):
  1312     """Subclass must override (and not call their super method).
  1343     """Subclass must override (and not call their super method).
  1313 
  1344 
  1314     Returns:
  1345     Returns:
  1323     or use a GQL query with a LIMIT clause. It's more efficient.
  1354     or use a GQL query with a LIMIT clause. It's more efficient.
  1324 
  1355 
  1325     Returns:
  1356     Returns:
  1326       Iterator for this query.
  1357       Iterator for this query.
  1327     """
  1358     """
  1328     return _QueryIterator(self._model_class, iter(self._get_query().Run()))
  1359     iterator = self._get_query().Run()
       
  1360     if self._keys_only:
       
  1361       return iterator
       
  1362     else:
       
  1363       return _QueryIterator(self._model_class, iter(iterator))
  1329 
  1364 
  1330   def __iter__(self):
  1365   def __iter__(self):
  1331     """Iterator for this query.
  1366     """Iterator for this query.
  1332 
  1367 
  1333     If you know the number of results you need, consider fetch() instead,
  1368     If you know the number of results you need, consider fetch() instead,
  1386     if limit < 0 or offset < 0:
  1421     if limit < 0 or offset < 0:
  1387       raise ValueError('Arguments to fetch() must be >= 0')
  1422       raise ValueError('Arguments to fetch() must be >= 0')
  1388     if limit == 0:
  1423     if limit == 0:
  1389       return []
  1424       return []
  1390     raw = self._get_query().Get(limit, offset)
  1425     raw = self._get_query().Get(limit, offset)
  1391     return map(self._model_class.from_entity, raw)
  1426 
       
  1427     if self._keys_only:
       
  1428       return raw
       
  1429     else:
       
  1430       return [self._model_class.from_entity(e) for e in raw]
  1392 
  1431 
  1393   def __getitem__(self, arg):
  1432   def __getitem__(self, arg):
  1394     """Support for query[index] and query[start:stop].
  1433     """Support for query[index] and query[start:stop].
  1395 
  1434 
  1396     Beware: this ignores the LIMIT clause on GQL queries.
  1435     Beware: this ignores the LIMIT clause on GQL queries.
  1527 
  1566 
  1528      for story in Query(story).filter('title =', 'Foo').order('-date'):
  1567      for story in Query(story).filter('title =', 'Foo').order('-date'):
  1529        print story.title
  1568        print story.title
  1530   """
  1569   """
  1531 
  1570 
  1532   def __init__(self, model_class):
  1571   def __init__(self, model_class, keys_only=False):
  1533     """Constructs a query over instances of the given Model.
  1572     """Constructs a query over instances of the given Model.
  1534 
  1573 
  1535     Args:
  1574     Args:
  1536       model_class: Model class to build query for.
  1575       model_class: Model class to build query for.
  1537     """
  1576       keys_only: Whether the query should return full entities or only keys.
  1538     super(Query, self).__init__(model_class)
  1577     """
       
  1578     super(Query, self).__init__(model_class, keys_only)
  1539     self.__query_sets = [{}]
  1579     self.__query_sets = [{}]
  1540     self.__orderings = []
  1580     self.__orderings = []
  1541     self.__ancestor = None
  1581     self.__ancestor = None
  1542 
  1582 
  1543   def _get_query(self,
  1583   def _get_query(self,
  1544                  _query_class=datastore.Query,
  1584                  _query_class=datastore.Query,
  1545                  _multi_query_class=datastore.MultiQuery):
  1585                  _multi_query_class=datastore.MultiQuery):
  1546     queries = []
  1586     queries = []
  1547     for query_set in self.__query_sets:
  1587     for query_set in self.__query_sets:
  1548       query = _query_class(self._model_class.kind(), query_set)
  1588       query = _query_class(self._model_class.kind(),
       
  1589                            query_set,
       
  1590                            keys_only=self._keys_only)
       
  1591       query.Order(*self.__orderings)
  1549       if self.__ancestor is not None:
  1592       if self.__ancestor is not None:
  1550         query.Ancestor(self.__ancestor)
  1593         query.Ancestor(self.__ancestor)
  1551       queries.append(query)
  1594       queries.append(query)
  1552 
  1595 
  1553     if (_query_class != datastore.Query and
  1596     if (_query_class != datastore.Query and
  1564           _multi_query_class != datastore.MultiQuery):
  1607           _multi_query_class != datastore.MultiQuery):
  1565       raise BadArgumentError('_query_class must also be overridden if'
  1608       raise BadArgumentError('_query_class must also be overridden if'
  1566                              ' _multi_query_class is overridden.')
  1609                              ' _multi_query_class is overridden.')
  1567 
  1610 
  1568     if len(queries) == 1:
  1611     if len(queries) == 1:
  1569       queries[0].Order(*self.__orderings)
       
  1570       return queries[0]
  1612       return queries[0]
  1571     else:
  1613     else:
  1572       return _multi_query_class(queries, self.__orderings)
  1614       return _multi_query_class(queries, self.__orderings)
  1573 
  1615 
  1574   def __filter_disjunction(self, operations, values):
  1616   def __filter_disjunction(self, operations, values):
  1609       property_operator: string with the property and operator to filter by.
  1651       property_operator: string with the property and operator to filter by.
  1610       value: the filter value.
  1652       value: the filter value.
  1611 
  1653 
  1612     Returns:
  1654     Returns:
  1613       Self to support method chaining.
  1655       Self to support method chaining.
       
  1656 
       
  1657     Raises:
       
  1658       PropertyError if invalid property is provided.
  1614     """
  1659     """
  1615     match = _FILTER_REGEX.match(property_operator)
  1660     match = _FILTER_REGEX.match(property_operator)
  1616     prop = match.group(1)
  1661     prop = match.group(1)
  1617     if match.group(3) is not None:
  1662     if match.group(3) is not None:
  1618       operator = match.group(3)
  1663       operator = match.group(3)
  1619     else:
  1664     else:
  1620       operator = '=='
  1665       operator = '=='
  1621 
  1666 
       
  1667     if prop in self._model_class._unindexed_properties:
       
  1668       raise PropertyError('Property \'%s\' is not indexed' % prop)
       
  1669 
  1622     if operator.lower() == 'in':
  1670     if operator.lower() == 'in':
  1623       if not isinstance(value, (list, tuple)):
  1671       if self._keys_only:
       
  1672         raise BadQueryError('Keys only queries do not support IN filters.')
       
  1673       elif not isinstance(value, (list, tuple)):
  1624         raise BadValueError('Argument to the "in" operator must be a list')
  1674         raise BadValueError('Argument to the "in" operator must be a list')
  1625       values = [_normalize_query_parameter(v) for v in value]
  1675       values = [_normalize_query_parameter(v) for v in value]
  1626       self.__filter_disjunction(prop + ' =', values)
  1676       self.__filter_disjunction(prop + ' =', values)
  1627     else:
  1677     else:
  1628       if isinstance(value, (list, tuple)):
  1678       if isinstance(value, (list, tuple)):
  1629         raise BadValueError('Filtering on lists is not supported')
  1679         raise BadValueError('Filtering on lists is not supported')
  1630       if operator == '!=':
  1680       if operator == '!=':
       
  1681         if self._keys_only:
       
  1682           raise BadQueryError('Keys only queries do not support != filters.')
  1631         self.__filter_disjunction([prop + ' <', prop + ' >'],
  1683         self.__filter_disjunction([prop + ' <', prop + ' >'],
  1632                                   _normalize_query_parameter(value))
  1684                                   _normalize_query_parameter(value))
  1633       else:
  1685       else:
  1634         value = _normalize_query_parameter(value)
  1686         value = _normalize_query_parameter(value)
  1635         for query_set in self.__query_sets:
  1687         for query_set in self.__query_sets:
  1648 
  1700 
  1649     Returns:
  1701     Returns:
  1650       Self to support method chaining.
  1702       Self to support method chaining.
  1651 
  1703 
  1652     Raises:
  1704     Raises:
  1653       PropertyError if invalid property name is provided.
  1705       PropertyError if invalid property is provided.
  1654     """
  1706     """
  1655     if property.startswith('-'):
  1707     if property.startswith('-'):
  1656       property = property[1:]
  1708       property = property[1:]
  1657       order = datastore.Query.DESCENDING
  1709       order = datastore.Query.DESCENDING
  1658     else:
  1710     else:
  1660 
  1712 
  1661     if not issubclass(self._model_class, Expando):
  1713     if not issubclass(self._model_class, Expando):
  1662       if (property not in self._model_class.properties() and
  1714       if (property not in self._model_class.properties() and
  1663           property not in datastore_types._SPECIAL_PROPERTIES):
  1715           property not in datastore_types._SPECIAL_PROPERTIES):
  1664         raise PropertyError('Invalid property name \'%s\'' % property)
  1716         raise PropertyError('Invalid property name \'%s\'' % property)
       
  1717 
       
  1718     if property in self._model_class._unindexed_properties:
       
  1719       raise PropertyError('Property \'%s\' is not indexed' % property)
  1665 
  1720 
  1666     self.__orderings.append((property, order))
  1721     self.__orderings.append((property, order))
  1667     return self
  1722     return self
  1668 
  1723 
  1669   def ancestor(self, ancestor):
  1724   def ancestor(self, ancestor):
  1707 
  1762 
  1708     Args:
  1763     Args:
  1709       query_string: Properly formatted GQL query string.
  1764       query_string: Properly formatted GQL query string.
  1710       *args: Positional arguments used to bind numeric references in the query.
  1765       *args: Positional arguments used to bind numeric references in the query.
  1711       **kwds: Dictionary-based arguments for named references.
  1766       **kwds: Dictionary-based arguments for named references.
       
  1767 
       
  1768     Raises:
       
  1769       PropertyError if the query filters or sorts on a property that's not
       
  1770       indexed.
  1712     """
  1771     """
  1713     from google.appengine.ext import gql
  1772     from google.appengine.ext import gql
  1714     app = kwds.pop('_app', None)
  1773     app = kwds.pop('_app', None)
       
  1774 
  1715     self._proto_query = gql.GQL(query_string, _app=app)
  1775     self._proto_query = gql.GQL(query_string, _app=app)
  1716     super(GqlQuery, self).__init__(class_for_kind(self._proto_query._entity))
  1776     model_class = class_for_kind(self._proto_query._entity)
       
  1777     super(GqlQuery, self).__init__(model_class,
       
  1778                                    keys_only=self._proto_query._keys_only)
       
  1779 
       
  1780     for property, unused in (self._proto_query.filters().keys() +
       
  1781                              self._proto_query.orderings()):
       
  1782       if property in model_class._unindexed_properties:
       
  1783         raise PropertyError('Property \'%s\' is not indexed' % property)
       
  1784 
  1717     self.bind(*args, **kwds)
  1785     self.bind(*args, **kwds)
  1718 
  1786 
  1719   def bind(self, *args, **kwds):
  1787   def bind(self, *args, **kwds):
  1720     """Bind arguments (positional or keyword) to the query.
  1788     """Bind arguments (positional or keyword) to the query.
  1721 
  1789 
  1738       self._kwds[name] = _normalize_query_parameter(arg)
  1806       self._kwds[name] = _normalize_query_parameter(arg)
  1739 
  1807 
  1740   def run(self):
  1808   def run(self):
  1741     """Override _BaseQuery.run() so the LIMIT clause is handled properly."""
  1809     """Override _BaseQuery.run() so the LIMIT clause is handled properly."""
  1742     query_run = self._proto_query.Run(*self._args, **self._kwds)
  1810     query_run = self._proto_query.Run(*self._args, **self._kwds)
  1743     return _QueryIterator(self._model_class, iter(query_run))
  1811     if self._keys_only:
       
  1812       return query_run
       
  1813     else:
       
  1814       return _QueryIterator(self._model_class, iter(query_run))
  1744 
  1815 
  1745   def _get_query(self):
  1816   def _get_query(self):
  1746     return self._proto_query.Bind(self._args, self._kwds)
  1817     return self._proto_query.Bind(self._args, self._kwds)
  1747 
  1818 
  1748 
  1819 
  1749 class TextProperty(Property):
  1820 class UnindexedProperty(Property):
  1750   """A string that can be longer than 500 bytes.
  1821   """A property that isn't indexed by either built-in or composite indices.
  1751 
  1822 
  1752   This type should be used for large text values to make sure the datastore
  1823   TextProperty and BlobProperty derive from this class.
  1753   has good performance for queries.
       
  1754   """
  1824   """
       
  1825   def __init__(self, *args, **kwds):
       
  1826     """Construct property. See the Property class for details.
       
  1827 
       
  1828     Raises:
       
  1829       ConfigurationError if indexed=True.
       
  1830     """
       
  1831     self._require_parameter(kwds, 'indexed', False)
       
  1832     kwds['indexed'] = True
       
  1833     super(UnindexedProperty, self).__init__(*args, **kwds)
  1755 
  1834 
  1756   def validate(self, value):
  1835   def validate(self, value):
  1757     """Validate text property.
  1836     """Validate property.
  1758 
  1837 
  1759     Returns:
  1838     Returns:
  1760       A valid value.
  1839       A valid value.
  1761 
  1840 
  1762     Raises:
  1841     Raises:
  1763       BadValueError if property is not instance of 'Text'.
  1842       BadValueError if property is not an instance of data_type.
  1764     """
  1843     """
  1765     if value is not None and not isinstance(value, Text):
  1844     if value is not None and not isinstance(value, self.data_type):
  1766       try:
  1845       try:
  1767         value = Text(value)
  1846         value = self.data_type(value)
  1768       except TypeError, err:
  1847       except TypeError, err:
  1769         raise BadValueError('Property %s must be convertible '
  1848         raise BadValueError('Property %s must be convertible '
  1770                             'to a Text instance (%s)' % (self.name, err))
  1849                             'to a %s instance (%s)' %
  1771     value = super(TextProperty, self).validate(value)
  1850                             (self.name, self.data_type.__name__, err))
  1772     if value is not None and not isinstance(value, Text):
  1851     value = super(UnindexedProperty, self).validate(value)
  1773       raise BadValueError('Property %s must be a Text instance' % self.name)
  1852     if value is not None and not isinstance(value, self.data_type):
       
  1853       raise BadValueError('Property %s must be a %s instance' %
       
  1854                           (self.name, self.data_type.__name__))
  1774     return value
  1855     return value
       
  1856 
       
  1857 
       
  1858 class TextProperty(UnindexedProperty):
       
  1859   """A string that can be longer than 500 bytes."""
  1775 
  1860 
  1776   data_type = Text
  1861   data_type = Text
  1777 
  1862 
  1778 
  1863 
  1779 class StringProperty(Property):
  1864 class StringProperty(Property):
  1884   """A property whose values are PostalAddress instances."""
  1969   """A property whose values are PostalAddress instances."""
  1885 
  1970 
  1886   data_type = PostalAddress
  1971   data_type = PostalAddress
  1887 
  1972 
  1888 
  1973 
  1889 class BlobProperty(Property):
  1974 class BlobProperty(UnindexedProperty):
  1890   """A string that can be longer than 500 bytes.
  1975   """A byte string that can be longer than 500 bytes."""
  1891 
       
  1892   This type should be used for large binary values to make sure the datastore
       
  1893   has good performance for queries.
       
  1894   """
       
  1895 
       
  1896   def validate(self, value):
       
  1897     """Validate blob property.
       
  1898 
       
  1899     Returns:
       
  1900       A valid value.
       
  1901 
       
  1902     Raises:
       
  1903       BadValueError if property is not instance of 'Blob'.
       
  1904     """
       
  1905     if value is not None and not isinstance(value, Blob):
       
  1906       try:
       
  1907         value = Blob(value)
       
  1908       except TypeError, err:
       
  1909         raise BadValueError('Property %s must be convertible '
       
  1910                             'to a Blob instance (%s)' % (self.name, err))
       
  1911     value = super(BlobProperty, self).validate(value)
       
  1912     if value is not None and not isinstance(value, Blob):
       
  1913       raise BadValueError('Property %s must be a Blob instance' % self.name)
       
  1914     return value
       
  1915 
  1976 
  1916   data_type = Blob
  1977   data_type = Blob
  1917 
  1978 
  1918 
  1979 
  1919 class ByteStringProperty(Property):
  1980 class ByteStringProperty(Property):
  2264 
  2325 
  2265 
  2326 
  2266 class UserProperty(Property):
  2327 class UserProperty(Property):
  2267   """A user property."""
  2328   """A user property."""
  2268 
  2329 
  2269   def __init__(self, verbose_name=None, name=None,
  2330   def __init__(self,
  2270                required=False, validator=None, choices=None,
  2331                verbose_name=None,
  2271                auto_current_user=False, auto_current_user_add=False):
  2332                name=None,
       
  2333                required=False,
       
  2334                validator=None,
       
  2335                choices=None,
       
  2336                auto_current_user=False,
       
  2337                auto_current_user_add=False,
       
  2338                indexed=True):
  2272     """Initializes this Property with the given options.
  2339     """Initializes this Property with the given options.
  2273 
  2340 
  2274     Note: this does *not* support the 'default' keyword argument.
  2341     Note: this does *not* support the 'default' keyword argument.
  2275     Use auto_current_user_add=True instead.
  2342     Use auto_current_user_add=True instead.
  2276 
  2343 
  2283       choices: User provided set of valid property values.
  2350       choices: User provided set of valid property values.
  2284       auto_current_user: If true, the value is set to the current user
  2351       auto_current_user: If true, the value is set to the current user
  2285         each time the entity is written to the datastore.
  2352         each time the entity is written to the datastore.
  2286       auto_current_user_add: If true, the value is set to the current user
  2353       auto_current_user_add: If true, the value is set to the current user
  2287         the first time the entity is written to the datastore.
  2354         the first time the entity is written to the datastore.
       
  2355       indexed: Whether property is indexed.
  2288     """
  2356     """
  2289     super(UserProperty, self).__init__(verbose_name, name,
  2357     super(UserProperty, self).__init__(verbose_name, name,
  2290                                        required=required,
  2358                                        required=required,
  2291                                        validator=validator,
  2359                                        validator=validator,
  2292                                        choices=choices)
  2360                                        choices=choices,
       
  2361                                        indexed=indexed)
  2293     self.auto_current_user = auto_current_user
  2362     self.auto_current_user = auto_current_user
  2294     self.auto_current_user_add = auto_current_user_add
  2363     self.auto_current_user_add = auto_current_user_add
  2295 
  2364 
  2296   def validate(self, value):
  2365   def validate(self, value):
  2297     """Validate user.
  2366     """Validate user.
  2358       item_type = basestring
  2427       item_type = basestring
  2359     if not isinstance(item_type, type):
  2428     if not isinstance(item_type, type):
  2360       raise TypeError('Item type should be a type object')
  2429       raise TypeError('Item type should be a type object')
  2361     if item_type not in _ALLOWED_PROPERTY_TYPES:
  2430     if item_type not in _ALLOWED_PROPERTY_TYPES:
  2362       raise ValueError('Item type %s is not acceptable' % item_type.__name__)
  2431       raise ValueError('Item type %s is not acceptable' % item_type.__name__)
  2363     if 'required' in kwds and kwds['required'] is not True:
  2432     if issubclass(item_type, (Blob, Text)):
  2364       raise ValueError('List values must be required')
  2433       self._require_parameter(kwds, 'indexed', False)
       
  2434       kwds['indexed'] = True
       
  2435     self._require_parameter(kwds, 'required', True)
  2365     if default is None:
  2436     if default is None:
  2366       default = []
  2437       default = []
  2367     self.item_type = item_type
  2438     self.item_type = item_type
  2368     super(ListProperty, self).__init__(verbose_name,
  2439     super(ListProperty, self).__init__(verbose_name,
  2369                                        required=True,
       
  2370                                        default=default,
  2440                                        default=default,
  2371                                        **kwds)
  2441                                        **kwds)
  2372 
  2442 
  2373   def validate(self, value):
  2443   def validate(self, value):
  2374     """Validate list.
  2444     """Validate list.