"Enter"a basıp içeriğe geçin

Flask Uygulamalarında Application Factory Pattern Kullanımı

Flask ile geliştirilen uygulamaların standart bir proje mimarisi ile geliştirilmediğini fark etmişsinizdir. Her uygulama, geliştiricisinin kendi kurguladığı proje tasarımı ve uygulama mimarisi ile inşa edilir ve kullanıma sunulur. Bunun en önemli sebebi, Flask’in geliştiricileri bu konuda oldukça özgür bırakmasıdır.

Ancak yine de resmi Flask dokümanlarını incelediğimizde bize önerilen bir tasarım deseninin mevcut olduğunu görüyoruz. Daha önce karşılaştığınızı düşündüğüm bu tasarım desenine Application Factory Pattern yada Türkçe olarak Uygulama Fabrikası Deseni diyoruz. Bizlerde bu makalede, Application Factory Pattern kullanarak bir Flask uygulamasının nasıl en iyi şekilde yapılandırabileceğimizi öğreneceğiz.

Application Factory Pattern Nedir?

Flask ile bir uygulama geliştirdiğimizde, geleneksel yöntemde, bütün uygulama tek bir app nesnesi üzerine inşa edilir ve farklı örnekleri oluşturulamaz. Ancak Application Factory Pattern uygulamayı bir fonksiyon içerisinde yapılandırarak uygulamanın bu fonksiyon ile ayağa kaldırılması ilkesine dayanır. Bu sayede uygulamamızın birden fazla örneğini, birden fazla yapılandırma ayarı ile hızlıca oluşturulup kullanılabilir hale getirebiliriz. Yani özetle AFP;

  • Döngüsel içe aktarma problemlerini çözer.
  • Farklı ortamlar (development, test, production) için daha hızlı ve daha kolay kurulum sağlar.
  • Daha organize ve daha okunabilir kod tabanı oluşturur.
  • Sürdürülebilir ve ölçeklenebilir proje mimarileri için alt yapı kurar.

Application Factory Pattern ile Uygulama Geliştirmek

Örneğin, aşağıda SQLAlchemy ile desteklenmiş basit bir web uygulamasını görebilirsiniz.

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
db = SQLAlchemy(app)


@app.route("/")
@app.route("/index")
def index():
    return render_template("index.html")

Geleneksel yöntemlerle geliştirdiğimiz uygulamamızda, 4. satırda hızlıca app = Flask(__name__) diyerek uygulamamızı oluşturduk. Gördüğünüz gibi örnek oluşturmaya müsait değil ve farklı yapılandırma ayarları eklemek istiyorsak eğer biraz çaba sarf etmemiz gerecek. Oysa uygulama fabrikalarını kullandığımızda, uygulamamızı bir fonksiyona atayarak birden fazla örneğini oluşturabiliriz.


Devam etmeden önce, uygulama dizinini göstermek istiyorum. Böylece, neyin nerede olduğunu kabaca görebilirsiniz.

projectFolder
├── app
│   ├── __init__.py
│   └── routes
│       ├── admin.py
│       └── main.py
├── requirements.txt
├── wsgi.py
└── settings.py

Bu uygulama dizini yapısı, Demongo’da kullandığım yapının kırpılmış hali. Eğer isterseniz bu linkten proje yapısını detaylı olarak inceleyebilirsiniz.


Uygulama Fabrikası Oluşturma

Şimdi, proje dizinimizin içerisine bir app klasörü oluşturalım ve içerisine __init__.py dosyasını aşağıdaki gibi oluşturalım. Burada amaç, app klasörünün bütün projeyi, bir bütün olarak temsil etmesini sağlamaktır.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

from settings import DefaultConfig

db = SQLAlchemy()


def create_app(configs=DefaultConfig):
    app = Flask(__name__)
    app.config.from_object(configs)
    
    db.init_app(app)
    
    from app.routes.main import main as main_bp
    app.register_blueprint(main_bp, url_prefix="/")

    from app.routes.admin import admin as admin_bp
    app.register_blueprint(admin_bp, url_prefix="/admin")

    return app

Burada gördüğünüzüz gibi, uygulamamızı create_app fonksiyonu içerisinde oluşturduk ve yapılandırdık. Yapılandırma sırasında default bir config alsa da kullanıcının istediği harici bir config ile çalışabilmesinede olanak sağlamış olduk.

Dikkat etmemiz gereken önemli bir detay ise 13. satırda bulunuyor. SQLAlchemy gibi Flask modüllerini uygulamamıza tanıtmamız için init_app ile uygulama bağlamına eklememiz gerekiyor. Aksi durumda modülü kullanamayacağız. (Uygulama BağlamıApplication Context – kavramına farklı bir yazıda değineceğim)

Ayrıca, 15. satırdan itibaren Blueprint ile oluşturduğumuz modülleri projemize dahil ettik. Örneğin, kök dizine (/) gelecek istekleri karşılayacak modülümüze main ismini verdik. Modül içeriği aşağıdaki gibidir.

from flask import Blueprint, render_template, current_app

main = Blueprint("main", __name__)


@main.route("/")
@main.route("/index")
def index():
    temp_value = current_app.config["ENV"]
    return render_template("views/main/index.html", title="Home")

Gördüğünüz gibi, web sitesinin temel sayfalarını oluşturan modülü bu şekilde geliştirmiş olduk. Admin panelini içeren sayfalarıda benzer şekilde geliştirebilirsiniz. Burada yabancı gelen tek şey muhtemelen 1. ve 9.satırdaki current_app nesnesidir. Bu nesne, uygulamamızı temsil eder ve uygulamamıza ait bütün özellikleri içerisinde barındırır. Böylece uygulama ait verilere bu nesne aracılığı ile ulaşabiliriz.

Application Config

Uygulamamızda farklı ortamlar için farklı konfigürasyon dosyaları kullanmamız gerekebilir. Bunun için settings.py dosyasına farklı ortamlar için farklı ayar sınıfları oluşturmamız gerekiyor.

from os import path, environ, getenv


class DefaultConfig(object):
    def __init__(self):
        self.BASEDIR = path.abspath(path.dirname(__file__))
        self.SQLALCHEMY_DATABASE_URI = environ['DATABASE']
        self.SQLALCHEMY_TRACK_MODIFICATIONS = False
        self.SECRET_KEY = "super_secret_key"
        self.ROOT_URL = "http://0.0.0.0:5000"


class ProductionConfig(DefaultConfig):
    def __init__(self):
        super(ProductionConfig, self).__init__()
        self.SQLALCHEMY_DATABASE_URI = environ['DATABASE']
        self.ROOT_URL = "https://prodsite.com"


class TestConfig(DefaultConfig):
    def __init__(self):
        super(ProductionConfig, self).__init__()
        self.SQLALCHEMY_DATABASE_URI = environ['DATABASE']
        self.ROOT_URL = "https://testsite.com"

Uygulamayı Çalıştırma

Uygulamamızı temel hatları ile geliştirdiğimize göre geliştirme ortamına ayağa kaldırabiliriz. Bunun için terminal üzerinden, proje dizininde flask run komutunu vermeniz yeterli olacaktır. Böylece proje localde hızlı bir şekilde ayağa kalkacaktır.

~$ export FLASK_ENV=development
~$ flask run

Uygulamayı WSGI Server’a Tanıtma

Projemizi uygulama fabrikası ile oluşturduk. Şimdi uygulamamızı bir WSGI Server ile çalıştırabilmemiz için arayüz dosyası hazırlamamız gerekiyor.

from app import create_app
from settings import ProductionConfig, TestConfig

production_app = create_app(configs=ProductionConfig)
test_app = create_app(configs=TestConfig)

if __name__ == "__main__":
    test_app.run()

Gördüğünüz gibi, uygulamamızın farklı ortamlarda çalışacak iki farklı örneğini hızlıca oluşturduk. Şimdi gunicorn yada benzeri bir WSGI Server’a uygulamamızı tanıtmak için wsgi.py dosyasındaki uygulama örneklerinden birini işaret edebilirsiniz. Hepsi bu kadar.

Uygulama fabrikaların mantığı biraz kafa karıştırıcı olsada doğru kullanımı hayat kurtarır diyebilirim. Daha önce geliştirdiğim Demongo isimli projeyi kullanarak sizlerde Flask ile hızlıca Application Factory Pattern kullanan uygulamalar geliştirebilirsiniz. İyi yapılandırılmış uygulama mimarisi ve ihtiyacınız olan pek çok şeyin içerisinde bulunması size oldukça hız katacaktır diyebilirim.

Demongo: https://github.com/emregeldegul/demongo

Faydalı olması dileklerim ile, iyi çalışmalar.

4 Yorum

  1. Ercan Can
    Ercan Can 5 Temmuz 2022

    yapıyorsun bu işi :)) eline sağlık yunus emre başarılı olmuş

  2. Oktay
    Oktay 4 Temmuz 2022

    Akıcı bir makale olmuş. Teşekkürler.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir