weedata


Nameweedata JSON
Version 0.2.5 PyPI version JSON
download
home_pageNone
Summaryan ORM/ODM for Google Cloud Datastore/MongoDB/redis, featuring a compatible interface with Peewee.
upload_time2024-04-20 12:26:05
maintainerNone
docs_urlNone
authorNone
requires_python>=3.6
licenseMIT License Copyright (c) 2024 cdhigh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords peewee orm odm google cloud datastore mongodb redis
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # <img style="vertical-align: top;" src="https://github.com/cdhigh/weedata/blob/main/logo.png?raw=true" height="50px"> weedata

[![PyPI version shields.io](https://img.shields.io/pypi/v/weedata.svg)](https://pypi.python.org/pypi/weedata/) ![python](https://img.shields.io/badge/python-3.6+-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/cdhigh/weedata/blob/main/LICENSE)


The weedata is a python ODM/ORM module for Google Cloud Datastore / MongoDB / Redis, featuring a compatible interface with [Peewee](https://github.com/coleifer/peewee).    
The main priority of this library is to ensure compatibility with the Peewee API.    
If you don't use advanced SQL features such as multi-table join queries and more, you can easily switch between SQL and NoSQL without modifying your application code.    
I know using NoSQL as if it were SQL is not a very smart idea, but it can achieve maximum compatibility with various databases, so, just choose what you like.    



# Quickstart
Alright, if you're already familiar with Peewee, you basically don't need this documentation.     
The majority of the content in this document is directly taken from the [official Peewee documentation](http://docs.peewee-orm.com), with minimal alterations. Gratitude is expressed in advance for this.   

  >> If you have any questions during use, you can first check the peewee documentation, and then try in weedata to verify if weedata supports it or not.




## How to migrate your peewee-based project to NoSQL
Only Two Steps Needed:

1. Change 
```python
from peewee import *
```
to
```python
from weedata import *
```

2. Change
```python
db = SqliteDatabase(dbName)
```
to one of the following lines:
```python
db = DatastoreClient(project="AppId")
db = MongoDbClient(dbName, "mongodb://localhost:27017/")
db = RedisDbClient("AppId", "redis://127.0.0.1:6379/")
```



## Installation

weedata supports Google Cloud Datastore, MongoDB and Redis.    
To use Google Cloud Datastore, you need to install google-cloud-datastore [optional, only install if need].   
To use MongoDB, you need to install pymongo [optional, only install if need].   

To use redis, you need to install Redis-py [optional, only install if need].   

```bash
pip install google-cloud-datastore
pip install pymongo
pip install redis
pip install weedata
```


### DatastoreClient
To use Google Cloud Datastore, firstly you need to create a project, set up authentication. You can refer to [Firestore in Datastore mode documentation](https://cloud.google.com/datastore/docs) or [backDatastore mode client libraries](https://cloud.google.com/datastore/docs/reference/libraries) or [Python Client for Google Cloud Datastore API](https://cloud.google.com/python/docs/reference/datastore/latest) for guidance.
```python
API signature: DatastoreClient(project=None, namespace=None, credentials=None, \_http=None)
```

### MongoDbClient
weedata uses pymongo as the MongoDB driver. After correctly installing the MongoDB service and pymongo, create a client following this API signature.
The parameter 'project' corresponds to the MongoDB database name, and 'host' can be passed as complete database url.
```python
MongoDbClient(project, dbUrl='mongodb://127.0.0.1:27017/')
```

### RedisDbClient
weedata uses redis-py as the redis driver. After correctly installing the redis service and redis-py, create a client following this API signature.  
The parameter 'project' corresponds to the redis key prefix, and 'host' can be passed as complete database url, you can also choose which db to be used by passing the parameter 'db', the range is [0-15].
```python
RedisDbClient(project, dbUrl='redis://127.0.0.1:6379/0', key_sep=':')
```

> **Important Notice:**
> Redis functions as an in-memory database. Although it includes disk persistence capabilities, this feature does not ensure 100% data integrity and presents a potential risk of data loss. Prior to implementing Redis as a storage database, it is crucial to grasp pertinent knowledge and configure it appropriately, including enabling RDB (Redis Database) or AOF (Append Only File) functionality.
For example, you can add two lines in redis.conf:
```
appendonly yes
appendfsync always
or
appendonly yes
appendfsync everysec
```


### PickleDbClient
weedata also provides a simple database implementation PickleDbClient using Python's pickle library, which can be used for testing purposes and in applications with limited resources and low data integrity requirements.   
The parameter "dbName" is the filename of pickle file, if set to ":memory:", an in-memory database is created.  
```python
PickleDbClient(dbName, bakBeforeWrite=True)
```




## Model Definition

```python
from weedata import *

db = DatastoreClient(project="AppId")
db = MongoDbClient("AppId", "mongodb://localhost:27017/")
db = RedisDbClient("AppId")

class Person(Model):
    class Meta:
        database = db

    name = CharField()
    birthday = DateTimeField()
```

The best practice is to define a base class that connects to the database, and then have other models within your application inherit from it.

```python
class MyBaseModel(Model):
    class Meta:
        database = db

class Person(MyBaseModel):
    name = CharField()
    birthday = DateTimeField()

class Message(MyBaseModel):
    context = TextField()
    read_count = IntegerField(default=0)
```

Or you can setup or change database connection dynamically by using bind method.
```python
Person.bind(db)
Message.bind(db)

#or
db.bind([Person, Message])
```



## Storing data

Let's begin by populating the database with some people. We will use the save() and create() methods to add and update people's records.

```python
from datetime import datetime
uncle_bob = Person(name='Bob', birthday=datetime(1960, 1, 15))
uncle_bob.save()
```

You can also add a person by calling the create() method, which returns a model instance. The insert_many() function is a convenient method for adding many data at once:

```python
grandma = Person.create(name='grandma', birthday=datetime(1935, 3, 1))
Person.insert_many([{'name':'Herb', 'birthday':datetime(1950, 5, 5)}, {'name':'Adam', 'birthday':datetime(1990, 9, 1)}])
```



## Counting records

You can count the number of rows in any select query:

```python
Tweet.select().count()
Tweet.select().where(Tweet.id > 50).count()
```




## Updating data

To update data, modify the model instance and call save() to persist the changes.   
Here we will change Grandma's name and then save the changes in the database.    
Or you can use an update statement that supports all standard arithmetic operators:  

```python
grandma.name = 'Grandma'
grandma.save()

Person.update({Person.name: 'Grandma L.'}).where(Person.name == 'Grandma').execute() #Changing to other name
Person.update(name='Grandma').where(Person.name == 'Grandma').execute() #Changing to other name
Person.update({Person.name: 'Dear. ' + Person.name}).where(Person.birthday > datetime(1950, 5, 5)).execute() #Adding a title of respect before someone's name
# update statement supports: +, -, *, /, //, %, **, <<, >>, &, |, ^
```

To delete one or many instances from database:

```python
herb.delete_instance()
Person.delete().where(Person.birthday < datetime(1950, 5, 4)).execute()
```

To remove the whole collection(MongoDb)/kind(datastore), you can use:

```python
Person.drop_table()
db.drop_tables([Person, Message])
```


## Retrieving Data


### Getting single records
Let's retrieve Grandma's record from the database. To get a single record from the database, use Select.get():

```python
grandma = Person.get(name = 'Grandma')
grandma = Person.get(Person.name == 'Grandma')
grandma = Person.select().where(Person.name != 'Grandma').get()
grandma = Person.select().where(Person.name == 'Grandma').first()
grandma = Person.get_or_none(Person.name == 'Grandma')
grandma = Person.get_by_id('65bda09d6efd9b1130ffccb0')
grandma = Person.select().where(Person.id == '65bda09d6efd9b1130ffccb0').first()
```

```python
grandma = Person.select(Person.name, Person.birthday).where(Person.name == 'Grandma').first()
```

The code lines above return an instance of the Model. If, in some situations, you need a dictionary, you can use dicts() to return a standard Python dictionary.

```python
grandma.dicts()
grandma.dicts(only=[Person.name, Person.birthday])
grandma.dicts(exclude=[Person.birthday])
grandma.dicts(remove_id=True)
```



### Lists of records
Let's list all the people in the database:

```python
for person in Person.select():
    print(person.name)
```



### Sorting
Let's make sure these are sorted alphabetically by adding an order_by() clause:

```python
for person in Person.select().where(Person.birthday <= datetime(1960, 1, 15)).order_by(Person.name):
    print(person.name)

for person in Person.select().order_by(Person.birthday.desc()):
    print(person.name, person.birthday)
```



### Combining filter expressions

People whose birthday is between 1940 and 1960 (inclusive of both years):

```python
d1940 = datetime(1940, 1, 1)
d1960 = datetime(1960, 12, 31)
query = Person.select().where((Person.birthday >= d1940) & (Person.birthday <= d1960))
for person in query:
    print(person.name, person.birthday)


query = Person.select().where(Person.birthday.between(d1940, d1960))
query = Person.select().where(Person.birthday >= d1940).where(Person.birthday <= d1960)
query = Person.select().where((Person.birthday < d1940) | (Person.birthday > d1960))
query = Person.select().where(~((Person.birthday < d1940) | (Person.birthday > d1960)))
```


# Models and Fields

## Field types supported:
* BooleanField
* IntegerField
* BigIntegerField
* SmallIntegerField
* FloatField
* DoubleField
* DecimalField
* CharField
* FixedCharField
* TextField
* BlobField
* UUIDField
* DateTimeField
* JSONField
* ForeignKeyField
* PrimaryKeyField


## Reserved field names
The following names of fields reserved by the model, should be avoided for your fields:   

```_key, _id, id```


## Field initialization arguments
Parameters accepted by all field types and their default values:
* `unique = False` – create a unique index on this column.
* `index = None` – create an index on this column. If you want to store content longer than 1500 bytes in the datastore, set the index to False.   
* `default = None` – any value or callable to use as a default for uninitialized models
* `enforce_type = False` – determine if the new value is of a specific type.

Other parameters accepted by Peewee can be passed, weedata simply ignores them in a straightforward manner.



## Default field values
weedata can provide default values for fields when objects are created. For example to have an IntegerField default to zero rather than None, you could declare the field with a default value:

```python
class Message(Model):
    context = TextField()
    read_count = IntegerField(default=0)
```

In some instances it may make sense for the default value to be dynamic. A common scenario is using the current date and time. weedata allows you to specify a function in these cases, whose return value will be used when the object is created. Note we only provide the function, we do not actually call it:

```python
class Message(Model):
    context = TextField()
    timestamp = DateTimeField(default=datetime.datetime.now)
```


## Model options and table metadata
In order not to pollute the model namespace, model-specific configuration is placed in a special class called Meta (a convention borrowed from the django framework):

```python
db = MongoDbClient("AppId", "mongodb://localhost:27017/")

class Person(Model):
    name = CharField()
    birthday = DateTimeField()

    class Meta:
        database = db
```

Once the class is defined, you should not access ModelClass.Meta, but instead use ModelClass.\_meta.  
The ModelOptions class implements several methods which may be of use for retrieving model metadata.  

```python
Person._meta.fields
Person._meta.client
```
Now, the ModelOptions accepts two parameters:
* **database**: Indicating the backend database client instance to be used, if not set, you can call `Model.bind()` or `db.bind() ` at run time.
* **primary_key**: Optional, the name of the primary key at the underlying level of each database is different. It's called "key" in Datastore, for MongoDB, it's "\_id", to ensure compatibility with SQL and simplify application code, weedata automatically adds a primary key named 'id' with a string type. This primary key is only an application-level attribute variable and will not be saved to the underlying database.
If this name conflicts with your application, you can use the "primary_key" attribute to modify it, for example:

```python
class Meta
    database = db
    primary_key = 'id_'
```


# Querying

## Selecting a single record

```python
User.get_by_id('65bda09d6efd9b1130ffccb0')
User.get(User.username == 'Charlie')
User.get(username='Charlie')
User.select().where(User.username.in_(['Charlie', 'Adam'])).order_by(User.birthday.desc()).get()
```


## Filtering records
You can filter for particular records using normal python operators. weedata supports a wide variety of query operators.


### Query operators
The following types of comparisons are supported by weedata:

| Comparison          | Meaning                         |
|---------------------|---------------------------------|
| ==                  | x equals y                      |
| !=                  | x is not equal to y             |
| <                   | x is less than y                |
| <=                  | x is less than or equal to y    |
| >                   | x is greater than y             |
| >=                  | x is greater than or equal to y |
| .in_(list)          | IN lookup                       |
| .not_in(list)       | NOT IN lookup.                  |
| .between(v1, v2)    | Between lookup                  |
| .startswith(prefix) | lookup using a string prefix    |
| &                   | logical AND                     |
| \|                  | logical OR                      |
| ~                   | logical NOT (mongodb only)      |




## Some extra examples

```python
user = User.select().where(User.name == 'python').get()
user = User.select().where(User.name == 'python').first()
user = User.select().where(User.name.in_(['python', 'cobra'])).first()
user = User.select().where(User.name.not_in(['python', 'cobra'])).first()
users = User.select(User.name, User.score).where(User.name == 'python').execute()
users = User.select().where(User.birthdate.between(datetime.datetime(2024,1,1), datetime.datetime(2024,2,1))).execute()
user = User.select().where((User.name != 'python') & (User.name != 'cobra')).first()
user = User.select().where(User.name != 'python').where(User.name != 'cobra').first()
users = User.select().order_by(User.birthdate.desc(), User.score).limit(10).execute()
users = User.select().where((User.name == 'python') | (User.name == 'cobra')).execute()
users = list(User.get(User.age > 30))
Tweet.select().where(Tweet.content.startswith('de'))

User.update({User.score: User.att_days + (User.evaluation * 2)}).where(User.age < 10).execute()

User.replace(name='python', score=100, birthdate=datetime.datetime(2024,1,1)).execute()

```


# Changelog  
* v0.2.5
1. bugfix: The compatibility problem of get_or_none().


* v0.2.4
1. Optimize the modification logic for JSONField, saving to the database at any time.    


* v0.2.3
1. bugfix: TextField/BlobField/JSONField initial params not worked.   


* v0.2.2
1. Delays connecting to the pymongo database until the first operation.   
2. The default Index property of TextField/BlobField/JSONField is set to False.   


* v0.2.1
1. Set index=False will exclude the field from indexes in datastore
2. Bugfix: datastore update query removes the fields unmodified


* v0.2.0
1. Supports Redis
2. Add a simple database implementation PickleDbClient
3. Supports ForeignKeyField
4. Add Model.replace() and Model.get_or_create() method
5. Add Field.startswith() query
6. [MongoDB/Redis] Auto create index when field with attr index=True or unique=True
7. Fix DoesNotExist not found error


* v0.1.0
Initial version


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "weedata",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": null,
    "keywords": "peewee, ORM, ODM, google cloud datastore, MongoDB, redis",
    "author": null,
    "author_email": "cdhigh <akindleear@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/88/4d/ccb39d58ca9763f52214d90d1a4d3d1a081d3b4da418c440250eb29f65ca/weedata-0.2.5.tar.gz",
    "platform": null,
    "description": "# <img style=\"vertical-align: top;\" src=\"https://github.com/cdhigh/weedata/blob/main/logo.png?raw=true\" height=\"50px\"> weedata\r\n\r\n[![PyPI version shields.io](https://img.shields.io/pypi/v/weedata.svg)](https://pypi.python.org/pypi/weedata/) ![python](https://img.shields.io/badge/python-3.6+-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/cdhigh/weedata/blob/main/LICENSE)\r\n\r\n\r\nThe weedata is a python ODM/ORM module for Google Cloud Datastore / MongoDB / Redis, featuring a compatible interface with [Peewee](https://github.com/coleifer/peewee).    \r\nThe main priority of this library is to ensure compatibility with the Peewee API.    \r\nIf you don't use advanced SQL features such as multi-table join queries and more, you can easily switch between SQL and NoSQL without modifying your application code.    \r\nI know using NoSQL as if it were SQL is not a very smart idea, but it can achieve maximum compatibility with various databases, so, just choose what you like.    \r\n\r\n\r\n\r\n# Quickstart\r\nAlright, if you're already familiar with Peewee, you basically don't need this documentation.     \r\nThe majority of the content in this document is directly taken from the [official Peewee documentation](http://docs.peewee-orm.com), with minimal alterations. Gratitude is expressed in advance for this.   \r\n\r\n  >> If you have any questions during use, you can first check the peewee documentation, and then try in weedata to verify if weedata supports it or not.\r\n\r\n\r\n\r\n\r\n## How to migrate your peewee-based project to NoSQL\r\nOnly Two Steps Needed:\r\n\r\n1. Change \r\n```python\r\nfrom peewee import *\r\n```\r\nto\r\n```python\r\nfrom weedata import *\r\n```\r\n\r\n2. Change\r\n```python\r\ndb = SqliteDatabase(dbName)\r\n```\r\nto one of the following lines:\r\n```python\r\ndb = DatastoreClient(project=\"AppId\")\r\ndb = MongoDbClient(dbName, \"mongodb://localhost:27017/\")\r\ndb = RedisDbClient(\"AppId\", \"redis://127.0.0.1:6379/\")\r\n```\r\n\r\n\r\n\r\n## Installation\r\n\r\nweedata supports Google Cloud Datastore, MongoDB and Redis.    \r\nTo use Google Cloud Datastore, you need to install google-cloud-datastore [optional, only install if need].   \r\nTo use MongoDB, you need to install pymongo [optional, only install if need].   \r\n\r\nTo use redis, you need to install Redis-py [optional, only install if need].   \r\n\r\n```bash\r\npip install google-cloud-datastore\r\npip install pymongo\r\npip install redis\r\npip install weedata\r\n```\r\n\r\n\r\n### DatastoreClient\r\nTo use Google Cloud Datastore, firstly you need to create a project, set up authentication. You can refer to [Firestore in Datastore mode documentation](https://cloud.google.com/datastore/docs) or [backDatastore mode client libraries](https://cloud.google.com/datastore/docs/reference/libraries) or [Python Client for Google Cloud Datastore API](https://cloud.google.com/python/docs/reference/datastore/latest) for guidance.\r\n```python\r\nAPI signature: DatastoreClient(project=None, namespace=None, credentials=None, \\_http=None)\r\n```\r\n\r\n### MongoDbClient\r\nweedata uses pymongo as the MongoDB driver. After correctly installing the MongoDB service and pymongo, create a client following this API signature.\r\nThe parameter 'project' corresponds to the MongoDB database name, and 'host' can be passed as complete database url.\r\n```python\r\nMongoDbClient(project, dbUrl='mongodb://127.0.0.1:27017/')\r\n```\r\n\r\n### RedisDbClient\r\nweedata uses redis-py as the redis driver. After correctly installing the redis service and redis-py, create a client following this API signature.  \r\nThe parameter 'project' corresponds to the redis key prefix, and 'host' can be passed as complete database url, you can also choose which db to be used by passing the parameter 'db', the range is [0-15].\r\n```python\r\nRedisDbClient(project, dbUrl='redis://127.0.0.1:6379/0', key_sep=':')\r\n```\r\n\r\n> **Important Notice:**\r\n> Redis functions as an in-memory database. Although it includes disk persistence capabilities, this feature does not ensure 100% data integrity and presents a potential risk of data loss. Prior to implementing Redis as a storage database, it is crucial to grasp pertinent knowledge and configure it appropriately, including enabling RDB (Redis Database) or AOF (Append Only File) functionality.\r\nFor example, you can add two lines in redis.conf:\r\n```\r\nappendonly yes\r\nappendfsync always\r\nor\r\nappendonly yes\r\nappendfsync everysec\r\n```\r\n\r\n\r\n### PickleDbClient\r\nweedata also provides a simple database implementation PickleDbClient using Python's pickle library, which can be used for testing purposes and in applications with limited resources and low data integrity requirements.   \r\nThe parameter \"dbName\" is the filename of pickle file, if set to \":memory:\", an in-memory database is created.  \r\n```python\r\nPickleDbClient(dbName, bakBeforeWrite=True)\r\n```\r\n\r\n\r\n\r\n\r\n## Model Definition\r\n\r\n```python\r\nfrom weedata import *\r\n\r\ndb = DatastoreClient(project=\"AppId\")\r\ndb = MongoDbClient(\"AppId\", \"mongodb://localhost:27017/\")\r\ndb = RedisDbClient(\"AppId\")\r\n\r\nclass Person(Model):\r\n    class Meta:\r\n        database = db\r\n\r\n    name = CharField()\r\n    birthday = DateTimeField()\r\n```\r\n\r\nThe best practice is to define a base class that connects to the database, and then have other models within your application inherit from it.\r\n\r\n```python\r\nclass MyBaseModel(Model):\r\n    class Meta:\r\n        database = db\r\n\r\nclass Person(MyBaseModel):\r\n    name = CharField()\r\n    birthday = DateTimeField()\r\n\r\nclass Message(MyBaseModel):\r\n    context = TextField()\r\n    read_count = IntegerField(default=0)\r\n```\r\n\r\nOr you can setup or change database connection dynamically by using bind method.\r\n```python\r\nPerson.bind(db)\r\nMessage.bind(db)\r\n\r\n#or\r\ndb.bind([Person, Message])\r\n```\r\n\r\n\r\n\r\n## Storing data\r\n\r\nLet's begin by populating the database with some people. We will use the save() and create() methods to add and update people's records.\r\n\r\n```python\r\nfrom datetime import datetime\r\nuncle_bob = Person(name='Bob', birthday=datetime(1960, 1, 15))\r\nuncle_bob.save()\r\n```\r\n\r\nYou can also add a person by calling the create() method, which returns a model instance. The insert_many() function is a convenient method for adding many data at once:\r\n\r\n```python\r\ngrandma = Person.create(name='grandma', birthday=datetime(1935, 3, 1))\r\nPerson.insert_many([{'name':'Herb', 'birthday':datetime(1950, 5, 5)}, {'name':'Adam', 'birthday':datetime(1990, 9, 1)}])\r\n```\r\n\r\n\r\n\r\n## Counting records\r\n\r\nYou can count the number of rows in any select query:\r\n\r\n```python\r\nTweet.select().count()\r\nTweet.select().where(Tweet.id > 50).count()\r\n```\r\n\r\n\r\n\r\n\r\n## Updating data\r\n\r\nTo update data, modify the model instance and call save() to persist the changes.   \r\nHere we will change Grandma's name and then save the changes in the database.    \r\nOr you can use an update statement that supports all standard arithmetic operators:  \r\n\r\n```python\r\ngrandma.name = 'Grandma'\r\ngrandma.save()\r\n\r\nPerson.update({Person.name: 'Grandma L.'}).where(Person.name == 'Grandma').execute() #Changing to other name\r\nPerson.update(name='Grandma').where(Person.name == 'Grandma').execute() #Changing to other name\r\nPerson.update({Person.name: 'Dear. ' + Person.name}).where(Person.birthday > datetime(1950, 5, 5)).execute() #Adding a title of respect before someone's name\r\n# update statement supports: +, -, *, /, //, %, **, <<, >>, &, |, ^\r\n```\r\n\r\nTo delete one or many instances from database:\r\n\r\n```python\r\nherb.delete_instance()\r\nPerson.delete().where(Person.birthday < datetime(1950, 5, 4)).execute()\r\n```\r\n\r\nTo remove the whole collection(MongoDb)/kind(datastore), you can use:\r\n\r\n```python\r\nPerson.drop_table()\r\ndb.drop_tables([Person, Message])\r\n```\r\n\r\n\r\n## Retrieving Data\r\n\r\n\r\n### Getting single records\r\nLet's retrieve Grandma's record from the database. To get a single record from the database, use Select.get():\r\n\r\n```python\r\ngrandma = Person.get(name = 'Grandma')\r\ngrandma = Person.get(Person.name == 'Grandma')\r\ngrandma = Person.select().where(Person.name != 'Grandma').get()\r\ngrandma = Person.select().where(Person.name == 'Grandma').first()\r\ngrandma = Person.get_or_none(Person.name == 'Grandma')\r\ngrandma = Person.get_by_id('65bda09d6efd9b1130ffccb0')\r\ngrandma = Person.select().where(Person.id == '65bda09d6efd9b1130ffccb0').first()\r\n```\r\n\r\n```python\r\ngrandma = Person.select(Person.name, Person.birthday).where(Person.name == 'Grandma').first()\r\n```\r\n\r\nThe code lines above return an instance of the Model. If, in some situations, you need a dictionary, you can use dicts() to return a standard Python dictionary.\r\n\r\n```python\r\ngrandma.dicts()\r\ngrandma.dicts(only=[Person.name, Person.birthday])\r\ngrandma.dicts(exclude=[Person.birthday])\r\ngrandma.dicts(remove_id=True)\r\n```\r\n\r\n\r\n\r\n### Lists of records\r\nLet's list all the people in the database:\r\n\r\n```python\r\nfor person in Person.select():\r\n    print(person.name)\r\n```\r\n\r\n\r\n\r\n### Sorting\r\nLet's make sure these are sorted alphabetically by adding an order_by() clause:\r\n\r\n```python\r\nfor person in Person.select().where(Person.birthday <= datetime(1960, 1, 15)).order_by(Person.name):\r\n    print(person.name)\r\n\r\nfor person in Person.select().order_by(Person.birthday.desc()):\r\n    print(person.name, person.birthday)\r\n```\r\n\r\n\r\n\r\n### Combining filter expressions\r\n\r\nPeople whose birthday is between 1940 and 1960 (inclusive of both years):\r\n\r\n```python\r\nd1940 = datetime(1940, 1, 1)\r\nd1960 = datetime(1960, 12, 31)\r\nquery = Person.select().where((Person.birthday >= d1940) & (Person.birthday <= d1960))\r\nfor person in query:\r\n    print(person.name, person.birthday)\r\n\r\n\r\nquery = Person.select().where(Person.birthday.between(d1940, d1960))\r\nquery = Person.select().where(Person.birthday >= d1940).where(Person.birthday <= d1960)\r\nquery = Person.select().where((Person.birthday < d1940) | (Person.birthday > d1960))\r\nquery = Person.select().where(~((Person.birthday < d1940) | (Person.birthday > d1960)))\r\n```\r\n\r\n\r\n# Models and Fields\r\n\r\n## Field types supported:\r\n* BooleanField\r\n* IntegerField\r\n* BigIntegerField\r\n* SmallIntegerField\r\n* FloatField\r\n* DoubleField\r\n* DecimalField\r\n* CharField\r\n* FixedCharField\r\n* TextField\r\n* BlobField\r\n* UUIDField\r\n* DateTimeField\r\n* JSONField\r\n* ForeignKeyField\r\n* PrimaryKeyField\r\n\r\n\r\n## Reserved field names\r\nThe following names of fields reserved by the model, should be avoided for your fields:   \r\n\r\n```_key, _id, id```\r\n\r\n\r\n## Field initialization arguments\r\nParameters accepted by all field types and their default values:\r\n* `unique = False` \u2013 create a unique index on this column.\r\n* `index = None` \u2013 create an index on this column. If you want to store content longer than 1500 bytes in the datastore, set the index to False.   \r\n* `default = None` \u2013 any value or callable to use as a default for uninitialized models\r\n* `enforce_type = False` \u2013 determine if the new value is of a specific type.\r\n\r\nOther parameters accepted by Peewee can be passed, weedata simply ignores them in a straightforward manner.\r\n\r\n\r\n\r\n## Default field values\r\nweedata can provide default values for fields when objects are created. For example to have an IntegerField default to zero rather than None, you could declare the field with a default value:\r\n\r\n```python\r\nclass Message(Model):\r\n    context = TextField()\r\n    read_count = IntegerField(default=0)\r\n```\r\n\r\nIn some instances it may make sense for the default value to be dynamic. A common scenario is using the current date and time. weedata allows you to specify a function in these cases, whose return value will be used when the object is created. Note we only provide the function, we do not actually call it:\r\n\r\n```python\r\nclass Message(Model):\r\n    context = TextField()\r\n    timestamp = DateTimeField(default=datetime.datetime.now)\r\n```\r\n\r\n\r\n## Model options and table metadata\r\nIn order not to pollute the model namespace, model-specific configuration is placed in a special class called Meta (a convention borrowed from the django framework):\r\n\r\n```python\r\ndb = MongoDbClient(\"AppId\", \"mongodb://localhost:27017/\")\r\n\r\nclass Person(Model):\r\n    name = CharField()\r\n    birthday = DateTimeField()\r\n\r\n    class Meta:\r\n        database = db\r\n```\r\n\r\nOnce the class is defined, you should not access ModelClass.Meta, but instead use ModelClass.\\_meta.  \r\nThe ModelOptions class implements several methods which may be of use for retrieving model metadata.  \r\n\r\n```python\r\nPerson._meta.fields\r\nPerson._meta.client\r\n```\r\nNow, the ModelOptions accepts two parameters:\r\n* **database**: Indicating the backend database client instance to be used, if not set, you can call `Model.bind()` or `db.bind() ` at run time.\r\n* **primary_key**: Optional, the name of the primary key at the underlying level of each database is different. It's called \"key\" in Datastore, for MongoDB, it's \"\\_id\", to ensure compatibility with SQL and simplify application code, weedata automatically adds a primary key named 'id' with a string type. This primary key is only an application-level attribute variable and will not be saved to the underlying database.\r\nIf this name conflicts with your application, you can use the \"primary_key\" attribute to modify it, for example:\r\n\r\n```python\r\nclass Meta\r\n    database = db\r\n    primary_key = 'id_'\r\n```\r\n\r\n\r\n# Querying\r\n\r\n## Selecting a single record\r\n\r\n```python\r\nUser.get_by_id('65bda09d6efd9b1130ffccb0')\r\nUser.get(User.username == 'Charlie')\r\nUser.get(username='Charlie')\r\nUser.select().where(User.username.in_(['Charlie', 'Adam'])).order_by(User.birthday.desc()).get()\r\n```\r\n\r\n\r\n## Filtering records\r\nYou can filter for particular records using normal python operators. weedata supports a wide variety of query operators.\r\n\r\n\r\n### Query operators\r\nThe following types of comparisons are supported by weedata:\r\n\r\n| Comparison          | Meaning                         |\r\n|---------------------|---------------------------------|\r\n| ==                  | x equals y                      |\r\n| !=                  | x is not equal to y             |\r\n| <                   | x is less than y                |\r\n| <=                  | x is less than or equal to y    |\r\n| >                   | x is greater than y             |\r\n| >=                  | x is greater than or equal to y |\r\n| .in_(list)          | IN lookup                       |\r\n| .not_in(list)       | NOT IN lookup.                  |\r\n| .between(v1, v2)    | Between lookup                  |\r\n| .startswith(prefix) | lookup using a string prefix    |\r\n| &                   | logical AND                     |\r\n| \\|                  | logical OR                      |\r\n| ~                   | logical NOT (mongodb only)      |\r\n\r\n\r\n\r\n\r\n## Some extra examples\r\n\r\n```python\r\nuser = User.select().where(User.name == 'python').get()\r\nuser = User.select().where(User.name == 'python').first()\r\nuser = User.select().where(User.name.in_(['python', 'cobra'])).first()\r\nuser = User.select().where(User.name.not_in(['python', 'cobra'])).first()\r\nusers = User.select(User.name, User.score).where(User.name == 'python').execute()\r\nusers = User.select().where(User.birthdate.between(datetime.datetime(2024,1,1), datetime.datetime(2024,2,1))).execute()\r\nuser = User.select().where((User.name != 'python') & (User.name != 'cobra')).first()\r\nuser = User.select().where(User.name != 'python').where(User.name != 'cobra').first()\r\nusers = User.select().order_by(User.birthdate.desc(), User.score).limit(10).execute()\r\nusers = User.select().where((User.name == 'python') | (User.name == 'cobra')).execute()\r\nusers = list(User.get(User.age > 30))\r\nTweet.select().where(Tweet.content.startswith('de'))\r\n\r\nUser.update({User.score: User.att_days + (User.evaluation * 2)}).where(User.age < 10).execute()\r\n\r\nUser.replace(name='python', score=100, birthdate=datetime.datetime(2024,1,1)).execute()\r\n\r\n```\r\n\r\n\r\n# Changelog  \r\n* v0.2.5\r\n1. bugfix: The compatibility problem of get_or_none().\r\n\r\n\r\n* v0.2.4\r\n1. Optimize the modification logic for JSONField, saving to the database at any time.    \r\n\r\n\r\n* v0.2.3\r\n1. bugfix: TextField/BlobField/JSONField initial params not worked.   \r\n\r\n\r\n* v0.2.2\r\n1. Delays connecting to the pymongo database until the first operation.   \r\n2. The default Index property of TextField/BlobField/JSONField is set to False.   \r\n\r\n\r\n* v0.2.1\r\n1. Set index=False will exclude the field from indexes in datastore\r\n2. Bugfix: datastore update query removes the fields unmodified\r\n\r\n\r\n* v0.2.0\r\n1. Supports Redis\r\n2. Add a simple database implementation PickleDbClient\r\n3. Supports ForeignKeyField\r\n4. Add Model.replace() and Model.get_or_create() method\r\n5. Add Field.startswith() query\r\n6. [MongoDB/Redis] Auto create index when field with attr index=True or unique=True\r\n7. Fix DoesNotExist not found error\r\n\r\n\r\n* v0.1.0\r\nInitial version\r\n\r\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2024 cdhigh  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "an ORM/ODM for Google Cloud Datastore/MongoDB/redis, featuring a compatible interface with Peewee.",
    "version": "0.2.5",
    "project_urls": {
        "Homepage": "https://github.com/cdhigh/weedata",
        "Issues": "https://github.com/cdhigh/weedata/issues"
    },
    "split_keywords": [
        "peewee",
        " orm",
        " odm",
        " google cloud datastore",
        " mongodb",
        " redis"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b48c0f148ecaeb26750c6fa3edb4134bf55a2122133b6826048d70871a566342",
                "md5": "7e9132b845714e4eab4f2a7ef76a2bfa",
                "sha256": "35c057a8d4592475cb808e6958be68840e9ac8d3a160aab1e07adb4816f7e75e"
            },
            "downloads": -1,
            "filename": "weedata-0.2.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7e9132b845714e4eab4f2a7ef76a2bfa",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 24812,
            "upload_time": "2024-04-20T12:26:03",
            "upload_time_iso_8601": "2024-04-20T12:26:03.481761Z",
            "url": "https://files.pythonhosted.org/packages/b4/8c/0f148ecaeb26750c6fa3edb4134bf55a2122133b6826048d70871a566342/weedata-0.2.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "884dccb39d58ca9763f52214d90d1a4d3d1a081d3b4da418c440250eb29f65ca",
                "md5": "9c266e46a23041783dd29b3505fb0c6e",
                "sha256": "59b0790feae6f0aa1f15aaad3201aa6e7d60b877c088fd65a1fed112ca9e7a75"
            },
            "downloads": -1,
            "filename": "weedata-0.2.5.tar.gz",
            "has_sig": false,
            "md5_digest": "9c266e46a23041783dd29b3505fb0c6e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 36216,
            "upload_time": "2024-04-20T12:26:05",
            "upload_time_iso_8601": "2024-04-20T12:26:05.303463Z",
            "url": "https://files.pythonhosted.org/packages/88/4d/ccb39d58ca9763f52214d90d1a4d3d1a081d3b4da418c440250eb29f65ca/weedata-0.2.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-20 12:26:05",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "cdhigh",
    "github_project": "weedata",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "weedata"
}
        
Elapsed time: 0.23092s