{"id":37849,"date":"2026-01-16T23:41:01","date_gmt":"2026-01-16T20:41:01","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=37849"},"modified":"2026-01-16T23:41:01","modified_gmt":"2026-01-16T20:41:01","slug":"flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/","title":{"rendered":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?"},"content":{"rendered":"<p><body><\/p>\n<h2>Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?<\/h2>\n<p>Veritaban\u0131 tasar\u0131m\u0131, modern web uygulamalar\u0131n\u0131n temel ta\u015flar\u0131ndan biridir ve veriler aras\u0131ndaki ili\u015fkileri do\u011fru bir \u015fekilde modellemek, uygulaman\u0131n esnekli\u011fi, performans\u0131 ve s\u00fcrd\u00fcr\u00fclebilirli\u011fi a\u00e7\u0131s\u0131ndan kritik \u00f6neme sahiptir. Flask gibi hafif ve esnek bir web \u00e7at\u0131s\u0131 ile SQLite gibi sunucusuz bir veritaban\u0131n\u0131 birle\u015ftirdi\u011fimizde, geli\u015ftiricilere h\u0131zl\u0131 prototipleme ve orta \u00f6l\u00e7ekli uygulamalar i\u00e7in g\u00fc\u00e7l\u00fc bir kombinasyon sunulur. Bu makale, Flask ve SQLite ikilisiyle many-to-many (\u00e7oka-\u00e7ok) veritaban\u0131 ili\u015fkilerini nas\u0131l etkili bir \u015fekilde kullanaca\u011f\u0131n\u0131z\u0131 ayr\u0131nt\u0131l\u0131 olarak ele alacakt\u0131r. SQLAlchemy ORM (Object Relational Mapper) k\u00fct\u00fcphanesini kullanarak, karma\u015f\u0131k veritaban\u0131 i\u015flemlerini Python nesneleri arac\u0131l\u0131\u011f\u0131yla nas\u0131l y\u00f6netece\u011fimizi ad\u0131m ad\u0131m inceleyece\u011fiz.<\/p>\n<h3>Many-to-Many \u0130li\u015fkileri Nedir ve Neden \u00d6nemlidir?<\/h3>\n<p>Web uygulamalar\u0131nda, farkl\u0131 veri varl\u0131klar\u0131 (entity) aras\u0131nda \u00e7e\u015fitli ili\u015fkiler bulunur. \u00d6rne\u011fin, bir kullan\u0131c\u0131 birden fazla g\u00f6nderi yazabilir (one-to-many), veya bir g\u00f6nderinin sadece bir yazar\u0131 olabilir (many-to-one). Ancak baz\u0131 senaryolarda, iki varl\u0131k aras\u0131nda daha karma\u015f\u0131k bir ili\u015fki t\u00fcr\u00fc ortaya \u00e7\u0131kar: many-to-many (\u00e7oka-\u00e7ok) ili\u015fkiler.<\/p>\n<h4>Many-to-Many \u0130li\u015fkisinin Tan\u0131m\u0131<\/h4>\n<p>Many-to-many ili\u015fkisi, A varl\u0131\u011f\u0131ndaki her bir \u00f6\u011fenin B varl\u0131\u011f\u0131ndaki birden fazla \u00f6\u011feyle ili\u015fkili olabilece\u011fi ve B varl\u0131\u011f\u0131ndaki her bir \u00f6\u011fenin de A varl\u0131\u011f\u0131ndaki birden fazla \u00f6\u011feyle ili\u015fkili olabilece\u011fi bir durumdur.<\/p>\n<p><strong>\u00d6rnek Senaryolar:<\/strong><\/p>\n<p>*   <strong>Kitaplar ve Yazarlar:<\/strong> Bir kitap birden fazla yazar taraf\u0131ndan yaz\u0131labilir ve bir yazar birden fazla kitap yazabilir.<br \/>\n*   <strong>\u00d6\u011frenciler ve Dersler:<\/strong> Bir \u00f6\u011frenci birden fazla derse kaydolabilir ve bir derse birden fazla \u00f6\u011frenci kaydolabilir.<br \/>\n*   <strong>\u00dcr\u00fcnler ve Kategoriler:<\/strong> Bir \u00fcr\u00fcn birden fazla kategoriye ait olabilir (\u00f6rn. &#8220;Ak\u0131ll\u0131 Telefon&#8221; hem &#8220;Elektronik&#8221; hem de &#8220;Mobil Cihazlar&#8221; kategorisinde yer alabilir) ve bir kategori birden fazla \u00fcr\u00fcn i\u00e7erebilir.<br \/>\n*   <strong>Kullan\u0131c\u0131lar ve Rolleri:<\/strong> Bir kullan\u0131c\u0131 birden fazla role sahip olabilir (\u00f6rn. &#8220;Y\u00f6netici&#8221; ve &#8220;Edit\u00f6r&#8221;) ve bir role birden fazla kullan\u0131c\u0131 atanabilir.<\/p>\n<p>Bu t\u00fcr ili\u015fkiler, ger\u00e7ek d\u00fcnya senaryolar\u0131n\u0131 veritaban\u0131nda do\u011fru bir \u015fekilde temsil etmek i\u00e7in hayati \u00f6neme sahiptir. E\u011fer many-to-many ili\u015fkileri do\u011fru bir \u015fekilde y\u00f6netilmezse, veri tekrar\u0131, tutars\u0131zl\u0131k ve sorgulama zorluklar\u0131 gibi problemlere yol a\u00e7abilir.<\/p>\n<h4>\u0130li\u015fkisel Veritabanlar\u0131nda Many-to-Many \u00c7\u00f6z\u00fcm\u00fc: Ara Tablo (Junction\/Association Table)<\/h4>\n<p>\u0130li\u015fkisel veritaban\u0131 teorisinde, many-to-many ili\u015fkileri do\u011frudan iki ana tablo aras\u0131nda kurulamaz. Bunun yerine, bu t\u00fcr ili\u015fkiler, araya bir &#8220;ara tablo&#8221; (junction table veya association table) eklenerek \u00e7\u00f6z\u00fcl\u00fcr. Ara tablo, her iki ana tablonun birincil anahtarlar\u0131n\u0131 (primary key) yabanc\u0131 anahtar (foreign key) olarak i\u00e7erir. Bu sayede, her bir ana tablonun ara tablo ile one-to-many ili\u015fkisi kurulmu\u015f olur.<\/p>\n<p><strong>\u00d6rnek: Kitaplar ve Yazarlar<\/strong><\/p>\n<p>*   <code>Kitaplar<\/code> tablosu: <code>id<\/code>, <code>ba\u015fl\u0131k<\/code>, <code>yay\u0131n_y\u0131l\u0131<\/code><br \/>\n*   <code>Yazarlar<\/code> tablosu: <code>id<\/code>, <code>ad<\/code>, <code>soyad<\/code><br \/>\n*   <code>kitap_yazar_ili\u015fkisi<\/code> (ara tablo): <code>kitap_id<\/code>, <code>yazar_id<\/code><\/p>\n<p><code>kitap_yazar_ili\u015fkisi<\/code> tablosundaki her bir sat\u0131r, belirli bir kitab\u0131n belirli bir yazarla olan ili\u015fkisini temsil eder. Bu tablo sayesinde, bir kitap birden fazla <code>yazar_id<\/code> ile ili\u015fkilendirilebilir ve bir yazar birden fazla <code>kitap_id<\/code> ile ili\u015fkilendirilebilir.<\/p>\n<h3>Ortam Kurulumu ve Flask-SQLAlchemy Entegrasyonu<\/h3>\n<p>Flask uygulamam\u0131zda many-to-many ili\u015fkilerini y\u00f6netmek i\u00e7in Flask-SQLAlchemy uzant\u0131s\u0131n\u0131 kullanaca\u011f\u0131z. Bu uzant\u0131, SQLAlchemy ORM&#8217;ini Flask ile sorunsuz bir \u015fekilde entegre eder ve veritaban\u0131 i\u015flemlerini Python kodumuz i\u00e7inde daha kolay ve &#8220;Pythonic&#8221; bir \u015fekilde yapmam\u0131z\u0131 sa\u011flar.<\/p>\n<h4>Gerekli K\u00fct\u00fcphaneler<\/h4>\n<p>Ba\u015flamadan \u00f6nce a\u015fa\u011f\u0131daki k\u00fct\u00fcphaneleri y\u00fcklememiz gerekiyor:<\/p>\n<p>*   <code>Flask<\/code>: Web \u00e7at\u0131s\u0131.<br \/>\n*   <code>Flask-SQLAlchemy<\/code>: SQLAlchemy&#8217;yi Flask ile entegre eden uzant\u0131.<br \/>\n*   <code>SQLAlchemy<\/code>: Python i\u00e7in g\u00fc\u00e7l\u00fc bir ORM. (Flask-SQLAlchemy ile birlikte otomatik olarak y\u00fcklenecektir.)<br \/>\n*   <code>sqlite3<\/code>: SQLite veritaban\u0131 s\u00fcr\u00fcc\u00fcs\u00fc. (Python ile birlikte gelir, ayr\u0131ca y\u00fcklemeye gerek yoktur.)<\/p>\n<pre><code class=\"language-bash\">pip install Flask Flask-SQLAlchemy<\/code><\/pre>\n<h4>Proje Yap\u0131s\u0131<\/h4>\n<p>Basit bir proje yap\u0131s\u0131 a\u015fa\u011f\u0131daki gibi olabilir:<\/p>\n<pre><code class=\"language-\">my_app\/\n\u251c\u2500\u2500 app.py\n\u251c\u2500\u2500 models.py\n\u2514\u2500\u2500 instance\/\n    \u2514\u2500\u2500 my_app.sqlite<\/code><\/pre>\n<p>*   <code>app.py<\/code>: Flask uygulamas\u0131n\u0131 ba\u015flatt\u0131\u011f\u0131m\u0131z ve rotalar\u0131 tan\u0131mlad\u0131\u011f\u0131m\u0131z ana dosya.<br \/>\n*   <code>models.py<\/code>: Veritaban\u0131 modellerimizi (tablolar\u0131m\u0131z\u0131) tan\u0131mlad\u0131\u011f\u0131m\u0131z dosya.<br \/>\n*   <code>instance\/my_app.sqlite<\/code>: SQLite veritaban\u0131 dosyam\u0131z burada tutulacak. Flask varsay\u0131lan olarak <code>instance<\/code> klas\u00f6r\u00fcn\u00fc uygulama d\u0131\u015f\u0131 veriler i\u00e7in kullan\u0131r.<\/p>\n<h4>Flask Uygulamas\u0131n\u0131 Ba\u015flatma ve SQLAlchemy Entegrasyonu<\/h4>\n<p>\u0130lk olarak, Flask uygulamas\u0131n\u0131 ba\u015flat\u0131p Flask-SQLAlchemy&#8217;yi entegre edelim.<\/p>\n<pre><code class=\"language-python\"># app.py\nfrom flask import Flask, request, jsonify\nfrom flask_sqlalchemy import SQLAlchemy\nimport os\n\n<h2>Uygulama ve veritaban\u0131 yolu ayarlar\u0131<\/h2>\nbasedir = os.path.abspath(os.path.dirname(__file__))\napp = Flask(__name__)\napp.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:\/\/\/' + os.path.join(basedir, 'instance', 'my_app.sqlite')\napp.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False\n\ndb = SQLAlchemy(app)\n\n<h2>Modelleri i\u00e7eri aktar<\/h2>\nfrom models import * # Modelleri daha sonra models.py i\u00e7inde tan\u0131mlayaca\u011f\u0131z\n\n<h2>Veritaban\u0131n\u0131 olu\u015fturma (sadece bir kez \u00e7al\u0131\u015ft\u0131r\u0131lmal\u0131)<\/h2>\nwith app.app_context():\n    db.create_all()\n\n<h2>... (Rota tan\u0131mlamalar\u0131 buraya gelecek)<\/h2>\n\nif __name__ == '__main__':\n    app.run(debug=True)<\/code><\/pre>\n<p>Bu kod par\u00e7ac\u0131\u011f\u0131, Flask uygulamas\u0131n\u0131 ba\u015flat\u0131r, SQLite veritaban\u0131 dosyas\u0131n\u0131n yolunu ayarlar ve <code>db<\/code> nesnesini olu\u015fturur. <code>db.create_all()<\/code> \u00e7a\u011fr\u0131s\u0131, tan\u0131mlad\u0131\u011f\u0131m\u0131z modelleri kullanarak veritaban\u0131 tablolar\u0131n\u0131 olu\u015fturur. <code>app.app_context()<\/code> i\u00e7inde \u00e7al\u0131\u015ft\u0131r\u0131lmas\u0131 \u00f6nemlidir, \u00e7\u00fcnk\u00fc veritaban\u0131 i\u015flemleri bir uygulama ba\u011flam\u0131 gerektirir.<\/p>\n<h3>\u00d6rnek Senaryo: Kitaplar ve Yazarlar Modelleri<\/h3>\n<p>\u015eimdi, many-to-many ili\u015fkisini somutla\u015ft\u0131rmak i\u00e7in &#8220;Kitaplar&#8221; ve &#8220;Yazarlar&#8221; senaryosunu ele alal\u0131m.<\/p>\n<p>*   Bir <code>Author<\/code> (Yazar) birden fazla <code>Book<\/code> (Kitap) yazabilir.<br \/>\n*   Bir <code>Book<\/code> (Kitap) birden fazla <code>Author<\/code> (Yazar) taraf\u0131ndan yaz\u0131labilir.<\/p>\n<p>Bu ili\u015fkiyi modellemek i\u00e7in bir ara tabloya ihtiyac\u0131m\u0131z olacak.<\/p>\n<h4>Yard\u0131mc\u0131 Tablo (Association Table) Olu\u015fturma<\/h4>\n<p><code>models.py<\/code> dosyas\u0131nda, \u00f6nce ara tabloyu tan\u0131mlamam\u0131z gerekiyor. Bu tablo, <code>db.Table<\/code> kullan\u0131larak olu\u015fturulur ve <code>Column<\/code> nesneleri ile her iki ana tablonun birincil anahtarlar\u0131n\u0131 yabanc\u0131 anahtar olarak i\u00e7erir.<\/p>\n<pre><code class=\"language-python\"># models.py\nfrom app import db # app.py'den db nesnesini i\u00e7eri aktar\u0131yoruz\n\n<h2>Many-to-Many ili\u015fkisi i\u00e7in ara tablo (association table)<\/h2>\n<h2>Bu tablo, Kitaplar ve Yazarlar aras\u0131ndaki ba\u011flant\u0131y\u0131 tutar.<\/h2>\nauthors_books = db.Table('authors_books',\n    db.Column('author_id', db.Integer, db.ForeignKey('author.id'), primary_key=True),\n    db.Column('book_id', db.Integer, db.ForeignKey('book.id'), primary_key=True)\n)<\/code><\/pre>\n<p>Bu <code>authors_books<\/code> tablosu, <code>author.id<\/code> ve <code>book.id<\/code> s\u00fctunlar\u0131n\u0131 i\u00e7erir. Her iki s\u00fctun da birincil anahtar\u0131n par\u00e7as\u0131d\u0131r (<code>primary_key=True<\/code>), bu da ayn\u0131 yazar\u0131n ayn\u0131 kitab\u0131 birden fazla kez yazamayaca\u011f\u0131 anlam\u0131na gelir (mant\u0131ksal olarak do\u011fru). Ayr\u0131ca, bu s\u00fctunlar s\u0131ras\u0131yla <code>author<\/code> ve <code>book<\/code> tablolar\u0131na yabanc\u0131 anahtar olarak ba\u011flanm\u0131\u015ft\u0131r.<\/p>\n<h4><code>Author<\/code> Modeli Tan\u0131mlama<\/h4>\n<p><code>Author<\/code> modelini tan\u0131mlarken, <code>db.relationship<\/code> kullanarak <code>Book<\/code> modeliyle olan many-to-many ili\u015fkisini belirtmemiz gerekir.<\/p>\n<pre><code class=\"language-python\"># models.py devam\u0131\nclass Author(db.Model):\n    id = db.Column(db.Integer, primary_key=True)\n    name = db.Column(db.String(100), nullable=False)\n\n    # Many-to-Many ili\u015fkisi: Bir yazar\u0131n birden fazla kitab\u0131 olabilir.\n    # 'secondary' arg\u00fcman\u0131, ara tabloyu belirtir.\n    # 'back_populates' ise Book modelindeki 'authors' ili\u015fkisini geri ba\u011flar.\n    books = db.relationship('Book', secondary=authors_books, lazy='subquery',\n                            back_populates='authors')\n\n    def __repr__(self):\n        return f'<Author {self.name}>'\n\n    def to_dict(self):\n        return {\n            'id': self.id,\n            'name': self.name,\n            'books': [book.to_dict_simple() for book in self.books]\n        }\n    \n    def to_dict_simple(self):\n        return {\n            'id': self.id,\n            'name': self.name\n        }<\/code><\/pre>\n<p>*   <code>books = db.relationship('Book', ...)<\/code>: Bu sat\u0131r, <code>Author<\/code> modeli ile <code>Book<\/code> modeli aras\u0131nda bir ili\u015fki kurar.<br \/>\n*   <code>secondary=authors_books<\/code>: Bu arg\u00fcman, many-to-many ili\u015fkisini kurmak i\u00e7in kullan\u0131lan ara tabloyu (daha \u00f6nce tan\u0131mlad\u0131\u011f\u0131m\u0131z <code>authors_books<\/code>) belirtir.<br \/>\n*   <code>lazy='subquery'<\/code>: Bu, ilgili kitaplar\u0131n yazar sorguland\u0131\u011f\u0131nda hemen y\u00fcklenmesini sa\u011flar, ancak daha verimli bir \u015fekilde (tek bir sorguda alt sorgu kullanarak) yapar. Di\u011fer se\u00e7enekler <code>select<\/code> (her kitap i\u00e7in ayr\u0131 sorgu, N+1 problemi), <code>joined<\/code> (JOIN kullanarak tek sorgu) veya <code>dynamic<\/code> (ili\u015fkiyi sorgulanabilir bir nesne olarak d\u00f6nd\u00fcr\u00fcr) olabilir.<br \/>\n*   <code>back_populates='authors'<\/code>: Bu, <code>Book<\/code> modelindeki <code>authors<\/code> ili\u015fkisinin bu <code>books<\/code> ili\u015fkisiyle \u00e7ift y\u00f6nl\u00fc oldu\u011funu belirtir. Bu, bir yazar\u0131n kitaplar\u0131n\u0131 ekledi\u011finizde, kitab\u0131n yazarlar listesine de otomatik olarak yazar\u0131n eklenmesini sa\u011flar.<br \/>\n*   <code>to_dict<\/code> ve <code>to_dict_simple<\/code> metotlar\u0131, model nesnelerini JSON&#8217;a d\u00f6n\u00fc\u015ft\u00fcrmek i\u00e7in yard\u0131mc\u0131 fonksiyonlard\u0131r. <code>to_dict_simple<\/code> sonsuz d\u00f6ng\u00fcy\u00fc engellemek i\u00e7in kullan\u0131l\u0131r (bir kitap yazarlar\u0131 listelerken yazar da kitaplar\u0131 listelerse).<\/p>\n<h4><code>Book<\/code> Modeli Tan\u0131mlama<\/h4>\n<p>Benzer \u015fekilde, <code>Book<\/code> modelini de <code>Author<\/code> modeliyle olan many-to-many ili\u015fkisini belirterek tan\u0131mlar\u0131z.<\/p>\n<pre><code class=\"language-python\"># models.py devam\u0131\nclass Book(db.Model):\n    id = db.Column(db.Integer, primary_key=True)\n    title = db.Column(db.String(200), nullable=False)\n    publication_year = db.Column(db.Integer)\n\n    # Many-to-Many ili\u015fkisi: Bir kitab\u0131n birden fazla yazar\u0131 olabilir.\n    # 'secondary' arg\u00fcman\u0131, ara tabloyu belirtir.\n    # 'back_populates' ise Author modelindeki 'books' ili\u015fkisini geri ba\u011flar.\n    authors = db.relationship('Author', secondary=authors_books, lazy='subquery',\n                              back_populates='books')\n\n    def __repr__(self):\n        return f'<Book {self.title}>'\n\n    def to_dict(self):\n        return {\n            'id': self.id,\n            'title': self.title,\n            'publication_year': self.publication_year,\n            'authors': [author.to_dict_simple() for author in self.authors]\n        }\n    \n    def to_dict_simple(self):\n        return {\n            'id': self.id,\n            'title': self.title\n        }<\/code><\/pre>\n<p><code>Book<\/code> modelindeki <code>authors<\/code> ili\u015fkisi, <code>Author<\/code> modelindeki <code>books<\/code> ili\u015fkisiyle tamamen ayn\u0131 mant\u0131kla \u00e7al\u0131\u015f\u0131r. <code>back_populates<\/code> sayesinde, bir <code>Book<\/code> nesnesine bir <code>Author<\/code> ekledi\u011finizde, o <code>Author<\/code> nesnesinin <code>books<\/code> listesine de ilgili <code>Book<\/code> nesnesi otomatik olarak eklenir.<\/p>\n<h3>Veritaban\u0131 \u0130\u015flemleri: Ekleme, Sorgulama, G\u00fcncelleme, Silme<\/h3>\n<p>Modellerimizi tan\u0131mlad\u0131\u011f\u0131m\u0131za g\u00f6re, \u015fimdi bu modellerle veritaban\u0131nda nas\u0131l CRUD (Create, Read, Update, Delete) i\u015flemleri yapaca\u011f\u0131m\u0131za bakal\u0131m.<\/p>\n<h4>Veri Ekleme (Creating Data)<\/h4>\n<p>Yeni yazarlar ve kitaplar olu\u015fturup, aralar\u0131ndaki many-to-many ili\u015fkileri kurmak olduk\u00e7a basittir.<\/p>\n<pre><code class=\"language-python\"># app.py veya ayr\u0131 bir script i\u00e7inde \u00e7al\u0131\u015ft\u0131r\u0131labilir\nfrom app import app, db\nfrom models import Author, Book\n\nwith app.app_context():\n    # Yazarlar olu\u015fturma\n    author1 = Author(name='George Orwell')\n    author2 = Author(name='Aldous Huxley')\n    author3 = Author(name='Margaret Atwood')\n    author4 = Author(name='J.R.R. Tolkien')\n\n    # Kitaplar olu\u015fturma\n    book1 = Book(title='1984', publication_year=1949)\n    book2 = Book(title='Animal Farm', publication_year=1945)\n    book3 = Book(title='Brave New World', publication_year=1932)\n    book4 = Book(title='The Handmaid\\'s Tale', publication_year=1985)\n    book5 = Book(title='The Lord of the Rings', publication_year=1954)\n\n    # Kitaplar\u0131 yazarlara atayarak ili\u015fkileri kurma\n    author1.books.append(book1)\n    author1.books.append(book2)\n\n    author2.books.append(book3)\n\n    author3.books.append(book4)\n\n    author4.books.append(book5)\n\n    # \u00d6rnek: Birden fazla yazarl\u0131 kitap\n    # Diyelim ki 'The Silmarillion' Tolkien ve o\u011flu Christopher taraf\u0131ndan yaz\u0131ld\u0131 (basitle\u015ftirilmi\u015f)\n    book6 = Book(title='The Silmarillion', publication_year=1977)\n    author4.books.append(book6)\n    \n    # Yeni bir yazar ekleyelim ve bu kitaba ba\u011flayal\u0131m (\u00f6rnek ama\u00e7l\u0131)\n    author5 = Author(name='Christopher Tolkien')\n    author5.books.append(book6)\n\n\n    # T\u00fcm nesneleri veritaban\u0131na ekle\n    db.session.add_all([author1, author2, author3, author4, author5, book1, book2, book3, book4, book5, book6])\n    db.session.commit()\n\n    print(\"\u00d6rnek veriler ba\u015far\u0131yla eklendi.\")<\/code><\/pre>\n<p>Burada dikkat edilmesi gereken nokta, <code>author.books.append(book)<\/code> veya <code>book.authors.append(author)<\/code> kullanarak ili\u015fkileri kurmam\u0131zd\u0131r. SQLAlchemy, <code>back_populates<\/code> sayesinde bu i\u015flemi \u00e7ift y\u00f6nl\u00fc olarak otomatik y\u00f6netir. Yani, <code>author1.books.append(book1)<\/code> dedi\u011fimizde, <code>book1.authors<\/code> listesine de <code>author1<\/code> otomatik olarak eklenir. <code>db.session.add_all()<\/code> ile t\u00fcm nesneleri oturuma ekledikten sonra <code>db.session.commit()<\/code> ile de\u011fi\u015fiklikleri veritaban\u0131na kal\u0131c\u0131 olarak kaydederiz.<\/p>\n<h4>Veri Sorgulama (Querying Data)<\/h4>\n<p>\u0130li\u015fkisel verileri sorgulamak, many-to-many ili\u015fkilerinin en g\u00fc\u00e7l\u00fc y\u00f6nlerinden biridir.<\/p>\n<pre><code class=\"language-python\"># app.py veya ayr\u0131 bir script i\u00e7inde \u00e7al\u0131\u015ft\u0131r\u0131labilir\nfrom app import app, db\nfrom models import Author, Book\n\nwith app.app_context():\n    # T\u00fcm yazarlar\u0131 ve kitaplar\u0131n\u0131 sorgula\n    all_authors = Author.query.all()\n    print(\"\\nT\u00fcm Yazarlar ve Kitaplar\u0131:\")\n    for author in all_authors:\n        print(f\"Yazar: {author.name}\")\n        for book in author.books:\n            print(f\"  - Kitap: {book.title} ({book.publication_year})\")\n\n    # Belirli bir yazar\u0131 ve kitaplar\u0131n\u0131 sorgula\n    george = Author.query.filter_by(name='George Orwell').first()\n    if george:\n        print(f\"\\n{george.name} taraf\u0131ndan yaz\u0131lan kitaplar:\")\n        for book in george.books:\n            print(f\"  - {book.title} ({book.publication_year})\")\n\n    # T\u00fcm kitaplar\u0131 ve yazarlar\u0131n\u0131 sorgula\n    all_books = Book.query.all()\n    print(\"\\nT\u00fcm Kitaplar ve Yazarlar\u0131:\")\n    for book in all_books:\n        author_names = \", \".join([a.name for a in book.authors])\n        print(f\"Kitap: {book.title} ({book.publication_year}) - Yazarlar: {author_names}\")\n\n    # Belirli bir kitab\u0131 ve yazarlar\u0131n\u0131 sorgula\n    lotr = Book.query.filter_by(title='The Lord of the Rings').first()\n    if lotr:\n        author_names = \", \".join([a.name for a in lotr.authors])\n        print(f\"\\n'{lotr.title}' kitab\u0131n\u0131n yazarlar\u0131: {author_names}\")\n\n    # Belirli bir yazar\u0131n yazd\u0131\u011f\u0131 belirli bir kitab\u0131 bulma (join ile)\n    # Bu daha \u00e7ok bir SQL JOIN \u00f6rne\u011fi gibi ama ORM ile de yap\u0131labilir\n    book_by_author = Book.query.join(authors_books).join(Author).filter(\n        Author.name == 'George Orwell',\n        Book.title == '1984'\n    ).first()\n    if book_by_author:\n        print(f\"\\nGeorge Orwell'\u0131n yazd\u0131\u011f\u0131 '1984' kitab\u0131 bulundu: {book_by_author.title}\")<\/code><\/pre>\n<p><code>author.books<\/code> veya <code>book.authors<\/code> niteliklerine eri\u015fti\u011fimizde, SQLAlchemy otomatik olarak ili\u015fkili nesneleri veritaban\u0131ndan \u00e7eker (lazy loading stratejisine g\u00f6re). <code>lazy='subquery'<\/code> kulland\u0131\u011f\u0131m\u0131z i\u00e7in, ilgili veriler ana sorguyla birlikte daha verimli bir \u015fekilde \u00e7ekilecektir.<\/p>\n<h4>Veri G\u00fcncelleme (Updating Data)<\/h4>\n<p>\u0130li\u015fkileri g\u00fcncellemek, mevcut nesnelerin ili\u015fki listelerini de\u011fi\u015ftirmek anlam\u0131na gelir.<\/p>\n<pre><code class=\"language-python\"># app.py veya ayr\u0131 bir script i\u00e7inde \u00e7al\u0131\u015ft\u0131r\u0131labilir\nfrom app import app, db\nfrom models import Author, Book\n\nwith app.app_context():\n    # Bir kitab\u0131n yay\u0131n y\u0131l\u0131n\u0131 g\u00fcncelleme\n    book_to_update = Book.query.filter_by(title='1984').first()\n    if book_to_update:\n        book_to_update.publication_year = 1950 # Yanl\u0131\u015fl\u0131kla g\u00fcncelleyelim\n        db.session.commit()\n        print(f\"\\n'{book_to_update.title}' kitab\u0131n\u0131n yay\u0131n y\u0131l\u0131 g\u00fcncellendi: {book_to_update.publication_year}\")\n\n    # Bir kitab\u0131n yazar listesini g\u00fcncelleme (yeni yazar ekleme)\n    silmarillion = Book.query.filter_by(title='The Silmarillion').first()\n    if silmarillion:\n        # Diyelim ki J.R.R. Tolkien'in ba\u015fka bir ortak yazar\u0131 var\n        new_author = Author(name='Another Co-Author')\n        db.session.add(new_author) # Yeni yazar\u0131 \u00f6nce veritaban\u0131na eklemeliyiz\n        silmarillion.authors.append(new_author)\n        db.session.commit()\n        print(f\"\\n'{silmarillion.title}' kitab\u0131na yeni yazar eklendi.\")\n        print(f\"Yeni yazarlar: {[a.name for a in silmarillion.authors]}\")\n\n    # Bir kitab\u0131n yazar listesinden yazar \u00e7\u0131karma\n    if silmarillion:\n        christopher = Author.query.filter_by(name='Christopher Tolkien').first()\n        if christopher and christopher in silmarillion.authors:\n            silmarillion.authors.remove(christopher)\n            db.session.commit()\n            print(f\"\\n'{silmarillion.title}' kitab\u0131ndan Christopher Tolkien \u00e7\u0131kar\u0131ld\u0131.\")\n            print(f\"Kalan yazarlar: {[a.name for a in silmarillion.authors]}\")<\/code><\/pre>\n<p>\u0130li\u015fkili nesneleri eklemek i\u00e7in <code>.append()<\/code> kullan\u0131rken, \u00e7\u0131karmak i\u00e7in <code>.remove()<\/code> kullan\u0131r\u0131z. SQLAlchemy, bu de\u011fi\u015fiklikleri ara tabloda otomatik olarak yans\u0131t\u0131r.<\/p>\n<h4>Veri Silme (Deleting Data)<\/h4>\n<p>Bir ana nesneyi sildi\u011fimizde, ili\u015fkilerin nas\u0131l etkilenece\u011fi \u00f6nemlidir. SQLAlchemy&#8217;de <code>cascade<\/code> se\u00e7enekleri ile bu davran\u0131\u015f kontrol edilebilir. Varsay\u0131lan olarak, bir yazar silindi\u011finde, yazar ile ilgili kitap ili\u015fkileri (ara tablodaki kay\u0131tlar) silinir, ancak kitap nesneleri silinmez.<\/p>\n<pre><code class=\"language-python\"># app.py veya ayr\u0131 bir script i\u00e7inde \u00e7al\u0131\u015ft\u0131r\u0131labilir\nfrom app import app, db\nfrom models import Author, Book\n\nwith app.app_context():\n    # Bir yazar\u0131 silme\n    author_to_delete = Author.query.filter_by(name='Aldous Huxley').first()\n    if author_to_delete:\n        db.session.delete(author_to_delete)\n        db.session.commit()\n        print(f\"\\n'{author_to_delete.name}' yazar\u0131 silindi.\")\n        # 'Brave New World' kitab\u0131n\u0131n yazarlar\u0131n\u0131 kontrol edelim\n        brave_new_world = Book.query.filter_by(title='Brave New World').first()\n        if brave_new_world:\n            print(f\"'{brave_new_world.title}' kitab\u0131n\u0131n kalan yazarlar\u0131: {[a.name for a in brave_new_world.authors]}\")\n        else:\n            print(f\"'{brave_new_world.title}' kitab\u0131 bulunamad\u0131.\") # Kitap silinmedi\u011fi i\u00e7in bulunacak\n\n    # Bir kitab\u0131 silme\n    book_to_delete = Book.query.filter_by(title='Animal Farm').first()\n    if book_to_delete:\n        db.session.delete(book_to_delete)\n        db.session.commit()\n        print(f\"\\n'{book_to_delete.title}' kitab\u0131 silindi.\")\n        # George Orwell'\u0131n kitaplar\u0131n\u0131 kontrol edelim\n        george = Author.query.filter_by(name='George Orwell').first()\n        if george:\n            print(f\"'{george.name}' yazar\u0131n\u0131n kalan kitaplar\u0131: {[b.title for b in george.books]}\")<\/code><\/pre>\n<p>Varsay\u0131lan <code>cascade<\/code> davran\u0131\u015f\u0131, bir nesne silindi\u011finde sadece o nesneyi ve ara tablodaki ilgili ili\u015fki kay\u0131tlar\u0131n\u0131 siler. Ba\u011flant\u0131l\u0131 nesneler (\u00f6rne\u011fin, bir yazar silindi\u011finde kitaplar) silinmez. E\u011fer bir yazar silindi\u011finde yazd\u0131\u011f\u0131 t\u00fcm kitaplar\u0131n da silinmesini istiyorsan\u0131z, <code>db.relationship<\/code> tan\u0131m\u0131na <code>cascade=\"all, delete-orphan\"<\/code> gibi se\u00e7enekler eklemeniz gerekir. Ancak bu, many-to-many ili\u015fkilerinde genellikle istenmeyen bir durumdur, \u00e7\u00fcnk\u00fc bir kitap birden fazla yazara ait olabilir ve bir yazar silindi\u011finde di\u011fer yazarlar\u0131n kitaplar\u0131n\u0131n da silinmesi mant\u0131ks\u0131z olur.<\/p>\n<h3>Flask Uygulamas\u0131na Entegre Etme: Basit Bir API<\/h3>\n<p>\u015eimdi, bu veritaban\u0131 i\u015flemlerini Flask rotalar\u0131 arac\u0131l\u0131\u011f\u0131yla nas\u0131l bir web API&#8217;sine d\u00f6n\u00fc\u015ft\u00fcrece\u011fimize bakal\u0131m.<\/p>\n<pre><code class=\"language-python\"># app.py devam\u0131\nfrom flask import Flask, request, jsonify\nfrom flask_sqlalchemy import SQLAlchemy\nimport os\nfrom models import Author, Book, authors_books # models.py'den import ediyoruz\n\n<h2>... (Uygulama ve db tan\u0131mlamalar\u0131 yukar\u0131da yap\u0131ld\u0131)<\/h2>\n\n<h2>Ana sayfa (sadece test i\u00e7in)<\/h2>\n@app.route('\/')\ndef index():\n    return \"Flask Many-to-Many \u0130li\u015fkileri API'si\"\n\n<h2>T\u00fcm yazarlar\u0131 listele<\/h2>\n@app.route('\/authors', methods=['GET'])\ndef get_authors():\n    authors = Author.query.all()\n    return jsonify([author.to_dict() for author in authors])\n\n<h2>Belirli bir yazar\u0131 ve kitaplar\u0131n\u0131 g\u00f6ster<\/h2>\n@app.route('\/authors\/<int:author_id>', methods=['GET'])\ndef get_author(author_id):\n    author = Author.query.get_or_404(author_id)\n    return jsonify(author.to_dict())\n\n<h2>Yeni yazar ekle<\/h2>\n@app.route('\/authors', methods=['POST'])\ndef add_author():\n    data = request.get_json()\n    if not data or not 'name' in data:\n        return jsonify({'message': 'Yazar ad\u0131 gerekli'}), 400\n    \n    new_author = Author(name=data['name'])\n    db.session.add(new_author)\n    db.session.commit()\n    return jsonify(new_author.to_dict()), 201\n\n<h2>Bir yazar\u0131 g\u00fcncelle<\/h2>\n@app.route('\/authors\/<int:author_id>', methods=['PUT'])\ndef update_author(author_id):\n    author = Author.query.get_or_404(author_id)\n    data = request.get_json()\n    if 'name' in data:\n        author.name = data['name']\n    db.session.commit()\n    return jsonify(author.to_dict())\n\n<h2>Bir yazar\u0131 sil<\/h2>\n@app.route('\/authors\/<int:author_id>', methods=['DELETE'])\ndef delete_author(author_id):\n    author = Author.query.get_or_404(author_id)\n    db.session.delete(author)\n    db.session.commit()\n    return jsonify({'message': 'Yazar ba\u015far\u0131yla silindi'}), 200\n\n<h2>T\u00fcm kitaplar\u0131 listele<\/h2>\n@app.route('\/books', methods=['GET'])\ndef get_books():\n    books = Book.query.all()\n    return jsonify([book.to_dict() for book in books])\n\n<h2>Belirli bir kitab\u0131 ve yazarlar\u0131n\u0131 g\u00f6ster<\/h2>\n@app.route('\/books\/<int:book_id>', methods=['GET'])\ndef get_book(book_id):\n    book = Book.query.get_or_404(book_id)\n    return jsonify(book.to_dict())\n\n<h2>Yeni kitap ekle ve yazarlar\u0131yla ili\u015fkilendir<\/h2>\n@app.route('\/books', methods=['POST'])\ndef add_book():\n    data = request.get_json()\n    if not data or not 'title' in data or not 'publication_year' in data:\n        return jsonify({'message': 'Kitap ba\u015fl\u0131\u011f\u0131 ve yay\u0131n y\u0131l\u0131 gerekli'}), 400\n    \n    new_book = Book(title=data['title'], publication_year=data['publication_year'])\n\n    # E\u011fer yazar ID'leri sa\u011fland\u0131ysa, yazarlar\u0131 bul ve kitaba ekle\n    if 'author_ids' in data and isinstance(data['author_ids'], list):\n        for author_id in data['author_ids']:\n            author = Author.query.get(author_id)\n            if author:\n                new_book.authors.append(author)\n    \n    db.session.add(new_book)\n    db.session.commit()\n    return jsonify(new_book.to_dict()), 201\n\n<h2>Bir kitab\u0131 g\u00fcncelle<\/h2>\n@app.route('\/books\/<int:book_id>', methods=['PUT'])\ndef update_book(book_id):\n    book = Book.query.get_or_404(book_id)\n    data = request.get_json()\n    \n    if 'title' in data:\n        book.title = data['title']\n    if 'publication_year' in data:\n        book.publication_year = data['publication_year']\n    \n    # Yazarlar\u0131 g\u00fcncelleme (tamamen de\u011fi\u015ftirme veya ekleme\/\u00e7\u0131karma)\n    if 'author_ids' in data and isinstance(data['author_ids'], list):\n        book.authors = [] # Mevcut t\u00fcm yazarlar\u0131 kald\u0131r\n        for author_id in data['author_ids']:\n            author = Author.query.get(author_id)\n            if author:\n                book.authors.append(author) # Yeni yazarlar\u0131 ekle\n    \n    db.session.commit()\n    return jsonify(book.to_dict())\n\n<h2>Bir kitab\u0131 sil<\/h2>\n@app.route('\/books\/<int:book_id>', methods=['DELETE'])\ndef delete_book(book_id):\n    book = Book.query.get_or_404(book_id)\n    db.session.delete(book)\n    db.session.commit()\n    return jsonify({'message': 'Kitap ba\u015far\u0131yla silindi'}), 200\n\n<h2>Bir kitaba yazar ekle (belirli bir kitap ve yazar ID'si ile)<\/h2>\n@app.route('\/books\/<int:book_id>\/authors\/<int:author_id>', methods=['POST'])\ndef add_author_to_book(book_id, author_id):\n    book = Book.query.get_or_404(book_id)\n    author = Author.query.get_or_404(author_id)\n\n    if author not in book.authors:\n        book.authors.append(author)\n        db.session.commit()\n        return jsonify(book.to_dict()), 200\n    return jsonify({'message': 'Bu yazar zaten bu kitaba atanm\u0131\u015f'}), 409 # Conflict\n\n<h2>Bir kitaptan yazar \u00e7\u0131kar (belirli bir kitap ve yazar ID'si ile)<\/h2>\n@app.route('\/books\/<int:book_id>\/authors\/<int:author_id>', methods=['DELETE'])\ndef remove_author_from_book(book_id, author_id):\n    book = Book.query.get_or_404(book_id)\n    author = Author.query.get_or_404(author_id)\n\n    if author in book.authors:\n        book.authors.remove(author)\n        db.session.commit()\n        return jsonify(book.to_dict()), 200\n    return jsonify({'message': 'Bu yazar bu kitaba atanmam\u0131\u015f'}), 404 # Not Found\n\n\n<h2>... (Uygulama \u00e7al\u0131\u015ft\u0131rma blo\u011fu yukar\u0131da yap\u0131ld\u0131)<\/h2>\nif __name__ == '__main__':\n    app.run(debug=True)<\/code><\/pre>\n<p>Bu Flask API&#8217;si, bir\u00e7ok temel i\u015flemi kapsar:<br \/>\n*   <strong>GET \/authors<\/strong>: T\u00fcm yazarlar\u0131 ve onlar\u0131n kitaplar\u0131n\u0131 listeler.<br \/>\n*   <strong>GET \/authors\/<id><\/strong>: Belirli bir yazar\u0131 ve onun kitaplar\u0131n\u0131 g\u00f6sterir.<br \/>\n*   <strong>POST \/authors<\/strong>: Yeni bir yazar olu\u015fturur.<br \/>\n*   <strong>PUT \/authors\/<id><\/strong>: Bir yazar\u0131n bilgilerini g\u00fcnceller.<br \/>\n*   <strong>DELETE \/authors\/<id><\/strong>: Bir yazar\u0131 siler.<br \/>\n*   <strong>GET \/books<\/strong>: T\u00fcm kitaplar\u0131 ve onlar\u0131n yazarlar\u0131n\u0131 listeler.<br \/>\n*   <strong>GET \/books\/<id><\/strong>: Belirli bir kitab\u0131 ve onun yazarlar\u0131n\u0131 g\u00f6sterir.<br \/>\n*   <strong>POST \/books<\/strong>: Yeni bir kitap olu\u015fturur ve iste\u011fe ba\u011fl\u0131 olarak yazar ID&#8217;leri listesi ile yazarlar\u0131yla ili\u015fkilendirir.<br \/>\n*   <strong>PUT \/books\/<id><\/strong>: Bir kitab\u0131n bilgilerini veya yazar listesini g\u00fcnceller.<br \/>\n*   <strong>DELETE \/books\/<id><\/strong>: Bir kitab\u0131 siler.<br \/>\n*   <strong>POST \/books\/<book_id>\/authors\/<author_id><\/strong>: Belirli bir kitab\u0131 belirli bir yazara ba\u011flar.<br \/>\n*   <strong>DELETE \/books\/<book_id>\/authors\/<author_id><\/strong>: Belirli bir kitab\u0131n belirli bir yazarla olan ba\u011flant\u0131s\u0131n\u0131 kald\u0131r\u0131r.<\/p>\n<p><code>request.get_json()<\/code> ile gelen JSON verilerini i\u015fleriz ve <code>jsonify()<\/code> ile Python nesnelerini JSON yan\u0131tlar\u0131na d\u00f6n\u00fc\u015ft\u00fcr\u00fcr\u00fcz. Modellerimizdeki <code>to_dict()<\/code> ve <code>to_dict_simple()<\/code> metotlar\u0131 bu d\u00f6n\u00fc\u015f\u00fcm\u00fc kolayla\u015ft\u0131r\u0131r ve sonsuz d\u00f6ng\u00fcleri engeller.<\/p>\n<h3>Geli\u015fmi\u015f Konular ve En \u0130yi Uygulamalar<\/h3>\n<p>Many-to-many ili\u015fkilerini kullan\u0131rken dikkate al\u0131nmas\u0131 gereken baz\u0131 geli\u015fmi\u015f konular ve en iyi uygulamalar bulunmaktad\u0131r:<\/p>\n<h4><code>lazy<\/code> Y\u00fckleme Stratejileri ve N+1 Problemi<\/h4>\n<p><code>db.relationship<\/code> tan\u0131m\u0131nda kullan\u0131lan <code>lazy<\/code> arg\u00fcman\u0131, ili\u015fkili verilerin ne zaman y\u00fcklenece\u011fini belirler.<br \/>\n*   <code>lazy='select'<\/code> (varsay\u0131lan): \u0130li\u015fkili verilere her eri\u015fildi\u011finde ayr\u0131 bir SELECT sorgusu \u00e7al\u0131\u015ft\u0131r\u0131r. N adet ana nesne varsa, N+1 sorguya neden olabilir (N+1 problemi). Performans a\u00e7\u0131s\u0131ndan genellikle k\u00f6t\u00fcd\u00fcr.<br \/>\n*   <code>lazy='joined'<\/code>: \u0130li\u015fkili verileri ana sorguyla birlikte bir JOIN kullanarak y\u00fckler. Genellikle daha verimlidir, ancak \u00e7ok fazla JOIN gerektiren karma\u015f\u0131k senaryolarda sorguyu b\u00fcy\u00fctebilir.<br \/>\n*   <code>lazy='subquery'<\/code>: \u0130li\u015fkili verileri ayr\u0131 bir alt sorgu kullanarak y\u00fckler. <code>joined<\/code> kadar olmasa da \u00e7o\u011fu durumda verimlidir.<br \/>\n*   <code>lazy='dynamic'<\/code>: \u0130li\u015fkili nesneleri do\u011frudan y\u00fcklemez, bunun yerine sorgulanabilir bir nesne d\u00f6nd\u00fcr\u00fcr. Bu, ili\u015fkili nesneler \u00fczerinde ek filtreleme veya s\u0131ralama yapmak istedi\u011finizde kullan\u0131\u015fl\u0131d\u0131r.<\/p>\n<p>B\u00fcy\u00fck veri k\u00fcmeleriyle \u00e7al\u0131\u015f\u0131rken N+1 problemini \u00f6nlemek i\u00e7in <code>joinedload<\/code> veya <code>subqueryload<\/code> gibi <code>eager loading<\/code> tekniklerini kullanmak \u00f6nemlidir. \u00d6rne\u011fin:<\/p>\n<pre><code class=\"language-python\">authors = Author.query.options(db.joinedload(Author.books)).all()\n<h2>veya<\/h2>\nauthors = Author.query.options(db.subqueryload(Author.books)).all()<\/code><\/pre>\n<p>Bu, t\u00fcm yazarlar\u0131 ve ilgili kitaplar\u0131n\u0131 tek bir sorguda veya daha az sorguda \u00e7eker.<\/p>\n<h4>Ara Tabloda Ek S\u00fctunlar (Association Object)<\/h4>\n<p>Bazen ara tabloda sadece iki ana tablonun ID&#8217;lerini tutmak yeterli olmaz. \u00d6rne\u011fin, bir \u00f6\u011frencinin bir derse ne zaman kaydoldu\u011fu veya bir yazar\u0131n bir kitab\u0131 yazmaya ne zaman ba\u015flad\u0131\u011f\u0131 gibi ek bilgiler ara tabloda tutulmak istenebilir. Bu durumda, <code>db.Table<\/code> yerine \u00f6zel bir &#8220;ili\u015fki modeli&#8221; (association object) olu\u015fturulur.<\/p>\n<pre><code class=\"language-python\"># models.py i\u00e7inde\nclass AuthorBookAssociation(db.Model):\n    __tablename__ = 'author_book_association'\n    author_id = db.Column(db.Integer, db.ForeignKey('author.id'), primary_key=True)\n    book_id = db.Column(db.Integer, db.ForeignKey('book.id'), primary_key=True)\n    contribution_date = db.Column(db.DateTime, default=db.func.current_timestamp()) # Ek s\u00fctun\n\n    author = db.relationship('Author', back_populates='book_associations')\n    book = db.relationship('Book', back_populates='author_associations')\n\nclass Author(db.Model):\n    # ... di\u011fer s\u00fctunlar ...\n    book_associations = db.relationship('AuthorBookAssociation', back_populates='author')\n    books = association_proxy('book_associations', 'book') # Daha temiz eri\u015fim i\u00e7in\n\nclass Book(db.Model):\n    # ... di\u011fer s\u00fctunlar ...\n    author_associations = db.relationship('AuthorBookAssociation', back_populates='book')\n    authors = association_proxy('author_associations', 'author') # Daha temiz eri\u015fim i\u00e7in<\/code><\/pre>\n<p>Bu yakla\u015f\u0131m, ara tabloda ek veriler saklaman\u0131za olanak tan\u0131r ve <code>association_proxy<\/code> ile ili\u015fkilere daha temiz bir \u015fekilde eri\u015fim sa\u011flayabilirsiniz.<\/p>\n<h4>Validasyon ve Hata Y\u00f6netimi<\/h4>\n<p>API u\u00e7 noktalar\u0131n\u0131za gelen verileri her zaman do\u011frulamal\u0131s\u0131n\u0131z. \u00d6rne\u011fin, bir yazar eklerken ad\u0131n bo\u015f olmamas\u0131n\u0131 veya belirli bir uzunlukta olmas\u0131n\u0131 sa\u011flamak gibi. Flask-WTF veya Marshmallow gibi k\u00fct\u00fcphaneler, veri validasyonu ve serile\u015ftirmeyi kolayla\u015ft\u0131rabilir. Hata durumlar\u0131nda uygun HTTP durum kodlar\u0131 (400 Bad Request, 404 Not Found, 409 Conflict vb.) d\u00f6nd\u00fcrmek \u00f6nemlidir.<\/p>\n<h4>Veritaban\u0131 Migrasyonlar\u0131 (Alembic)<\/h4>\n<p>Uygulaman\u0131z geli\u015ftik\u00e7e veritaban\u0131 \u015feman\u0131z de\u011fi\u015fecektir (yeni s\u00fctunlar, yeni tablolar, indeksler vb.). Flask-Migrate (Alembic \u00fczerine kurulu) gibi ara\u00e7lar, veritaban\u0131 \u015fema de\u011fi\u015fikliklerini y\u00f6netmenize ve \u00fcretim ortam\u0131nda g\u00fcvenli bir \u015fekilde uygulaman\u0131za olanak tan\u0131r.<\/p>\n<h3>Sonu\u00e7<\/h3>\n<p>Flask ve SQLite ile many-to-many veritaban\u0131 ili\u015fkilerini y\u00f6netmek, Flask-SQLAlchemy&#8217;nin g\u00fc\u00e7l\u00fc ORM yetenekleri sayesinde olduk\u00e7a kolay ve sezgiseldir. Ara tablo kavram\u0131n\u0131 anlayarak, modellerinizi do\u011fru bir \u015fekilde tan\u0131mlayarak ve CRUD i\u015flemlerini uygulayarak, karma\u015f\u0131k ger\u00e7ek d\u00fcnya senaryolar\u0131n\u0131 veritaban\u0131n\u0131zda etkili bir \u015fekilde modelleyebilirsiniz.<\/p>\n<p>Bu makalede ele ald\u0131\u011f\u0131m\u0131z ad\u0131mlar ve \u00f6rnek kodlar, Flask uygulaman\u0131zda \u00e7oka-\u00e7ok ili\u015fkilerini ba\u015far\u0131yla uygulaman\u0131z i\u00e7in sa\u011flam bir temel sunmaktad\u0131r. Performans optimizasyonlar\u0131, geli\u015fmi\u015f ili\u015fki y\u00f6netimi ve sa\u011flam hata i\u015fleme gibi konular\u0131 daha derinlemesine ara\u015ft\u0131rarak uygulaman\u0131z\u0131n kalitesini ve s\u00fcrd\u00fcr\u00fclebilirli\u011fini daha da art\u0131rabilirsiniz. Flask ve SQLAlchemy&#8217;nin sundu\u011fu esneklik ve g\u00fc\u00e7 ile, veri yo\u011fun web uygulamalar\u0131 geli\u015ftirmek hi\u00e7 bu kadar eri\u015filebilir olmam\u0131\u015ft\u0131.<\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?\nVeritaban\u0131 tasar\u0131m\u0131, modern web uygulamalar\u0131n\u0131n temel ta\u015flar\u0131nd","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1505],"tags":[],"class_list":{"0":"post-37849","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-sql-2","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?\" \/>\n<meta property=\"og:description\" content=\"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r? Veritaban\u0131 tasar\u0131m\u0131, modern web uygulamalar\u0131n\u0131n temel ta\u015flar\u0131nd\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-16T20:41:01+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"23 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?\",\"datePublished\":\"2026-01-16T20:41:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/\"},\"wordCount\":2201,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"SQL\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#respond\"]}],\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/\",\"name\":\"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2026-01-16T20:41:01+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/","og_locale":"tr_TR","og_type":"article","og_title":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?","og_description":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r? Veritaban\u0131 tasar\u0131m\u0131, modern web uygulamalar\u0131n\u0131n temel ta\u015flar\u0131nd","og_url":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2026-01-16T20:41:01+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"23 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?","datePublished":"2026-01-16T20:41:01+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/"},"wordCount":2201,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["SQL"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#respond"]}],"copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/","url":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/","name":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2026-01-16T20:41:01+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/flask-ve-sqlite-ile-many-to-many-veritabani-iliskileri-nasil-kullanilir\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Flask ve SQLite ile Many-to-Many Veritaban\u0131 \u0130li\u015fkileri Nas\u0131l Kullan\u0131l\u0131r?"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/37849","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=37849"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/37849\/revisions"}],"predecessor-version":[{"id":37850,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/37849\/revisions\/37850"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=37849"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=37849"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=37849"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}