python sqlalchemy 和django orm 對比


表和表的之間關系,往往通過外鍵建立關系,那簡單介紹下外鍵。

一:DB角度上的上外鍵含義:

主鍵:主鍵是唯一標識一條記錄,不能重復,有唯一性約束,不可以為空。用來保證數據的完整性,我們常用自增id來創建主鍵。

外鍵:是另一張表的主鍵或者帶有唯一性約束的列,外鍵可以重復,可以為空,主要作用:用他來和其他的表建立邏輯關系。所以當我們談到外鍵的時候最少涉及到2張表。

比如:

部門表dept 和員工表emp。emp表中的Dept_id就是外鍵,和dept表單的主鍵id關聯。

因為一個部門多個員工,所以員工需要在知道自己歸屬的部門,所以emp是子表而dept是父表。

外鍵一定是從表中建立的,從而和主表建立關系,從表維護二者的關系。

使用外鍵的條件:

  • 1、兩張表必須都是InnodeDB表,並且沒有臨時表。
  • 注:InnodDB是數據庫引擎。mysql常見的數據庫引擎:innodeDBhe 和MySIAM,而MySIM不支持外鍵約束!!!
  • 2、建立外鍵關系的對應列必須有具有相似的InnoDB內部數據類型。
  • 3、建立外鍵關系的對應列必須建立了索引,

二:從python角度理解:

在python中通過關系映射(orm),調用底層dbapi來實現數據庫的操作。通過定義類和對象,(類是表,類的對象是數據庫的一行數據。)來操作數據庫,通過底層的轉換,最終形成sql,在相應的數據庫中執行。

notice:

  1. 無論是python通過orm(sqlalchemy和django的orm)來創建表,通過定義字段使表與表建立關系,比如外鍵。python層面定義的外鍵作用到數據庫中,也是形成相應的外鍵。
  2. 所以無論哪種的orm建立的表結構,外鍵都是在子表中,可以理解成外鍵在多對一中“多”的字段中。
  3. 在數據庫中,外鍵是建立在子表中。建立外鍵的列是另一張的表的主鍵。所以python設置外鍵的表是固定的。對應的“一對多”的“多”表中建立外鍵。

A:django的orm:

一對多:

比如說:作者和書籍的關系,一個作者有多本書,構成一對多的關系。

modles結構:

1 class Author(models.Model):
2     username=models.CharField(max_length=32)
3 class Book(models.Model):
4     name=models.CharField(max_length=32)
5     b_author=models.ForeignKey('Author')

 

插入數據:通過訪問相應的url插入數據

1 def insert(request):
2     models.Author.objects.create(username="tom")
3     return HttpResponse('ok')

1 def insert(request):
2     models.Book.objects.create(name='唐吉坷德',b_author_id=1)
3     return HttpResponse('ok')

數據庫本質的插入。

查詢:

1、正向查詢:

通過雙下划線來操作。

比如:百年孤獨的作者的名字是誰?

1 def insert(request):
2     ret=models.Book.objects.filter(name="百年孤獨").values("b_author__username")
3     print(ret)
4     return HttpResponse('ok')
5 <QuerySet [{'b_author__username': 'tom'}]>

反向查詢:一對多也支持反向查詢。方法有2個。一個是通過雙下划線,一個通過tablename_set字段哎查詢,查詢的方式不一樣,方法也不一樣!!!

  • 通過tablename_set來反向查詢,但是在這種查詢,方法和manytomany 操作第三章表類似。

需求:查看tom都出 那些書,書的名字是什么?

1 def insert(request):
2     obj=models.Author.objects.filter(username='tom').first()
3     ret=obj.book_set.all()
4     for i in ret:
5         print(i.name)
6     return HttpResponse('ok')
1 百年孤獨
2 唐吉坷德
  • 通過雙下滑線反向查詢:
1 def insert(request):
2     booklist=models.Author.objects.filter(username='tom').values('book__name')
3     print(booklist)
4     return HttpResponse('ok')
5 <QuerySet [{'book__name': '百年孤獨'}, {'book__name': '唐吉坷德'}]>

notice:

  • 無論正向查詢還是反向查詢,都可以用雙下划線。
  • 反向查詢的時候,因為對應的是“一”,所以查詢的結果需要單個對象,然后查詢對應“多”的表的對象集合。而使用set的字段的時候,需要注意使用的方法都是all、filter等。

對於多對多情況,正向查詢的時候,使用的的是雙下划線,反向查詢是用含有manytomany的字段的“表”名的隱藏的列的進行反向查詢。也是利用雙下划線。

表結構:一個服務器有多個用戶,一個用戶在存在於多個服務器中。

1 class Host(models.Model):
2     ip=models.CharField(max_length=32)
3     hostname=models.CharField(max_length=32)
4 
5 class User(models.Model):
6     username=models.CharField(max_length=32)
7     password=models.CharField(max_length=32)
8     user_host=models.ManyToManyField('Host')#注意引號的作用,如果沒有引號的話,關聯的表必須在當前表的前面,否則報錯。

插入數據:

1 def insert(request):
2     for i in range(4):
3         models.Host.objects.create(ip='172.17.33.'+str(i),hostname=str(i)+'.com')
4     return HttpResponse('ok')

1 def insert(request):
2     for i in range(4):
3         models.User.objects.create(username='evil'+str(i),password=str(i)+'123')
4     return HttpResponse('ok')

  • 需要注意:當我們在給含有ManyToMany的表進行插值的時候,對於字段:user_host=models.ManyToManyField('Host'),不需要插值。該列只是關聯第三張關系表:mod_user_user_host。實質該列在數據庫並不存在該列。

第三張表(mod_user_user_host)進行插值:第三張表存儲在django層面來看是對象,實際在數據庫中存儲的是這2張表(host、user)的主鍵值。所以插入值的方法也有2種。

正向插入值:

1 def insert(request):
2     res=models.User.objects.filter(id=3).first()
3     ret=models.Host.objects.filter(id__gt=2)
4     res.user_host.add(*ret)
5     return HttpResponse('ok')

 

反向插入值,反向插入值,用另一張表名_set.add()方法來操作。

1 def insert(request):
2     res=models.Host.objects.filter(id=1).first()
3     ret=models.User.objects.filter(id__lt=4)
4     res.user_set.add(*ret)
5     return HttpResponse('ok')

 

當然相應的查詢方法,也可以 用_set字段或者表名進行查詢,和一對多是一樣的。唯一區別是:更新第三張表的時候,最好用原生sql進行更新。

B:sqlalchemy的orm

  • 對於一對多或者多對多的情況下,在sqlalchemy中使用的是relationship()來創建一個數據庫中並不存在的列來構建2個表之間的關系。
  • 需要注意的:在django中建立外鍵,直接類的名字既可,在sqlalchemy中需要寫:表的名字.主鍵列的名字。

表結構:比如主機和主機用戶來構建多對多表結構

 1 class Host(Base):
 2     __tablename__='host'
 3     nid=Column(Integer,autoincrement=True,primary_key=True)
 4     hostname=Column(String(32))
 5     ip=Column(String(32))
 6 
 7 class system_User(Base):
 8     __tablename__='system_user'
 9     nid=Column(Integer,autoincrement=True,primary_key=True)
10     username=Column(String(32))
11     password=Column(String(32))
12 
13 class Host_to_system_User(Base):
14     __tablename__='host_to_system_user'
15     nid=Column(Integer,primary_key=True,autoincrement=True)
16     host_nid=Column(Integer,ForeignKey('host.nid'))
17     system_user_nid=Column(Integer,ForeignKey('system_user.nid'))#需要注意這個和django不一樣,django直接寫類名字既可。 18     host=relationship('Host',backref='ho')
19     system_user=relationship('system_User',backref='sys_u')
20 Base.metadata.create_all(engine)##執行該函數,他就會執行所有Base所有的子類。調用我們定義類並創建相應的表結構。
21 Session=sessionmaker(engine)
22 session=Session()#創建數據庫連接。可以理解為django的db模塊中connection。

 

插入數據:2張表正常插入值和django一樣,不需要關注第三張表,當需要建立關系的時候,直接給第三張表插入相應的id值既可。

 1 Session=sessionmaker(engine)
 2 session=Session()#創建數據庫連接。可以理解為django的db模塊中connection。
 3 host_obj=Host(hostname='c1.com',ip='172.17.22.12')
 4 host_obj_1=Host(hostname='c2.com',ip='172.17.22.13')
 5 host_obj_2=Host(hostname='c3.com',ip='172.17.22.14')
 6 session.add_all(
 7         [
 8             host_obj,
 9             host_obj_1,
10             host_obj_2
11         ]
12 )
13 system_user_obj=system_User(username='evil',password='123')
14 system_user_obj_1=system_User(username='tom',password='123')
15 system_user_obj_2=system_User(username='jack',password='123')
16 session.add_all(
17         (
18             system_user_obj,
19             system_user_obj_1,
20             system_user_obj_2
21         )
22 )
23 #
24 host_to_system_user_obj=Host_to_system_User(host_nid=1,system_user_nid=1)
25 host_to_system_user_obj_1=Host_to_system_User(host_nid=1,system_user_nid=2)
26 host_to_system_user_obj_2=Host_to_system_User(host_nid=1,system_user_nid=3)
27 host_to_system_user_obj_3=Host_to_system_User(host_nid=2,system_user_nid=1)
28 host_to_system_user_obj_7=Host_to_system_User(host_nid=2,system_user_nid=2)
29 host_to_system_user_obj_4=Host_to_system_User(host_nid=2,system_user_nid=3)
30 host_to_system_user_obj_5=Host_to_system_User(host_nid=3,system_user_nid=1)
31 host_to_system_user_obj_6=Host_to_system_User(host_nid=3,system_user_nid=2)
32 session.add_all(
33     [
34         host_to_system_user_obj,
35         host_to_system_user_obj_1,
36         host_to_system_user_obj_2,
37         host_to_system_user_obj_3,
38         host_to_system_user_obj_4,
39         host_to_system_user_obj_5,
40         host_to_system_user_obj_6,
41         host_to_system_user_obj_7
42     ]
43 )
44 session.commit()

 

 1 mysql> select * from  host;
 2 +-----+----------+--------------+
 3 | nid | hostname | ip           |
 4 +-----+----------+--------------+
 5 |   1 | c1.com   | 172.17.22.12 |
 6 |   2 | c2.com   | 172.17.22.13 |
 7 |   3 | c3.com   | 172.17.22.14 |
 8 +-----+----------+--------------+
 9 3 rows in set (0.00 sec)
10 
11 mysql> select * from  system_user;
12 +-----+----------+----------+
13 | nid | username | password |
14 +-----+----------+----------+
15 |   1 | evil     | 123      |
16 |   2 | tom      | 123      |
17 |   3 | jack     | 123      |
18 +-----+----------+----------+
19 3 rows in set (0.00 sec)
20 
21 mysql> select * from host_to_system_user;
22 +-----+----------+-----------------+
23 | nid | host_nid | system_user_nid |
24 +-----+----------+-----------------+
25 |   1 |        1 |               1 |
26 |   2 |        1 |               2 |
27 |   3 |        1 |               3 |
28 |   4 |        2 |               1 |
29 |   5 |        2 |               3 |
30 |   6 |        3 |               1 |
31 |   7 |        3 |               2 |
32 |   8 |        2 |               2 |
33 +-----+----------+-----------------+
34 8 rows in set (0.00 sec)

 

查詢:

需求:用戶evil 都在哪些服務器上?

分析:首先通過system_user查到evil的對象,通過該對象獲取sys_u的列,這個列是第三張表的對象的集合,通過循環該列獲取每列的我們建立的host關系列來獲取對應的host表的屬性值。也就是說先反向查詢在正向查詢。

1 ret=session.query(system_User).filter(system_User.username=='evil').first()
2 for i in ret.sys_u:
3     print(i.host.ip)

 

1 172.17.22.12
2 172.17.22.13
3 172.17.22.14

 

django orm和sqlalchemy的orm的對比:

  • 在django中orm中插入和查詢的時候,使用是類中定義數據庫的列的名字,而在sqlalchemy中使用的調用數據庫的字段是對象的屬性字段。

django:

modle:

1 class Person(models.Model):
2     username=models.CharField(max_length=32)
3 
4 class Fav(models.Model):
5     name=models.CharField(max_length=32)
6     per_fav=models.ForeignKey('Person')

查詢語句:

比如查詢名字為evil的愛好都有哪些:

1 def insert(request):
2     ret=models.Fav.objects.filter(per_fav__username='evil').values('name')
3     print(ret)
4     return HttpResponse('ok')

其中查詢的字段並沒有對象.字段屬性。而sqlalchemy在調用表的字段的字段的時候,需要使用類.字段(其中字段屬於類的靜態字段。)

sqlalchemy:

 1 from sqlalchemy.ext.declarative import declarative_base
 2 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index#導入列數據類型字段。
 3 from sqlalchemy.orm import sessionmaker, relationship#導入會話函數、
 4 from sqlalchemy import create_engine
 5 engine = create_engine("mysql+pymysql://root:@192.168.31.222:3306/django", max_overflow=15)#創建數據庫引擎,通過連接池獲取數據庫的連接。數據庫連接池數量為:15,默認值是5.
 6 #創建sqlorm基類。(為聲明的類定義基類。)
 7 Base = declarative_base()
 8 class User(Base):
 9     __tablename__='user'
10     nid=Column(Integer,primary_key=True,autoincrement=True)
11     username=Column(String(32))
12 
13     def __repr__(self):
14         temp='%s-%s'%(self.nid,self.username)
15         return temp
16 Base.metadata.create_all(engine)##執行該函數,他就會執行所有Base所有的子類。調用我們定義類並創建相應的表結構。

插入數據:

 1 Session=sessionmaker(engine)
 2 session=Session()#創建數據庫連接。可以理解為django的db模塊中connection。
 3 user_obj=User(username='evil')#創建類的對象。
 4 user_obj1=User(username='tom')
 5 user_obj2=User(username='jack')
 6 session.add_all(
 7         (
 8             user_obj,
 9             user_obj1,
10             user_obj2
11         )
12 )
13 session.commit()#提交數據庫事務。

 

1 mysql> select *from user;
2 +-----+----------+
3 | nid | username |
4 +-----+----------+
5 |   1 | evil     |
6 |   2 | tom      |
7 |   3 | jack     |
8 +-----+----------+
9 3 rows in set (0.00 sec)

查詢數據庫:

1 Session=sessionmaker(engine)
2 session=Session()#創建數據庫連接。可以理解為django的db模塊中connection。
3 ret=session.query(User).filter(User.nid>1).all()
4 print(ret)
5 [2-tom, 3-jack]

對比:

  • 數據庫連接:django在創建項目的時候在setting配置文件中需要配置數據庫的連接串,默認使用數據庫是sqlite。
1 DATABASES = {
2     'default': {
3         'ENGINE': 'django.db.backends.sqlite3',
4         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
5     }
6 }
  • sqlalchemy 需要導入相應的模塊,然后建立相應的連接引擎和數據庫的連接池。每次執行數據庫操作的時候都需要創建連接對象。而django默認幫我們做數據庫連接。
1 from sqlalchemy import create_engine
2 engine = create_engine("mysql+pymysql://root:@192.168.31.222:3306/django", max_overflow=15)#創建數據庫引擎,通過連接池獲取數據庫的連接。 
  • django在創建數據庫的時候,創建表的類的時候需要繼承(models.Model)而sqlalchemy需要繼承一個基類:Base = declarative_base()
  • 在django如果不指定主鍵的時候,django默認會創建一個名為:id的自增列。而sqlalchemy需要手動指定自增列和主鍵。
  • 默認在django中表明是類名的小寫,而在sqlalchemy中必須要指定__tablename__字段,指定數據庫的表的名字否則報如下錯誤信息
1 sqlalchemy.exc.InvalidRequestError: Class <class '__main__.User'> does not have a __table__ or __tablename__ specified and does not inherit from an existing table-mapped class.

django:

1 from django.db import models
2 
3 # Create your models here.
4 class Person(models.Model):
5     username=models.CharField(max_length=32)

 sqlalchemy:

 1 from sqlalchemy.ext.declarative import declarative_base
 2 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index  # 導入列數據類型字段。
 3 from sqlalchemy.orm import sessionmaker, relationship  # 導入會話函數、
 4 from sqlalchemy import create_engine
 5 
 6 engine = create_engine("mysql+pymysql://root:@192.168.147.129:3306/sqlalchemy",
 7                        max_overflow=15)  # 創建數據庫引擎,通過連接池獲取數據庫的連接。數據庫連接池數量為:15,默認值是5.
 8 # 創建sqlorm基類。(為聲明的類定義基類。)
 9 Base = declarative_base()
10 
11 class   User(Base):
12     __tablename__='user'
13     nid=Column(Integer,primary_key=True,autoincrement=True)
14     name=Column(String(32))
15     def __repr__(self):
16         return self.name
  • django 默認情況不需要指定表名,而sqlalchemy需要指定表名否則報錯。
  • 2者在查詢返回的結果都是對象的列表(django是Queryset對象,而sqlalchemy返回的是相應的類對象),django可以用__unicode__方法 輸出對象的時候我們可以自定義輸出的我們自定義的字段(django版本Django 1.10中是__str__方法),而sqlalchemy是__repr__方法來輸出對象的自定義字段。

sqlalchemy:

1 class User(Base):
2     __tablename__='user'
3     nid=Column(Integer,primary_key=True,autoincrement=True)
4     username=Column(String(32))
5 Session=sessionmaker(engine)
6 session=Session()#創建數據庫連接。可以理解為django的db模塊中connection。
7 ret=session.query(User).filter(User.nid>1).all()
8 print(ret)
9 [<__main__.User object at 0x03708210>, <__main__.User object at 0x03708250>]

 django:

1 from django.db import models
2 
3 # Create your models here.
4 class Person(models.Model):
5     username=models.CharField(max_length=32)
6 
7 class Fav(models.Model):
8     name=models.CharField(max_length=32)
9     per_fav=models.ForeignKey('Person')
1 def insert(request):
2     ret=models.Fav.objects.filter(per_fav__username='evil').all()
3     print(ret)
4     return HttpResponse('ok')
1 <QuerySet [<Fav: Fav object>, <Fav: Fav object>]>

 sqlalchemy:

1 class User(Base):
2     __tablename__='user'
3     nid=Column(Integer,primary_key=True,autoincrement=True)
4     username=Column(String(32))
5 
6     def __repr__(self):
7         temp='%s-%s'%(self.nid,self.username)
8         return temp
9  [2-tom, 3-jack]

 django:

 1 from django.db import models
 2 
 3 # Create your models here.
 4 class Person(models.Model):
 5     username=models.CharField(max_length=32)
 6     def __str__(self):
 7         temp='%s-%s'%(self.id,self.username)
 8         return temp
 9 
10 class Fav(models.Model):
11     name=models.CharField(max_length=32)
12     per_fav=models.ForeignKey('Person')
13     def __str__(self):
14         temp='%s-%s'%(self.id,self.name)
15         return temp

輸出函數:

 1 from django.shortcuts import render,HttpResponse
 2 from mod  import models
 3 # Create your views here.
 4 def insert(request):
 5     ret=models.Fav.objects.filter(per_fav__username='evil').all()
 6     for i in ret:
 7         print(i)
 8     return HttpResponse('ok')
 9 1-bak
10 2-foot
  •  在sqlalchemy中對數據庫進行增刪改的時候,最后需要提交事務(session.commit()),數據庫才能保存我們的數據修改,在低版本的django中也需要save()進行提交事務在版本:Django 1.10中不需要提交事務。
 1 User_obj=User(name='evil')
 2 User_obj_1=User(name='tom')
 3 User_obj_2=User(name='jack')
 4 
 5 Session=sessionmaker(engine)
 6 session=Session()
 7 session.add_all(
 8     [
 9         User_obj,
10         User_obj_1,
11         User_obj_2
12     ]
13 )
14 session.commit()

 

1 mysql> select * from  user;
2 +-----+------+
3 | nid | name |
4 +-----+------+
5 |   1 | evil |
6 |   2 | tom  |
7 |   3 | jack |
8 +-----+------+
9 3 rows in set (0.00 sec)
  • 插入數據:在一對多的情況下,django可以有兩種方式進行數據的插入,包括:django層面,對外鍵列插入關聯表的對象,在數據庫層面:實際數據庫中存儲的是:另一個列的主鍵id值。可以直接插入數字。

表結構:

1 class Author(models.Model):
2     username=models.CharField(max_length=32)
3 class Book(models.Model):
4     name=models.CharField(max_length=32)
5     b_author=models.ForeignKey('Author')

給b_author插入值,默認情況下,book表(注意是小寫)中的b_author列在數據庫中的列為:b_author_id.

所以我們在插入b_author列插入author表的對象,也可以直接插入author主鍵列里的id值。插入對象:

1 from django.shortcuts import render,HttpResponse
2 from mod import models
3 # Create your views here.
4 def insert(request):
5     author_obj=models.Author.objects.filter(id=1).first()
6     models.Book.objects.create(b_author=author_obj,name="羅兵遜漂流記")
7     return HttpResponse('ok')

 

插入id值:

1 from django.shortcuts import render,HttpResponse
2 from mod import models
3 # Create your views here.
4 def insert(request):
5     models.Book.objects.create(b_author_id=2,name="陳二狗的妖孽人生")
6     return HttpResponse('ok')

需要注意的是:需要使用實際數據庫存在的列(b_author_id)而不是django定義字段的列名字:b_author。

  • 在sqlalchemy中,插入的時候可以直接入相應類的對象(add()),或者可迭代對象集合(addall(元組、或者列表)),存在foreign key 列需要特別注意: 插入該列的值不是對象,而是關聯表的主鍵nid值,不是對象!!!區別於django 插入外鍵的時候可以是對象或者id值。而且sqlalchemy定義的列名字就是數據庫存儲的名字。區別於django中在數據庫層次的實際存儲的列名字是django定義列的名字加上_id.

表結構:一個作者有多本書。book表示子表,相對author表為父表。

 1 class Author(Base):
 2     __tablename__='author'
 3     username=Column(String(32))
 4     nid=Column(Integer,primary_key=True,autoincrement=True)
 5     def __repr__(self):
 6         temp='%s--%s'%(self.nid,self.username)
 7         return temp
 8 
 9 class Book(Base):
10     __tablename__ = 'book'
11     nid = Column(Integer, primary_key=True, autoincrement=True)
12     name = Column(String(32))
13     b_a=Column(Integer,ForeignKey('author.nid'))
14     book=relationship('Author',backref='auth')
15 
16     def __repr__(self):
17         temp = '%s-%s' % (self.nid, self.name)
18         return temp
19 Base.metadata.create_all(engine)##執行該函數,他就會執行所有Base所有的子類。調用我們定義類並創建相應的表結構。

 插入值:

 1 author1=Author(username='evil')
 2 author2=Author(username='tom')
 3 author3=Author(username='jack')
 4 
 5 Session=sessionmaker(bind=engine)
 6 session=Session()
 7 session.add_all(
 8     [
 9         author1,
10         author2,
11         author3
12     ]
13 )
14 session.commit()
1 mysql> select * from author;
2 +----------+-----+
3 | username | nid |
4 +----------+-----+
5 | evil     |   1 |
6 | tom      |   2 |
7 | jack     |   3 |
8 +----------+-----+
9 3 rows in set (0.00 sec)

插入語句:注意外鍵的列插入的不是對象,而是相應的關聯表的主鍵的值。即主表的主鍵nid值。

 1 book1=Book(name='百年孤獨',b_a=3)
 2 book2=Book(name='陳二狗的妖孽人生',b_a=3)
 3 book3=Book(name='海賊王',b_a=3)
 4 
 5 session.add_all(
 6     (
 7         book1,
 8         book2,
 9         book3
10     )
11 )
12 session.commit()
 1 mysql> select * from book;
 2 +-----+--------------------------+------+
 3 | nid | name                     | b_a  |
 4 +-----+--------------------------+------+
 5 |   2 | 百年孤獨                 |    2 |
 6 |   3 | 陳二狗的妖孽人生         |    2 |
 7 |   4 | 海賊王                   |    2 |
 8 |   5 | 百年孤獨                 |    1 |
 9 |   6 | 陳二狗的妖孽人生         |    1 |
10 |   7 | 海賊王                   |    1 |
11 |   8 | 百年孤獨                 |    3 |
12 |   9 | 陳二狗的妖孽人生         |    3 |
13 |  10 | 海賊王                   |    3 |
14 +-----+--------------------------+------+
15 9 rows in set (0.00 sec)
  • 出現的問題: 編碼問題,如果我們在sqlalchemy中不指定編碼的時候,底層dbapi采用的編碼:latin-1進行編碼,如果你插入的數據含有中文的話,由於latin-1在解碼的時候,不支持中文會報錯:

UnicodeEncodeError: 'latin-1' codec can't encode characters in position 38-41: ordinal not in range(256)

解決方法:在數據連接引擎處指定編碼,讓sql語句中的中文部分按指定的編碼進行解碼。使用dbname?charset=utf8來指定相應的編碼。

http://firefish.blog.51cto.com/298258/112794/

1 engine = create_engine("mysql+pymysql://root:@192.168.147.129:3306/sqlalchemy?charset=utf8",
2                        max_overflow=15)  # 創建數據庫引擎,通過連接池獲取數據庫的連接。數據庫連接池數量為:15,默認值是5.

所以以后再寫引擎的時候,需要注意:直接寫上面的連接串。

在mysql中修改編碼的方法:在/etc/my.cnf 中添加入下語句,如果不添加client字段的話,在數據庫中中文字段顯示是?問號。但是程序查詢的時候,還會正常顯示中文。

1 [mysqld]
2 default-storage-engine=INNODB
3 default-character-set=utf8
4 [client]
5 default-character-set=utf8

因為有的版本mysql不支持參數:default-character-set=utf8 需要使用:character_set_server=utf8。

  •  建立外鍵的區別:django 中在一對多的情況下,使用的foreign key 。 在多對多,不創建第三張表的時候,使用ManyToMany字段。如果手動創建第三張表的時候使用foreign key來構建關系。sqlalchemy中,一對多、多對多的情況下,

都是用foreign key來構建關系。而且在多對多的情況下,需要手動構建表結構關系,創建第三張表,

  • 對外鍵列的插入方法的不同:在django中對於外鍵列插入值,可以是插入關聯表的對象或者關聯表的對應的主鍵列即id列2種方法,但是在sqlalchemy對於外鍵列只能插入父表中的定義的主鍵列的值比如:nid值,而不是對象。
  • 對於查詢建立關系的區別:在django中,默認給咱們創建相應的查詢的虛擬列比如一對多,反向查詢:tablename_set  和tablename2種虛擬關系列。前者不能使用雙下划線,后者可以使用雙下划線。在sqlalchemy中需要我們手動創建一個不存在數據庫的虛擬機列,使用(本表和關聯表的虛擬關系列)=relationship('classname',backref='另一張表的虛擬關系列')進行查詢。正向查詢用:用等號的左邊的列,反向查詢的時候,用等號的右邊的backref定義的虛擬關系列。

sqlalchemy:

表結構:

 1 class Author(Base):
 2     __tablename__='author'
 3     username=Column(String(32))
 4     nid=Column(Integer,primary_key=True,autoincrement=True)
 5     def __repr__(self):
 6         temp='%s--%s'%(self.nid,self.username)
 7         return temp
 8 
 9 class Book(Base):
10     __tablename__ = 'book'
11     nid = Column(Integer, primary_key=True, autoincrement=True)
12     name = Column(String(100))
13     b_a=Column(Integer,ForeignKey('author.nid'))
14     book=relationship('Author',backref='auth')
15     def __repr__(self):
16         temp = '%s-%s' % (self.nid, self.name)
17         return temp 

反向查詢:使用子表中定義的列:book=relationship('Author',backref='auth') 建立的虛擬關系列:auth需要注意的是auth是另一個表的對象的集合。

需求場景:作者為:evil,都出那些書籍?

1 Session=sessionmaker(bind=engine)
2 session=Session()
3 res=session.query(Author).filter(Author.username=='evil').first()
4 for i in res.auth:
5     print(i.name)
6 百年孤獨
7 陳二狗的妖孽人生
8 海賊王

正向查詢:

需求場景:book表中nid=2的書作者是誰?

1 Session=sessionmaker(bind=engine)
2 session=Session()
3 ret=session.query(Book).filter(Book.nid==2).first()
4 print(ret.book.username)
5 
6 tom
  •  在django中對於大於、小於、等於、包含、不包含等使用的雙下滑線:id__lt=2...    在sqlalchemy中直接使用  > < ==等。
  • 在django和sqlalchemy中如果查詢條件為並的時候,都是用逗號。
1 Session=sessionmaker(bind=engine)
2 session=Session()
3 ret=session.query(Book).filter(Book.nid.in_((2,3,7)) ).all()
4 for i in ret:
5     print(i.name)
6 百年孤獨
7 陳二狗的妖孽人生
8 海賊王

 


免責聲明!

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



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