SQLAlchemy(4)

結果查詢html

上節課使用query從數據庫中查詢到告終果,可是query返回的對象是直接可用的嗎?mysql

首先導入模塊web

from connect import session
from user_modules import User

query返回對象sql

複製代碼
rs = session.query(User)
print(rs)
for i in rs:
     print(i)
#----------------------------------

#根據返回結果來看, rs 是一個 Query 對象,打印出來能夠看到轉化的 SQL
rs = session.query(User).filter(User.username'塔卡')


#all 是返回全部符合條件的數據
rs = session.query(User).all() #查詢全部數據,返回一個列表
print(rs)
print(rs[0].username) #屬性訪問


#first 是返回全部符合條件數據的第一條數據
rs = session.query(User).first() #查詢第一條數據


#[0] 和 first 相似,可是若是沒有符合條件的數據則會報錯
session.query(User).filter(User.username
'budong')[0]


#這裏,在 query 中查詢對象的某個屬性值 ( 對應爲查詢表中某個字段的值 ),返回的結果再也不是一個 Query 對象,而是一個列表
rs = session.query(User.username).filter(User.username == '塔卡').all()


#同理,可是 first 返回結果是一個元組
rs = session.query(User.username).filter(User.username == '塔卡').first()


#[0] 和 first 相似,可是若是沒有符合條件的數據則會報錯
session.query(User.username).filter(User.username=='budong')[0]數據庫

#getattr(rs[0], 'username'), rs[0].username這兩種方式能夠取到具體的數據值
rs = session.query(User).filter(User.username=='budong').all()
print(hasattr(rs,'username'))
print(getattr(rs,'username','litao'))session

rs = session.query(User)[0:2] #索引取值
print(rs)
# rs2 = session.query(User).filter(User.username=='塔卡').all()app

print(rs,type(rs))

複製代碼

條件查詢一ssh

過濾函數函數

filter 是一個過濾函數,過濾條件均可以書寫在此函數中,不一樣的條件之間用 逗號 分隔tornado

filter_by 也是一個過濾函數,可是功能要弱一些

filter 和 filter_by 的區別

兩者都是 過濾函數,可是使用有以下差異:

1. filter 中須要添加 類對象,filter_by不須要

2. filter_by 中只能添加等於的條件,不能添加 不等於、大於小於等條件,filter沒有這個限制

rs = session.query(User.username).filter(User.username == '塔卡')
rs2 = session.query(User.username).filter_by(username = '塔卡')
print(rs)

like 和 notlike

like 是模糊查詢,和數據庫中的 like 用法同樣

notlike 和 like 做用相反

rs = session.query(User).filter(User.username.like('%塔%')).all()
rs = session.query(User).filter(User.username.notlike('%塔%')).all()

in_  和 notin_

in_ 和 notin_ 是範圍查找,參數爲列表

rs = session.query(User.username).filter(User.username.in_(['塔卡','小潑'])).all()
rs = session.query(User.username).filter(User.username.notin_(['塔卡','小潑'])).all()

is_ 和 isnot

is_  和 isnot  精確查找

rs = session.query(User).filter(User.username.is_(None)).all()
rs = session.query(User).filter(User.username.isnot(None)).all()
#判斷爲空還可使用:
session.query(User.id).filter(User.username==None).all()

查詢結果數:限制查詢

all、limit、offset、slice、one

複製代碼
rs  =session.query(User.username).all()
print(rs)
rs  =session.query(User.username).limit(2).all()  #限制數量查詢
rs  =session.query(User.username).offset(2).all()  #偏移量
rs  =session.query(User.username).slice(1,4).all()  #切片

#無論怎樣寫one只能查一條數據,若是有多條重複數據,會報錯

sqlalchemy.orm.exc.MultipleResultsFound: Multiple rows were found for one()

rs = session.query(User.username).filter(User.username == '李濤').one()
print(rs)

複製代碼

排序:倒敘先進行導入desc

複製代碼
from sqlalchemy import desc
rs = session.query(User.username,User.id).order_by(User.id).all() #升序排列
rs = session.query(User.username,User.id).order_by(desc(User.id)).all()

#綜合使用
rs = session.query(User.username,User.id).order_by(desc(User.id)).filter(User.username == '李濤').all()
print(rs)

複製代碼

聚合函數

func.count

使用函數時,須要導入 func, group_by 和 order_by 同樣,是能夠直接使用的,不須要導入

having 也能夠直接使用,使用方法也和 SQL 中使用相似

func.sum、func.max、func.min

extract

extract 提取對象中的數據,這裏提取分鐘,並把提取出來的結果用 label 命名別名,以後就可使用 group_by 來分組

count 裏面一樣可使用 *

or_

or_ 是或者的意思,和數據庫中的 or 同樣

複製代碼
# 分組查詢與聚合函數一塊兒使用
from sqlalchemy import func,extract,or_
# rs = session.query(User.password,func.count(User.id)).group_by(User.password).all()
# rs = session.query(User.password,func.count(User.id)).group_by(User.password).having(func.count(User.id) >1).all()
# print(rs)

# rs = session.query(User.password,func.sum(User.id)).group_by(User.password).all()

rs = session.query(User.password,func.max(User.id)).group_by(User.password).all()

rs = session.query(User.password,func.min(User.id)).group_by(User.password).all()

print(rs)

#extract

rs = session.query(extract('minute',User.create_time).label('minute'),func.count(User.id)).group_by('minute').all()

#or_
rs = session.query(User.username).filter(or_(User.username.isnot(None),User.password == '1234')).all()
print(rs)

複製代碼

 3 多表查詢

在user_modules.py中增長一張表UserDetails表

複製代碼
class UserDetails(Base):
    __tablename__='user_details'
    id = Column(Integer, primary_key=True, autoincrement=True)
    id_card = Column(Integer,nullable=True,unique=True)
    lost_login = Column(DateTime)
    login_num = Column(Integer,default=0)
    user_id = Column(Integer,ForeignKey('user.id'))


    
    
    
    
複製代碼
</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__repr__</span><span style="color: #000000;">(self): </span><span style="color: #0000ff;">return</span> <span style="color: #800000;">'</span><span style="color: #800000;">&lt;UserDetails(id=%s,id_card=%s,last_login=%s,login_num=%s,user_id=%s)&gt;</span><span style="color: #800000;">'</span>%<span style="color: #000000;">( self.id, self.id_card, self.lost_login, self.login_num, self.user_id )</span></pre>

在query_test.py文件中導入新增長的表

from user_modules import User,UserDetails

笛卡爾鏈接:

rs =session.query(User.username,UserDetails.lost_login).filter(UserDetails.user_id==User.id).all()

去掉.all(),查看原生SQL以下:

SELECT user.id AS user_id, user.username AS user_username, user.password AS user_password, 
user.create_time AS user_create_time, user._locked AS user__locked, user_details.id AS user_details_id,
user_details.id_card AS user_details_id_card, user_details.lost_login AS user_details_lost_login,
user_details.login_num AS user_details_login_num, user_details.user_id AS user_details_user_id FROM user, user_details WHERE user_details.user_id
= user.id

inner join:內鏈接

rs = session.query(User.username,UserDetails.lost_login).\
    join(UserDetails,UserDetails.user_id == User.id)

查看原生SQL以下:

SELECT user.username AS user_username, user_details.lost_login AS user_details_lost_login 
FROM user INNER JOIN user_details ON user_details.user_id = user.id

###使用笛卡爾積的filter條件與使用inner join運行的結果一致。但運行的原生sql不一致。

left join:外鏈接,能夠將兩張表對調

rs = session.query(User.username,UserDetails.lost_login).\
    outerjoin(UserDetails,UserDetails.user_id==User.id).all()

# print(rs)

運行SQL以下:

SELECT user.username AS user_username, user_details.lost_login AS user_details_lost_login 
FROM user LEFT OUTER JOIN user_details ON user_details.user_id = user.id

運行結果以下:

#兩張表對調
rs = session.query(UserDetails.lost_login,User.username).\
    outerjoin(User,UserDetails.user_id==User.id).all()

# print(rs)

運行SQL以下:

SELECT user_details.lost_login AS user_details_lost_login, user.username AS user_username 
FROM user_details LEFT OUTER JOIN user ON user_details.user_id = user.id

運行結果以下:

union:

 聯合查詢,有自動去重的功能,對應的還有 union_all

q1 = session.query(User.id)
q2 = session.query(UserDetails.user_id)
# print(q1.union(q2).all())

 

子表查詢

聲明子表

sql_0 = session.query(UserDetails.lost_login).subquery() #聲明子表
#使用 # print(session.query(User,sql_0.c.lost_login))

運行結果以下:

SELECT user.id AS user_id, user.username AS user_username, user.password AS user_password, 
user.create_time AS user_create_time, user._locked AS user__locked, anon_1.lost_login AS anon_1_lost_login FROM user, (SELECT user_details.lost_login AS lost_login FROM user_details) AS anon_1

原生SQL查詢:

複製代碼
sql_1 = '''
    select * from   `user`
'''
#查詢
row = session.execute(sql_1)
#循環取值
# for i in row: # print(i)
#取值 print(row) #fetch會記錄遊標運行了上面的for之後下面就查不到數據 print(row.fetchone()) #查詢一條 print(row.fetchmany()) #在多查詢一條 print(row.fetchall()) # 差剩下的全部
複製代碼

 

一對一表關係

Module

須要先建立對應的 Module ,這裏採用以前創建好的 User 和 UserDetails

複製代碼
from sqlalchemy.orm import relationship
....
class User(Base):
    .....
class UserDetails(Base):
    ......


    
    
    
    
複製代碼
userdetail </span>= relationship(<span style="color: #800000;">'</span><span style="color: #800000;">User</span><span style="color: #800000;">'</span>,backref=<span style="color: #800000;">'</span><span style="color: #800000;">details</span><span style="color: #800000;">'</span>,uselist=False,cascade=<span style="color: #800000;">'</span><span style="color: #800000;">all</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #008000;">#</span><span style="color: #008000;">SQLAlchemy裏面用來表示表關係的,一對一</span> <span style="color: #008000;">#</span><span style="color: #008000;">relationship只在模型層面上生效,只在模型層面上</span> <span style="color: #0000ff;">def</span> <span style="color: #800080;">__repr__</span><span style="color: #000000;">(self): ........</span></pre>

自動添加屬性

在剛纔這裏, User 裏面原本是沒有 details 這個屬性的,可是在 UserDetails 裏面添加 relationship 以後, User 實例會自動加上 details 屬性

relationship

表關係是邏輯上的關係,可是 mysql 中並無直接說明表關係的東西,外鍵約束是一個表現形式,外鍵是一種表之間的約束,能夠用來表示這種關係

在SQLAlchemy裏面,這個relationship表明了一對多的關係,固然咱們能夠經過參數改變關係,它默認是一對多的關係,而這個關係是SQLAlchemy裏面的,和數據庫沒有關係,可是relationship是和外鍵一塊兒使用的。

反向查詢

row = session.query(User).get(4)
print(row)
print(row.details)  #會把對應的詳情表裏面的對應的信息打印出來

結果爲:

        <User(id=4,username=小潑,password=55432,create_time=2019-04-01 23:10:56,_locked=False)>

[<UserDetails(id=2,id_card=543,last_login=2019-04-02 23:35:38,login_num=4,user_id=4)>]

正向查詢:

row= session.query(UserDetails).get(2)
print(row)
print(row.userdetail)

結果爲:

<UserDetails(id=2,id_card=543,last_login=2019-04-02 23:35:38,login_num=4,user_id=4)>

&lt;User(id=4,username=小潑,password=55432,create_time=2019-04-01 23:10:56,_locked=False)&gt;</pre>

使用一對多

relationship 默認是 一對多 關係

uselist

uselist=True

默認是 True ,所以能夠省略不寫

多對多表關係

用戶 和 文章之間,能夠是一對多的關係,可是若是用戶轉載的話,就能夠當作是 多對多 關係,那 多對多 關係在 SQLAlchemy 中怎麼表示呢?

在Module中建立中間表

複製代碼
from sqlalchemy import Table

user_article = Table('user_article', Base.metadata,
Column(
'user_id', Integer, ForeignKey('user.id'), primary_key=True), #聯合主鍵
Column('article_id', Integer, ForeignKey('article.id'), primary_key=True)
)

複製代碼

在Module中建立  文章Module

複製代碼
class Article(Base):
    __tablename__ = 'article'
    id = Column(Integer,primary_key=True,autoincrement=True)
    content = Column(String(500),nullable=True)
    create_time  = Column(DateTime,default=datetime.now)


    
    
    
    
複製代碼
article_user </span>= relationship(<span style="color: #800000;">'</span><span style="color: #800000;">User</span><span style="color: #800000;">'</span>,backref = <span style="color: #800000;">'</span><span style="color: #800000;">article</span><span style="color: #800000;">'</span>,secondary=<span style="color: #000000;">user_article) </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__repr__</span><span style="color: #000000;">(self): </span><span style="color: #0000ff;">return</span> <span style="color: #800000;">'</span><span style="color: #800000;">Article(id=%s, content=%s, creat_time=%s)</span><span style="color: #800000;">'</span> %<span style="color: #000000;"> ( self.id, self.content, self.create_time )</span></pre>

調用測試:

row = session.query(User).get(4)
print(dir(row))
print(row)
print(row.article)
print(row.details)  #會把對應的詳情表裏面的對應的信息打印出來

結果展現:

複製代碼
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 

'__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__mapper__', '__module__',

'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__table__', '__tablename__', '__weakref__', '_decl_class_registry', '_locked', '_sa_class_manager',

'_sa_instance_state', 'article', 'create_time', 'details', 'id', 'metadata', 'password', 'username']

[Article(id=1, content=litao進階了, creat_time=2019-04-05 18:51:34), Article(id=2, content=式微走了, creat_time=2019-04-01 18:52:06)]
[
<UserDetails(id=2,id_card=543,last_login=2019-04-02 23:35:38,login_num=4,user_id=4)>]

</span>&lt;User(id=4,username=小潑,password=55432,create_time=2019-04-01 23:10:56,_locked=False)&gt;<span style="color: #000000;">

複製代碼

包跟包管理

當把 Module 寫好以後,該如何調用呢?

在模塊中直接導入:

from data.user_modules import UserDetails

執行06-login.py,報錯結果以下:

複製代碼
Traceback (most recent call last):
  File "/home/pyvip/tornado_pro/06-login.py", line 11, in <module>
    from data.user_modules import UserDetails
  File "/home/pyvip/tornado_pro/data/user_modules.py", line 2, in <module>
    from connect import Base
ImportError: No module named 'connect'
複製代碼

解決方法:

簡單登陸

 定義06-login.py 文件

複製代碼
import sys
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler
from tornado.options import define,options
import util.ui_modules
import util.ui_methods
# import time
from data.connect import session
from data.user_modules import UserDetails, User

define('port',default=8080,help='run server',type=int)

#
class MainHandler(RequestHandler):
def get(self):
self.write(
'請去login')

class LoginHandler(RequestHandler):
def get(self):
self.render(
'in_out.html')


application = tornado.web.Application(
handlers
=[
(r
'/',MainHandler),
(r
'/login',LoginHandler),
],
debug
=True,
template_path
= 'templates',
static_path
='static',
# autoescape = None, #全局取消轉義
ui_methods=util.ui_methods,
ui_modules
=util.ui_modules
)
if name == 'main':
tornado.options.parse_command_line()
http_server
= tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()

</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> post(self): </span><span style="color: #800000;">'''</span><span style="color: #800000;">驗證邏輯</span><span style="color: #800000;">'''</span><span style="color: #000000;"> user </span>= self.get_argument(<span style="color: #800000;">'</span><span style="color: #800000;">name</span><span style="color: #800000;">'</span><span style="color: #000000;">,None) password </span>= self.get_argument(<span style="color: #800000;">'</span><span style="color: #800000;">password</span><span style="color: #800000;">'</span><span style="color: #000000;">,None) </span><span style="color: #008000;">username = session.query(User).filter(User.username == user).first()</span><span style="color: #0000ff;">print</span><span style="color: #000000;">(username) </span><span style="color: #0000ff;">if</span> username <span style="color: #0000ff;">and</span> password ==<span style="color: #000000;"> username.password: self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">02-templates.html</span><span style="color: #800000;">'</span><span style="color: #000000;">, username </span>=<span style="color: #000000;"> username.username ) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: self.write(</span><span style="color: #800000;">'</span><span style="color: #800000;">登陸失敗</span><span style="color: #800000;">'</span><span style="color: #000000;">)

複製代碼

渲染模板02-templates.html爲

複製代碼
<!DOCTYPE html>
{#去掉整個頁面的轉義#}
{#{% autoescape None %}#}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Templates</title>
</head>
<body>
{% if username !='' %}
    歡迎 {{ username }} 登陸
<img src="static/images/01.jpg" width="200px" alt="">
<img src="{{ static_url('images/02.webp') }}" width="200px" alt="">
{% else %}
    親,請登陸
{% end %}
</body>
</html>
複製代碼

登陸成功返回以下內容:

登陸失敗返回:

將LoginHandler的post方法的代碼簡化爲get_name方法:

複製代碼
class LoginHandler(RequestHandler):
    def get(self):
        self.render('in_out.html')
    def post(self):
        '''驗證邏輯'''
        user = self.get_argument('name',None)
        password = self.get_argument('password',None)
        # username = session.query(User).filter(User.username == user).first()
        username = User.get_name(user)
        print(username)
        if username and  password == username.password:
            self.render('02-templates.html',
                        username = username.username
                        )
        else:
            self.write('登陸失敗')
複製代碼

在user_modules.py文件的User Module下定義get_name方法:

複製代碼
class User(Base):
  。。。。
    def __repr__(self):
        return '''
        <User(id=%s,username=%s,password=%s,create_time=%s,_locked=%s)>
        '''%(self.id,self.username,self.password,self.create_time,self._locked)
    @classmethod
    def get_name(cls,user):
        '''用來查詢用戶名的方法'''
        return session.query(cls).filter(cls.username == user).first()
複製代碼
本站公眾號
   歡迎關注本站公眾號,獲取更多信息