Python Flask-SQLAlchemy ORM ile Veritabanı İşlemleri
ORM Nedir ?
ORM, Object Relational Mapping anlamına gelmektedir.
İlişkisel veritabanı (RDBMS) ile nesneye yönelik programların (Object Oriented Programming) arasında bir tür köprü özelliği gören ve ilişkisel veritabanındaki bilgilerimizi yönetmek için, nesne modellerimizi kullandığımız bir tekniktir/metodtur.
SQLAlchemy
- Python için geliştirilmiş SQL kütüphanesi/paketi ve Object Relational Mapper(ORM) aracıdır.
Veritabanı Modeli

Modelde gördüğünüz varlıklar (entity) arasındaki ilişki aşağıdaki gibi olacaktır:
- Teacher & Student
Many To Many - Teacher & Lecture
One To One - Teacher & Book
One To Many
- Teacher & Student
models.pyadında bir python dosyası oluşturalım.Flask ve SQLAlchemy sınıflarından nesneleri oluşturup konfigürasyonu yapalım.
xxxxxxxxxxfrom flask import Flaskfrom flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + 'veritabani.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Falsedb = SQLAlchemy(app)Projede
SQLiteveritabanı kullanıyoruz. MySQL, PostgreSQL kullanacaksanız önce veritabanını (database schema) oluşturmalısınız.- Veritabanı konfigürasyonunda daha fazlası için -> Configuration — Flask-SQLAlchemy Documentation (2.3)
SQLite Veritabanı adına
veritabani.dbadını verdik.Many To Manyilişkileri veritabanında kullanabilmek içinOne To Manyilişkilerine dönüştürüyoruz. Bunun için bir yardımcı tabloya ihtiyacımız var.Modelde göreceğiniz
StudentTeachertablosu yardımcı tablodur.
xxxxxxxxxx# Many-To-Many icin yardimci tablostudent_teacher = db.Table('StudentTeacher', db.Column('student_id', db.Integer, db.ForeignKey('student.id')), db.Column('teacher_id', db.Integer, db.ForeignKey('teacher.id')) )db.Table()sınıfı ile model olmayan tablo oluşturabiliyoruz.İlk parametre
StudentTeachertablo adı.db.Column()ile kolon oluşturuyoruz.İlk parametre
student_idkolon adı.db.Integerveri tipinin integer (tamsayı) olacağını belirtiyor.db.ForeignKey()sınıfı ile Dış Anahtar(Foreign Key) oluşturuyoruz.student.id; Student isimli tablonunid'sini belirtiyor.
primary_key=Truediyerek birincil anahtarı belirtiyoruz.
Student Modeli
xxxxxxxxxxclass Student(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) teachers = db.relationship('Teacher', secondary=student_teacher, lazy='dynamic', backref=db.backref('students', lazy='dynamic')) def __repr__(self): return '<Student %r>' % self.nameStudent(db.Model); db.Model sınıfını miras alıyor.id; db.Column ile kolon oluşturuyoruz.name;db.String(50), 50 karakterlik bir string alabileceğini belirtir.nullable=Falsediyerek, name değerinin boş bırakılamayacağını belirtiyoruz.
teachersclass attribute(sınıf niteliği);db.relationship()ile bir ilişkinin oluşturulacağını belirtiyoruz. db.relationship() ile veritabanında kolon(attribute) oluşturulmaz.db.relationship(); ilk parametresi'Teacher'ile hangi model class ile ilişki kuracağımızı belirtiyoruz.secondary=student_teacherdiyerek yardımcı tablomuzu da ilişkiye dahil ediyoruz(Many To Manyiçin gerekli!).lazyparametresi verinin database'den nasıl yükleneceğini belirtir.lazy='dynamic'dediğimizde database query'yi (veri tabanı sorgusunu) parça parça yapabiliriz. Filtreleme(filter_by), sıralama(order_by) yapabiliriz.lazy='select'ile tek seferde bütün datayı veritabanından standart select gibi almak için kullanılır. (select, True olarak da belirtilebilir.)lazy='joined'ile veriyi tek seferdeJOINolarak almak için kullanılır. select ile dynamic kombinasyonu gibidir. (joined, False olarak da belirtilebilir.)lazy='subquery', joined gibidir.
backrefile ilişki kurduğumuz model class'a bir tane property(özellik) ekliyoruz. Böylece ilişki kurduğumuzTeachersınıfından db.backref('students') içindeki'students'diyerek öğretmenin öğrencilerini görebiliriz.
__repr__(self)özel bir methoddur. Model class'tan nesne oluşturulduğunda sınıf adını ve methodda belirttiğimizself.namein değerini ekrana basar. Aşağıdaki gibi.
xxxxxxxxxx>>> Student(name='Adnan')<Student 'Adnan'>Teacher Modeli
xxxxxxxxxxclass Teacher(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) lecture_id = db.Column(db.Integer, db.ForeignKey('lecture.id')) lecture = db.relationship('Lecture', back_populates='teacher', uselist=False) books = db.relationship('Book', backref='author', lazy='dynamic') def __repr__(self): return '<Teacher %r>' % self.namelecture_id; Lecture model sınıfının id'sini tutacak sınıf niteliği.db.relationship(..., uselist=False, lazy=False);uselist=False: One to One ilişkide kullanmak için belirtildi.lazy=False, lazy='joined' demektir.back_populates; backref gibidir.
backrefparametresinin vedb.backref()methodunun kullanımına dikkat ediniz.
Lecture ve Book Modeli
xxxxxxxxxxclass Lecture(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), nullable=False) teacher = db.relationship('Teacher', back_populates = 'lecture', uselist=False) def __repr__(self): return '<Lecture %r>' % self.nameclass Book(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), nullable=False) teacher_id = db.Column(db.Integer, db.ForeignKey('teacher.id')) def __repr__(self): return '<Book %r>' % self.nameShell ortamında çalışırken import ederken kolaylık olması için;
xxxxxxxxxx.shell_context_processordef make_shell_context(): return { 'db':db, 'Student':Student, 'Teacher':Teacher, 'Lecture':Lecture, 'Book':Book }$ export FLASK_APP=models.pydedikten sonra$ flask shelldiyerek shell ortamında çalışabilirsiniz.
Shell ortamında işlemler
xxxxxxxxxx>>> # Model sınıflar ve db referansını import ediyoruz.>>> from models import *>>> # Model sınıflara(class) göre veritabanı tablolarını oluşturur.>>> db.create_all()>>> # Veritabanı işlemleri için data ekliyoruz.>>> student1 = Student(name='Adnan')>>> student2 = Student(name='Hamit')>>> student3 = Student(name='Mehmet')>>> teacher1 = Teacher(name='Şadi Evren Şeker')>>> teacher2 = Teacher(name='Akın Kaldıroğlu')>>> book1 = Book(name='Weka and Data Mining')>>> book2 = Book(name='Digital Firm')>>> book3 = Book(name='Java and OOP')>>> book4 = Book(name='Design Patterns and Clean Code')>>> lecture1 = Lecture(name='Python and Data Structures')>>> lecture2 = Lecture(name='Java ile Nesne Merkezli Programlama')>>> lecture3 = Lecture(name='Artificial Neural Networks')>>> # Veritabanına gönderilecek nesne referanslarını session'a ekliyoruz.>>> db.session.add(teacher1)>>> db.session.add(teacher2)>>> db.session.add_all([student1, student2, student3, book1, book2, book3, book4, lecture1, lecture2, lecture3])>>> # Session'a eklenen verileri veritabanına yazıyoruz.>>> db.session.commit()>>> - Bu işlemlerden sonra veritabanı tabloları:




xxxxxxxxxx>>> student1.teachers<sqlalchemy.orm.dynamic.AppenderBaseQuery object at 0x7fb5aef66c18>>>> student1.teachers.all()[]>>> # append() methoduna verdiğimiz nesne referansı ile ilişki bağlantısını yapmış oluyoruz. remove() ile de ilişkiyi koparabilirsiniz.>>> student1.teachers.append(teacher1)>>> student1.teachers.append(teacher2)>>> student1.teachers.all()[<Teacher 'Şadi Evren Şeker'>, <Teacher 'Akın Kaldıroğlu'>]>>> db.session.commit()>>> teacher1.students.all()[<Student 'Adnan'>]>>> teacher1.students.append(student2)>>> teacher1.students.append(student3)>>> teacher1.students.all()[<Student 'Adnan'>, <Student 'Hamit'>, <Student 'Mehmet'>]>>> db.session.commit()
xxxxxxxxxx>>> teacher1.books.all()[]>>> book1<Book 'Weka and Data Mining'>>>> book2<Book 'Digital Firm'>>>> teacher1.books.append(book1)>>> teacher1.books.append(book2)>>> teacher1.books.append(book4)>>> teacher1.books.all()[<Book 'Weka and Data Mining'>, <Book 'Digital Firm'>, <Book 'Design Patterns and Clean Code'>]>>> teacher2.books.all()[]>>> teacher2.books.append(book3)>>> teacher2.books.all()[<Book 'Java and OOP'>]>>> teacher2.books.append(book4)>>> teacher2.books.all()[<Book 'Java and OOP'>, <Book 'Design Patterns and Clean Code'>]>>> teacher1.books.all()[<Book 'Weka and Data Mining'>, <Book 'Digital Firm'>]>>> db.session.commit()>>> 
- Design Patterns and Clean Code kitabını Şadi Evren Şeker'e atayalım.
xxxxxxxxxx>>>>>> teacher1.books.all()[<Book 'Weka and Data Mining'>, <Book 'Digital Firm'>]>>> teacher1.books.append(book4)>>> teacher1.books.all()[<Book 'Weka and Data Mining'>, <Book 'Digital Firm'>, <Book 'Design Patterns and Clean Code'>]>>> db.session.commit()>>> 
xxxxxxxxxx>>> teacher1.lecture>>> lecture1<Lecture 'Python and Data Structures'>>>> lecture2<Lecture 'Java ile Nesne Merkezli Programlama'>>>> lecture3<Lecture 'Artificial Neural Networks'>>>> lecture1.teacher>>> lecture1.teacher = teacher1>>> teacher1.lecture<Lecture 'Python and Data Structures'>>>> lecture2.teacher = teacher1>>> teacher1.lecture<Lecture 'Java ile Nesne Merkezli Programlama'>>>> db.session.commit()>>> 
xxxxxxxxxx>>> teacher2.lecture = lecture2>>> teacher1.lecture<Lecture 'Java ile Nesne Merkezli Programlama'>>>> teacher2.lecture<Lecture 'Java ile Nesne Merkezli Programlama'>>>> db.session.commit()
- Dersi en son kime atadıysak onda kalır.
One To Onegereği!
backref'i daha fazla açıklarsak.
backrefkullandığınızda, 2 tablo arası ilişkide, 2. tablodadb.relationshipyapmanız gerekmiyor.Studentsınıfında ufak bir değişiklik yapalım.
xxxxxxxxxxclass Student(db.Model): #... teachers = db.relationship('Teacher', secondary=student_teacher, lazy='dynamic', backref=db.backref('ogrenciler', lazy='dynamic')) #...studentsyerineogrencileryaptık sadece! Aşağıdaki kodlara dikkat edelim.
xxxxxxxxxx>>> student1.teachers.append(teacher1)>>> student2.teachers.append(teacher1)>>> student3.teachers.append(teacher1)>>> teacher1.ogrenciler.all()[<Student 'Adnan'>, <Student 'Hamit'>, <Student 'Mehmet'>]backrefsayesindeteacher1.ogrencilerdiyerek veya aşağıdaki gibibook1.authordiyerek ilişkili tablonun verisine erişebiliyoruz.
xxxxxxxxxx>>> book1.author<Teacher 'Şadi Evren Şeker'>>>> book2.author<Teacher 'Şadi Evren Şeker'>>>> book4.author<Teacher 'Şadi Evren Şeker'>>>> book3.author<Teacher 'Akın Kaldıroğlu'>>>> - Kaynak: Basic Relationship Patterns — SQLAlchemy 1.2 Documentation
- Kodların Tamamı:
xxxxxxxxxxfrom flask import Flaskfrom flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + 'veritabani.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Falsedb = SQLAlchemy(app)# Many-To-Many icin yardimci tablostudent_teacher = db.Table('StudentTeacher', db.Column('student_id', db.Integer, db.ForeignKey('student.id'), primary_key=True), db.Column('teacher_id', db.Integer, db.ForeignKey('teacher.id'), primary_key=True) )class Student(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) teachers = db.relationship('Teacher', secondary=student_teacher, lazy='dynamic', backref=db.backref('ogrenciler', lazy='dynamic')) def __repr__(self): return '<Student %r>' % self.nameclass Teacher(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) lecture_id = db.Column(db.Integer, db.ForeignKey('lecture.id')) lecture = db.relationship('Lecture', back_populates='teacher', uselist=False) books = db.relationship('Book', backref='author', lazy='dynamic') def __repr__(self): return '<Teacher %r>' % self.nameclass Lecture(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), nullable=False) # back_populates='lecture', uselist=False also can be used instead of back_populates teacher = db.relationship('Teacher', back_populates = 'lecture', uselist=False) # One To One relationship can be converted to only one table def __repr__(self): return '<Lecture %r>' % self.nameclass Book(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(20), nullable=False) teacher_id = db.Column(db.Integer, db.ForeignKey('teacher.id')) def __repr__(self): return '<Book %r>' % self.name.shell_context_processordef make_shell_context(): return { 'db':db, 'Student':Student, 'Teacher':Teacher, 'Lecture':Lecture, 'Book':Book }
Yorumlar