Post

Sıfırdan Bir Django Uygulaması Geliştirme

Sıfırdan Bir Django Uygulaması Geliştirme

Bu dökümanı hazırlamamın amacı, başta kendim olmak üzere Django framework’üne aşina olan ancak zamanla kullanımını ve temel fonksiyonlarını unutan kişilere yardımcı olmaktır. Bu nedenle döküman boyunca konuların detaylarına girmeyecek ve daha ziyade püf noktalara değineceğim, zira Django yeni olanlar için internette birçok çeşitli kaynak mevcut bulunmaktadır.

Bu dökümanda Django Framework ile dinamik bir kişisel blog uygulaması yapacağım. Blog uygulamasında kullanacağım hazır bootstrap şablonuna buradan ulaşabilirsiniz.

Kurulum adımları

Doğrudan konuya girerek, gereken bileşenlerin kurulumlarını yaparak başlıyorum.

1
2
3
python3 -m venv env
source env/bin/activate
pip3 install Django

Bu döküman boyunca gösterilen ve çalıştırılan tüm komutlar linux işletim sistemine göre olacaktır. Ek olarak, benim bu dökümanı hazırladığım esnada mevcut Django sürümünün 5.0.1 olduğunu belirtirim.

Django projemizi oluşturmak için gereken bileşenler hazır hale geldiğine göre, projemize bir isim vererek oluşturmaya başlayabiliriz. Ben burada mysite olarak isimlendireceğim.

1
django-admin startproject mysite

Django projeniz şayet başarıyla oluşturulduysa, aşağıdaki dizin yapısına sahip olmalısınız.

1
2
3
4
5
6
7
8
9
10
11
(env) alchustan@debian:~/mysite$ tree
.
├── manage.py
└── mysite
    ├── asgi.py
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

2 directories, 6 files

Bir Django uygulaması oluşturmak

Django uygulamalarının mantığına kısaca değinecek olursam; Bir teknoloji şirketiniz ve bu şirketinizin websitesi olduğunu farz edelim.

Sitenize ait bir haberler sayfanız, teknoloji severlerin aralarında iletişim kurabileceği bir forumunuz, ve danışmanlık sağladığınız diğer şirketlere hizmet verdiğiniz başka bir web servisiniz mevcut. Bu durumda, her bir web servisinizi, Django üzerinde ayrı birer uygulama olarak yönetmeniz mümkündür. Böylece servislerinizi birbirlerinden bağımsız olarak yönetmeniz ve kullanmanız sizin için çok daha kolay olacaktır.

Bu kadar açıklama yeterli olduğuna göre, aşağıda yer alan komut ile Django uygulamanızı oluşturabilirsiniz. Ben burada uygulamamın adını blog yapacağım.

1
python3 manage.py startapp blog

Uygulamanın kurulumu

Her oluşturduğumuz uygulamayı, Django tanıtmamız gerekmekte. Bu nedenle Django ayarlarımızın tutulduğu settings.py içerisine, bu uygulamımızın dizindeki yerini tanımlamamız gerekiyor.

1
2
3
4
5
6
7
8
9
10
11
   .  .  .
INSTALLED_APPS = [
    'blog.apps.BlogConfig', # <-- Bu oluşturduğumuz uygulamamız
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
   .  .  .

Aynı şekilde bu blog uygulaması içerisinde url yönetim işlemlerini yapabilmemiz adına, ana uygulamamız içerisinde yer alan urls.py ile blog urls dosyasına yönlendirme yapıyorum.

1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls')),
]

Oluşturduğumuz bu blog uygulaması içerisinde urls.py dosyası bulunmadığı için bunu da biz oluşturuyoruz. Dosyanın içeriği ise aşağıda gördüğünüz gibi olacak.

1
2
3
4
5
6
7
8
from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home-page'),
    path('about/', views.about, name='blog-about'),
    path('post/', views.post),
]

Peki views ne içeriyor bir de ona bakalım.

1
2
3
4
5
6
7
8
9
10
from django.shortcuts import render

def home(request):
    return render(request, 'home.html')

def about(request):
    return render(request, 'about.html')

def post(request):
    return render(request, 'post.html')

Django Template yapısı

Pekala, artık oluşturduğumuz blog uygulamamızı Django’ya başarılı bir şekilde tanımladık ve ardından urls ile views kısmını isteğimiz doğrultusunda düzenledik.

Ben burada örnek olarak 3 sayfa oluşturmaya karar verdim. Bunlardan bir tanesi anasayfamız olan home, sitemizin hakkımızda sayfası olan about bölümü ve oluşturacağımız blog yazıları için post. Uygulamamızın son yapısına bakacak olursak kabaca aşağıdaki tablodaki görünecek:

urls.pyviews.pyTarayıcıda Görünecek Olan Adres
’’home.htmlhttp://127.0.0.1:8000/
‘about/’about.htmlhttp://127.0.0.1:8000/about/
‘post/’post.htmlhttp://127.0.0.1:8000/post/

Şayet ben eğer mysite/urls.py dosyası içerisinde 6. satır için şu şekilde bir düzenleme yapsaydım path('blog/', include('blog.urls')), bu sefer tüm blog uygulamama ilişkin adreslerin başına aşağıdaki tabloda da görüldüğü üzere /blog eklenirdi.

urls.pyviews.pyTarayıcıda Görünecek Olan Adres
’’home.htmlhttp://127.0.0.1:8000/blog/
‘about/’about.htmlhttp://127.0.0.1:8000/blog/about/
‘post/’post.htmlhttp://127.0.0.1:8000/blog/post/

Templates klasörü

Pekala buraya kadar mutabıksak sitemizde görüntülecek olan html dosyalarımızın nerede tutulacağına geçebiliriz. Django varsayılan olarak uygulamamız içerisinde bir templates klasörünün varlığını kontrol eder ve bu klasörün içine bakar. Bu nedenle views.py içerisinde bahsi geçen home.html, about.html ve post.html dosyalarını, uygulama dizinimin altında oluşturduğum templates klasöründe barındıracağım.

Bu adımları uyguladığınızda güncel Django dizin yapınız aşağıdakine benzer bir durumda olacaktır.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(env) alchustan@debian:~/mysite$ tree
.
├── manage.py
├── db.sqlite3
├── blog
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── templates
│   │   └── home.html
│   │   └── about.html
│   │   └── post.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
└── mysite
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

4 directories, 16 files

Siz Django uygulamanızı çalıştırdığınızda, ayrıca __pycache__ tarzında dizinler görebilirsiniz, ancak bunlar gözardı edilebilir. Mühim olmadıkları için yukarıdaki dizin yapısında bunları eklemedim.

Pekala, şimdi Django uygulamamız sorunsuz bir şekilde çalışıyormu teyit edelim.

Home home.html

About about.html

ve görüldüğü üzere Django, sayfaları başarıyla önümüze getiriyor.

Böl ve Yönet

Django, bizlere kullanım kolaylığı sağlamak açısından dinamik sayfalar üretebilmemize ve kod tekrarını önlemimize yardımcı oluyor. Böylece tüm sayfalarda yer alacak kodları, tekrar yazmaktan kurtulmuş oluyoruz.

Aşağıda yer alan görselde, yapacağımız sitenin bir görünümü yer almakta ve siteyi üç farklı renk ile parçalara ayırdım. Bu kısımları sırasıyla izah edecek olursam:

  • Kırmızı renkli kısım: Sitenin header adını verdiğimiz bölüm ve bu kısım statik, yani sitenin tüm sayfalarında aynı kalacak.
  • Mavi renkli kısım: Sitenin ana içeriği burada yer alacak ve bu kısım dinamik, yani sayfanın içeriğine göre değişken olacak.
  • Sarı renkli kısım: Sitenin footer adını verdiğimiz bölüm ve bu kısım statik, yani sitenin tüm sayfalarında aynı kalacak.

Site Görünümü Bu şablon açık kaynak kodlu ve kullanımı ücretsizdir, buradan ulaşabilirsiniz.

Burada ilk iş olarak statik html kodlarımın duracağı templates klasörü içerisinde components adında bir klasör daha oluşturuyorum. Ardından bu klasör içerisinde sırasıyla ilgili dosyaları oluşturuyorum:

  1. default.html -> Sitemde, sayfa oluştururken baz alacağım temel şablondur ve tüm sayfalar bu şablon baz alınarak türetilecektir.
  2. header.html -> Sitemin her sayfasında yer alacak olan header menüsüne ait kodlarım.
  3. footer.html -> Sitemin her sayfasında yer alacak olan footer kısmına ait kodlarım.

Pekala, şimdi default dosyamızın neler içerdiğine bir göz atalım.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{% load static %}
<!DOCTYPE html>
<html lang="en">
    <head>
        <link rel="icon" type="image/x-icon" href="{% static 'assets/favicon.ico' %}" />
        <link href="{% static 'css/styles.css' %}" rel="stylesheet" />
    </head>
    <body>
        <!-- Header-->
        {% include 'components/header.html' %}

        <!-- Main Content-->
        {% block content %}
        {% endblock %}
        
        <!-- Footer-->
        {% include 'components/footer.html' %}
        <script src="{% static 'js/scripts.js' %}"></script>
    </body>
</html>

Bu dosya içeriğindeki kodları sırasıyla izah edecek olursam:

  • {% load static %} -> Bir takım statik dosyalara ihtiyacımız olacağını belirtiyoruz.
  • {% static 'css/styles.css' %} -> Statik dosyalarımızın barındırıldığı klasör dizinine giderek css/styles.css dosyasını çağırır.
  • {% include 'components/header.html' %} -> Include fonksiyonu, bir başka html dosyasını çağırmamızı sağlar. Burada header.html içerisinde yer alan tüm kodların kopyalanaraktan, 8. satıra yapıştırıldığını düşünebilirsiniz.
  • {% block content %} {% endblock %} -> Bu default sayfadan türeteceğim ve oluşturacağım tüm dinamik içeriklerimin buraya yerleştirildiğini işaret ediyorum.

Tüm bu kodları parçalar haline getirmemizin bize yararı, sonrasında yapmak isteyebileceğimiz bir değişiklikte tek bir yere bakacağız ve kodu yönetme, değiştirme ve düzenleme işlemleri bizim için çok daha az uğraştırıcı olacak.

Bu değişikliklerin sonucunda html sayfalarımızın durumuna bir bakalım.

1
2
3
4
5
6
{% extends 'components/default.html' %}
{% block content %}
    <div class="container px-4 px-lg-5">
        .  .  .
    </div>
{% endblock %}

Statik dosyalarımız

Günümüzde her sitede olduğu üzere kullandığımız bir takım .css , .js ve görsel dosyalarımız mevcut olacaktır. Bunları kimi zaman artık CDN altyapılarında barındırsakta, birçok websitesi bu dosyaları hala kendi bünyesinde saklamaya devam ediyor.

Django bu tür statik dosyalarımızı, oluşturduğumuz uygulama dizinimizin altında static klasörü olarak kabul eder ve bu klasöre bakar. Bu nedenle bizde sitemizde kullanacağımız dosyaları bu klasör altına yerleştireceğiz.

Statik dosyalarınızın bulunduğu klasörün adını veya konumunu değiştirmek istersek settings.py içerisinde yer alan STATIC_URL = 'static/' değiştirmemiz yeterli olacaktır.

Bu değişikliklerden sonra ise güncel blog uygulamamızın dizin yapısı aşağıdaki gibi görünecektir.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(env) alchustan@debian:~/mysite/blog$ tree
.
├── __init__.py
├── admin.py
├── apps.py
├── models.py
├── tests.py
├── urls.py
└── views.py
├── static
│   ├── assets
│   │   └── favicon.ico
│   ├── css
│   │   └── styles.css
│   └── js
│       └── scripts.js
├── templates
│   ├── components
│   │   ├── default.html
│   │   ├── footer.html
│   │   └── header.html
│   ├── home.html
│   ├── about.html
│   └── post.html

7 directories, 16 files

Django Models yapısı

Models yapısı ile Django veritabanımızın genel hatlarını oluşturacağız. Burada oluşturacağımız her bir sınıf, yani class veritabanında bir tabloyu temsil eder, ve bu sınıf içerisinde oluşturduğumuz değişkenler ise kolonları temsil etmektedir.

Bu durumda aşğıda yer alan models dosyasına bakacak olursak; Post isimli bir tablo oluşturuyor ve sonrasında bu tablo içerisinde title, content, date_posted ve author kolonlarını oluşturduğumuzu söyleyebiliriz.

1
2
3
4
5
6
7
8
9
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

Bir kullanıcı oluşturmak

Burada dikkat etmemiz gereken bir diğer nokta da user kısmı. Henüz projemizde bir user bulunmamakta, bu nedenle yaptığımız değişiklikleri veritabanına uygulamadan önce, bir super-user, yani admin rolüne sahip bir kullanıcı oluşturmalıyız.

Bunun için sırasıyla aşağıdaki iki komutu çalıştırarak kullanıcı oluşturabiliriz.

1
2
(env) alchustan@debian:~/mysite$ python3 manage.py migrate
(env) alchustan@debian:~/mysite$ python3 manage.py createsuperuser

Bir user oluşturduğumuza göre veritabanı değişikliklerimizi uygulayabiliriz. Aşağıda yer alan iki komutu sırasıyla çalıştırdığımız taktirde tablo ve kolonlarımız oluşmuş olacaktır.

1
2
(env) alchustan@debian:~/mysite$ python3 manage.py makemigrations
(env) alchustan@debian:~/mysite$ python3 manage.py migrate

Django’da CRUD işlemleri

Bu noktadan sonra, Django üzerine okuduğum ve izlediğim içeriklerin neredeyse hepsi python shell arayüzüne geçiş yaparak veri yönetimi işlemlerini gerçekleştiriyor.

Ancak ben, bu dökümanda farklılık yapacağım ve oluşturacağımız bir python dosyası üzerinden bu işlemleri gerçekleştireceğiz.

Django projemin ana dizininde myscript isimli yeni bir python dosyası oluşturuyorum.

1
2
3
4
5
6
7
8
import django
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
django.setup()

from blog.models import Post
from django.contrib.auth.models import User

Burada önce django ve os kütüphaneleri dahil edildikten sonra django ayarlarımızı kaydetmiş olmamız önemli. Eğer Post ve User başta eklemeye çalışırsanız, django ayarları kayıt olmadığı için hata alacaksınız.

Create (Oluşturma)

1
2
3
# Yeni bir post oluşturup kaydetme
post1 = Post(title='Proje Başlığı', content='. . .' ,author=User.objects.get(id=1))
post1.save()

Read (Okuma)

1
2
3
4
5
6
7
# Tüm postları çekme
all_posts = Post.objects.all()
print(all_posts)

# Belirli bir postu id kullanarak çekme
specific_post = Post.objects.get(id=1)
print(specific_post)

Update (Güncelleme)

1
2
3
4
5
# Belirli bir postu güncelleme
post_to_update = Post.objects.get(id=1)
post_to_update.title = 'Güncellenmiş Başlık'
post_to_update.content = 'Güncellenmiş İçerik'
post_to_update.save()

Delete (Silme)

1
2
3
# Belirli bir postu silme
post_to_delete = Post.objects.get(id=1)
post_to_delete.delete()

Shell ile dosya arasındaki fark

Peki bu işlemleri python shell ile, oluşturduğumuz bir dosya üzerinde gerçekleştirmemiz arasındaki fark nedir?

Bu işlemleri bir dosya üzerinden gerçekleştirmeyi istememin sebebi; Birçok veriyi döngüler ile veritabanına aktarabilmek. Eğer kapsamlı bir web uygulaması yapmak istiyorsanız, düzenli olarak işlediğiniz verileri sitenizde görünür kılmak isteyebilirsiniz. Bu durumda verileri shell üzerinden teker teker işlemeniz imkansız olacaktır.

Verilerimizi görüntüleme

Pekala, artık verilerimizi veritabanımıza işlediğimize göre, bunları sitemizde görünür kılmaya geçebiliriz. Sırasıyla, önce verilerimi views ile html dosyama aktarıyorum.

1
2
3
4
5
6
from django.shortcuts import render
from .models import Post

def home(request):
    context = {'posts': Post.objects.all()}
    return render(request, 'home.html', context)

Ardından bir for döngüsü ile verilerimi sırasıyla alıyorum.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{% extends 'components/default.html' %}
{% block content %}
<div class="container px-4 px-lg-5">
  <div class="row gx-4 gx-lg-5 justify-content-center">
    <div class="col-md-10 col-lg-8 col-xl-7">

    {% for post in posts %}
      <!-- Post preview-->
      <div class="post-preview">
        <a href="post.html">
          <h2 class="post-title">{{ post.title }}</h2>
          <h3 class="post-subtitle">{{ post.content }}</h3>
        </a>
        <p class="post-meta"> Posted by <a href="#!">{{ post.author }}</a>
        on {{ post.date_posted }}
        </p>
      </div>
      <!-- Divider-->
      <hr class="my-4" />
    {% endfor %}

    </div>
  </div>
</div>
{% endblock %}

Django Admin paneli

Models yapısını anlattığımız esnada bir user oluşturmuştuk, peki bu super-user nelere kadir?

Django Framework, yapısı itibariyle bir admin arayüzü ile birlikte gelmekte. Bu arayüz, CRUD işlemlerimizin tamamını görsel olarak yapabilmemizi mümkün kılıyor.

Bu arayüze geçmeden önce, veritabanımızda bulunan Blog uygulamamızın Post tablosunu, bu admin paneline tanıtmamız gerek.

1
2
3
4
from django.contrib import admin
from .models import Post

admin.site.register(Post)

Bu işlemi tamamladıktan sonra panelimize geçiş yapabiliriz.

Bu panel, sitemizin /admin kısmında yer alıyor. Bu bilgiyi nereden edindiğimiz sorulacak olursa mysite/urls.py içerisinde bir yönlendirme mevcut.

http://127.0.0.1:8000/admin/ Adresine gidersek, bizi bir giriş ekranı karşılayacak. Oluşturduğumuz super-user bilgileri ile buraya giriş yapabiliyoruz.

Giriş yaptığımız taktirde bizi karşılayacak olan arayüz aşağıda yer alan görseldeki gibi olacaktır.

Admin Panel

Eğer Post kısmına bakacak olursak, mevcut postlarımızı görüntüleyebiliyoruz. Ayrıca sağ üst kısımda yer alan Add Post seçeneği ile yeni bir post ekleyebildiğimizi görüyoruz.

Posts

Ancak burada mevcut Postlarımıza baktığımızda, isimleri bizim için yeterince anlaşılır değiller. Bunları kendi Post başlıklarımız ile değiştirirsek, bizim için çok daha anlaşılır olacaklardır.

Bunun için models içerisinde oluşturduğum Post sınıfıma __str__ fonksiyonunu eklemem yeterli olacaktır. return self.title ile başlığı döndürmesini istediğimi belirtiyorum.

1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

Tekrar aynı arayüze dönecek olursak, artık her bir Post’u, bizim isimlendirdiğimiz başlık ile görebiliriz.

Updated Posts

Sonuç

Buraya kadar okuduysanız, artık temel düzeyde bir Django projesinin başlatılmasından, uygulamaların oluşturulmasına, oluşturduğumuz uygulamaların yönetimlerine, bu uygulamaların veritabanı ile etkileşimlerine ve admin paneline hakimsiniz demektir.

Bu döküman, başlangıçta kendim için çıkardığım notlardan oluşurken, bunları açık olarak paylaşma isteğim sonucunda blog yazım olarak evrildi. Dökümanda eksik veya yanlış olduğunu gördüğünüz noktalar varsa, düzeltmem için beni bilgilendirmenizden müteşekkir olurum. Ayrıca ihtiyaç duyduğum taktirde, zaman içerisinde dökümana eklemelerde bulunabilirim.

Yararlandığım Kaynaklar

  1. Django’nun kendi dökümantasyonu
  2. Django Tutorials - Corey Schafer
This post is licensed under CC BY 4.0 by the author.