peewee基本使用


PEEWEE基本使用

 

 Content 
Ⅰ  安裝
Ⅱ  鏈接數據庫
Ⅲ  建表
Ⅳ  增刪改
Ⅴ  基礎查詢
Ⅵ  ForeignKey
Ⅷ  事務

 參考官方文檔:http://docs.peewee-orm.com/en/latest/index.html

1. 安裝

pip install peewee

 

2. 鏈接數據庫

以mysql 為例(Peewee提供mysql,postgresql,sqllite)的支持

import peewee
settings = {'host': 'localhost', 'password': '', 'port': 3306, 'user': 'root'} db = peewee.MySQLDatabase("test",**settings)

 

3. 建表

3.1 表關系

class Person(Model):
    name = CharField(verbose_name='姓名', max_length=10, null=False, index=True)
    passwd = CharField(verbose_name='密碼', max_length=20, null=False, default='123456')
    email = CharField(verbose_name='郵件', max_length=50, null=True, unique=True)
    gender = IntegerField(verbose_name='姓別', null=False, default=1)
    birthday = DateField(verbose_name='生日', null=True, default=None)
    is_admin = BooleanField(verbose_name='是否是管理員', default=True)
    class Meta:
        database = db  # 這里是數據庫鏈接,為了方便建立多個表,可以把這個部分提煉出來形成一個新的類
    
table_name = 'persons' # 這里可以自定義表名


# 例如:
    class BaseModel(Model):    class Meta:    database = db class Person(BaseModel):    name = CharField()

 

全部數據類型
Field Type Sqlite Postgresql MySQL
IntegerField integer integer integer
BigIntegerField integer bigint bigint
SmallIntegerField integer smallint smallint
AutoField integer serial integer
FloatField real real real
DoubleField real double precision double precision
DecimalField decimal numeric numeric
CharField varchar varchar varchar
FixedCharField char char char
TextField text text longtext
BlobField blob bytea blob
BitField integer bigint bigint
BigBitField blob bytea blob
UUIDField text uuid varchar(40)
DateTimeField datetime timestamp datetime
DateField date date date
TimeField time time time
TimestampField integer integer integer
IPField integer bigint bigint
BooleanField integer boolean bool
BareField untyped not supported not supported
ForeignKeyField integer integer integer
null = False – 可否為空
index = False – index索引
unique = False – unique索引
column_name = None – string representing the underlying column to use if different, useful for legacy databases
default = None – 默認值,如果callable, 會調用生成!
primary_key = False – 主鍵
constraints = None - a list of one or more constraints, e.g. [Check('price > 0')]
sequence = None – sequence to populate field (if backend supports it)
collation = None – collation to use for ordering the field / index
unindexed = False – indicate field on virtual table should be unindexed (SQLite-only)
choices = None – an optional iterable containing 2-tuples of value, display
help_text = None – string representing any helpful text for this field
verbose_name = None – string representing the “user-friendly” name of this field
所有屬性

 

3.2 鏈接數據庫

db.is_closed()  # 判斷數據庫是不是鏈接
db.connect()   # 數據庫鏈接

 

3.3 建庫

db.create_tables([Person,]) #建庫

#   如果數據表已經存在,執行create_table的時候,將會拋出異常。

 

3.4 主鍵和約束

class Person(Model):
    first = CharField()
    last = CharField()

    class Meta:
        primary_key = CompositeKey('first', 'last')

class Pet(Model):
    owner_first = CharField()
    owner_last = CharField()
    pet_name = CharField()

    class Meta:
        constraints = [SQL('FOREIGN KEY(owner_first, owner_last) '
                           'REFERENCES person(first, last)')]
主鍵和約束
class BlogToTag(Model):
    """A simple "through" table for many-to-many relationship."""
    blog = ForeignKeyField(Blog)
    tag = ForeignKeyField(Tag)

    class Meta:
        primary_key = CompositeKey('blog', 'tag')
復合主鍵
User._meta.auto_increment = False # turn off auto incrementing IDs
關自增

 

4. 插&改&刪

4.1 插

p = Person.create(name='master')
####### 或 #########
p = Person(name="master")
p.save()

data = [ {'facid': 9, 'name': 'Spa', 'membercost': 20, 'guestcost': 30, 'initialoutlay': 100000, 'monthlymaintenance': 800}, {'facid': 10, 'name': 'Squash Court 2', 'membercost': 3.5, 'guestcost': 17.5, 'initialoutlay': 5000, 'monthlymaintenance': 80}] query = Facility.insert_many(data) # 插入了多個

with db.atomic(): # 一次鏈接 for data_dict in data_source: MyModel.create(**data_dict)
 
User.insert(username='Mickey').execute() # >>> 返回主鍵

 

# insert_from 是指從一個表查數據快速差到另一個表
query = (TweetArchive
         .insert_from(
             Tweet.select(Tweet.user, Tweet.message),
             fields=[Tweet.user, Tweet.message])
         .execute())
insert_from

 

4.2 改

p.email = "qq@qq.com"  # p 為記錄對象
p.save()  # 會調用update  但是不要這么寫!

query = (Facility .update(membercost=6, guestcost=30) .where(Facility.name.startswith('Tennis'))) 
query.execute() # 元子操作
 
        

 

4.3 注意

插入的時候,如果字段設置了default值,則會按照default指定的值插入,如果沒有指定,同時字段可以為null,則數據庫自動初始化值為null,如果字段不能為null,則數據庫自動初始化為其零值。 如果字段為非Null,最好設置default值,同時數據庫schema也設置其default值,如果字段為可以為null,那么初始值就設置為null即可。

 

4.4 數據刪除

p.delete_instance()
query = Member.delete().where(Member.memid == 37)


# DELETE FROM members WHERE NOT EXISTS (SELECT * FROM bookings WHERE bookings.memid = members.memid);
subq = Booking.select().where(Booking.member == Member.memid) query = Member.delete().where(~fn.EXISTS(subq)) # 同樣這樣的操作是被推薦的

 

 

5. 基礎查詢

  基本和sql語句相同

User.get(User.id == 1)  User.get_by_id(1) # Same as above.  User[1] # Also same as above. 
g = Person.select().where(Person.name == 'Grandma L.').get()   # where是查詢一個集合, select是查詢字段

g = Person.get(Person.name == 'fff.')   # get是得到第一個

g = Person.select().where(Person.age > 23).get()
# select 代表sql語句中select后面的語句表示要展示的字段 # where 代表where條件語句 得到一個數據集合,用for循環遍歷 # get()代表找第一個

 5.1 復合條件

query1 = Person.select().where((Person.name == "fff0") | (Person.name == "sss1"))

query2 = Person.select().where((Person.name == "fff") & (Person.is_relative == True))
==    x equals 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
!=    x is not equal to y
<<    x IN y, where y is a list or query
>>    x IS y, where y is None/NULL
%    x LIKE y where y may contain wildcards
**    x ILIKE y where y may contain wildcards
^    x XOR y
~    Unary negation (e.g., NOT x)
操作符

 

5.2 模糊查詢

#SELECT * FROM person WHERE name ILIKE '%tennis%';

Person.select().where(Person.name ** "%fff%").get()
######### OR ##############
query = Facility.select().where(Facility.name.contains('tennis'))

 5.3 In 查詢

# SELECT * FROM facilities WHERE facid IN (1, 5);
query = Facility.select().where(Facility.facid.in_([1, 5]))
person, created = Person.get_or_create(
    first_name=first_name,
    last_name=last_name,
    defaults={'dob': dob, 'favorite_color': 'green'})

# defaults dictionary, which will be used to populate values on newly-created instances.
get_or_create
query = User.select().dicts()
for row in query:
    print(row)
# row 是什么字典
字典展示(還可以tuples(),namedtuples(),objects())

 

5.4 Order by; Limit; Distinct; Group by; Having

query = (Person.select(Person.name).order_by(Person.name).limit(10).distinct())  # 幾乎和sql一模一樣
Person.select().order_by(Person.birthday.desc())  # 日期排序
query = (Booking .select(Booking.facid, fn.SUM(Booking.slots)) .group_by(Booking.facid) # group_by .order_by(Booking.facid))
query = (Booking .select(Booking.facility, fn.SUM(Booking.slots)) .group_by(Booking.facility) .having(fn.SUM(Booking.slots) > 1000) # having .order_by(Booking.facility))
 
Tweet.select().order_by(-Tweet.created_date) 
# Similarly you can use "+" to indicate ascending order, though ascending

 

5.5 聚合函數 

# SELECT MAX(birthday) FROM person;
query = Person.select(fn.MAX(Person.birthday))

# SELECT name, is_relative FROM person WHERE birthday = (SELECT MAX(birthday) FROM person);
MemberAlias = Member.alias() # 如果一個查詢中用了兩個表,需要這個Alias作為影子
subq = MemberAlias.select(fn.MAX(MemberAlias.joindate))
query = (Member.select(Person.is_relative, Person.name, ).where(Person.birthday == subq))

 

5.6 分頁&計數

for tweet in Tweet.select().order_by(Tweet.id).paginate(2, 10):
    print(tweet.message)

# paginate兩個參數:page_number 和 items_per_page
分頁
# 返回查到了多少條記錄
Tweet.select().where(Tweet.id > 50).count()
count

 

5.7 SQL

query = MyModel.raw('SELECT * FROM my_table WHERE data = %s', user_data)
query = MyModel.select().where(SQL('Some SQL expression %s' % user_data))
# sql 注入: ensure that any user-defined data is passed in as a query parameter and not part of the actual SQL query
原生sql

 

6. ForeignKey

6.1 表關系

class Pet(peewee.Model):
    name = peewee.CharField()
    owner = peewee.ForeignKeyField(Person,related_name="pets",backref="petties")   
  # backref是反查的字段,如果有related_name用related_name反查,如果沒有直接用petties反查 e.g. [
i.name for i in Person.get(name="aaa").petties]

class Meta: database = db
class Category(Model):
    name = CharField()
    parent = ForeignKeyField('self', null=True, backref='children')
   # 注意自關聯永遠是null = True
自關聯

 

6.2 插

g2 = Person.get(tablesinfo.Person.is_relative == False)
d2 = Pet.create(name="dog2",owner=g2)

 

6.3 正反查

#正查
dog1 = Pet.get(name="dog1")
dog1.owner.name


# 反查
aaa = Person.get(name="aaa").pets  # pets為related_name字段,如果沒寫用backref字段
for a in aaa:
    print(i.name)

 

6.4 連表查詢

g1 = Person.select().join(Pet).where(Pet.name == "dog2")

 

6.5 復雜連表

# SELECT DISTINCT m.firstname, m.surname FROM members AS m2
INNER JOIN members AS m ON (m.memid = m2.recommendedby)
ORDER BY m.surname, m.firstname;

MA = Member.alias()
query = (Member
         .select(Member.firstname, Member.surname)
         .join(MA, on=(MA.recommendedby == Member.memid))  # join中用on表示鏈接方法
         .order_by(Member.surname, Member.firstname))

 

6.6 連多表

User.select().join(Tweet).join(Comment)

Artist.select().join(Album).switch(Artist).join(Genre) # 如果連一表多次
連多表

 

6.7 多對多

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

class Student(BaseModel):
    name = CharField()

class Course(BaseModel):
    name = CharField()
    students = ManyToManyField(Student, backref='courses')
StudentCourse = Course.students.get_through_model() # 中間表

 

huey = Student.get(Student.name == 'Huey')

# We can add all the objects represented by a query.
english_courses = Course.select().where(
    Course.name.contains('english'))
huey.courses.add(english_courses)
add
huey = Student.get(Student.name == 'Huey')
for course in huey.courses.order_by(Course.name):
    print(course.name)
huey.courses.remove(Course.select().where(Course.name.startswith('CS')))
engl_101.students.remove(huey)
remove

 

7 事務

with db.atomic() as transaction:  # Opens new transaction.
    try:
        save_some_objects()
    except ErrorSavingData:
        # Because this block of code is wrapped with "atomic", a
        # new transaction will begin automatically after the call
        # to rollback().
        transaction.rollback()
        error_saving = True
atomic和rollback
db = SqliteDatabase(':memory:')

with db.atomic() as txn:
    # This is the outer-most level, so this block corresponds to
    # a transaction.
    User.create(username='charlie')

    with db.atomic() as nested_txn:
        # This block corresponds to a savepoint.
        User.create(username='huey')

        # This will roll back the above create() query.
        nested_txn.rollback()

    User.create(username='mickey')

# When the block ends, the transaction is committed (assuming no error
# occurs). At that point there will be two users, "charlie" and "mickey".
atomic甚至可以多層嵌套
@db.atomic()
def create_user(username):
    # This statement will run in a transaction. If the caller is already
    # running in an `atomic` block, then a savepoint will be used instead.
    return User.create(username=username)

create_user('charlie')
裝飾器模式
# 純手動用commit()提交,用rollback回滾
with db.transaction() as txn:
    User.create(username='mickey')
    txn.commit()  # Changes are saved and a new transaction begins.
    User.create(username='huey')

    # Roll back. "huey" will not be saved, but since "mickey" was already
    # committed, that row will remain in the database.
    txn.rollback()



# 半自動用savepoint上下文管理
with db.transaction() as txn:
    with db.savepoint() as sp:
        User.create(username='mickey')

    with db.savepoint() as sp2:
        User.create(username='zaizee')
        sp2.rollback()  # "zaizee" will not be saved, but "mickey" will be.
手動、半自動

 

8 其他

import uuid

class UUIDField(Field):
    field_type = 'uuid'

    def db_value(self, value):
        return str(value) # convert UUID to str

    def python_value(self, value):
        return uuid.UUID(value) # convert str to UUID
自定義類型!

 

Person._meta.fields   # 用訪問_meta訪問定義的meta
Person._meta.primary_key   
Person._meta.database

# 屬性有:database, table_name, table_function, indexes, primary_key, constraints, schema, only_save_dirty, options, table_alias, depends_on, without_rowid
數據表信息的訪問

 

class Article(Model):
    name = TextField()
    timestamp = TimestampField()
    status = IntegerField()
    flags = IntegerField()

# Add an index on "name" and "timestamp" columns.
Article.add_index(Article.name, Article.timestamp)

# Add a partial index on name and timestamp where status = 1.
Article.add_index(Article.name, Article.timestamp,
                  where=(Article.status == 1))

# Create a unique index on timestamp desc, status & 4.
idx = Article.index(
    Article.timestamp.desc(),
    Article.flags.bin_and(4),
    unique=True)
Article.add_index(idx)
索引增加

 

事務autocommit模式(不推薦)

 

Employee.select(fn.Min(Employee.salary), fn.Max(Employee.salary) ).scalar(as_tuple=True)
# You can retrieve multiple scalar values by passing as_tuple=True


# scalar 表示結果的第一行第一列
scalar

 

 

 

注:原生sql,推薦 https://pypi.python.org/pypi/records/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM