PYTHON-DJANGO-BLOG PROJE ÇALIŞMASI 10 (Bloğumuzda post oluşturma(create)- Güncelleme(update) ve Silme-(delete) İşlemlerini görelim)

Blog projemizde kullanıcı bloğa üye olabilir durumda. Şimdi de Blok projemize üye olan kullanıcı blogda post(gönderi) oluşturabilecek, gönderisini güncelleyebilme veya gönderisini silebilme gibi özelliklerini kazandıralım.

blog app- views.py dosyasını açalım.

Bu dosyadaki komutlara dikkat ederseniz bu makaleye kadar daha çok fonksiyon temelli işlemler yaptık. Bu işlemleri daha kolay yapmanın bir yolu var. O da sınıf temelli(class based) kodlar yazmak. Şimdi burada yer alan kodları sınıf-temelli yazarak işlerimizi kolaylaştıralım. Sınıf temelli kodlarda bir web sitesinde yapılan işlemler bellidir bu yüzden şablonlar(bir takım işlemlerin hazır hali) geliştirilmiştir bu işlemlere ait standart bazı işlemler daha önceden tanımlanmıştır( aslında şablonlardan bahsediyoruz) ve biz o tanımlanan hazır kodları(şablonları) kullanarak kendi sitemizde kullanabileceğiz. 

Generic views altında bulunan bu hazır şablonlar createview,  listview,  updateviews gibi çeşitli şablonlar vardır. Biz şimdi bu proje için gereken şablonları kullanacağız.

blog app- views.py dosyasının açın:

1. Bu makalede blog projemizde LİSTVİEW kullanımı görelim. İlk olarak bu dosyada sınıf temelli görünümler oluşturacağız bunun için aşağıdaki kod  generic sınıfı görünümünden listview dosyamıza eklenir. Aşağıdaki kodu en üste ekleyelim.

from django.views.generic import ListView

a. Anasayfamıza buraya kadarki makalemizde fonksiyon( def ile başlayan home fonksiyonu) temelli kod ile eriştik-çalıştırdık ve kod aşağıdaki gibiydi:

blog apps-views.py eski hali:

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

blog apps-urls.py eski hali:

from django.urls import path
from . import views

urlpatterns = [
path('', views.home, name="blog-home"),
path('hakkinda/', views.hakkinda, name="blog-hakkında"),
]



b. Şimdi de Anasayfamıza Sınıf Temelli Görünümle( Class Based Views-PostListView sınıfı temelli kullanım)  erişmeye-çalıştırmayı deneyelim bunun için kodlar aşağıdaki gibidir:


blog app-views.py yeni hali:

NOT: Burada dikkat ederseniz PostListView isimli sınıfımız ListView isimli sınıfın parantez içinde kullanımı ile o sınıftan miras alması sağlandı. Yani listview da ait hazır   neler varsa onları PostListView sınıfında kullanabileceğiz anlamına geliyor. 

class PostListView(ListView):
model = Post
template_name = 'blog/home.html' # <app>/<model>_ <viewtype>.html
context_object_name = 'postsA'
ordering = ['-date_posted']

NOT: Hemen üstteki kodda geçen ordering = ['-date_posted' komut gönderilen postları en son gönderilenden eskiye doğru sayfanızda sıralar(ordering özelliği). (Bu tıpkı en son tweetin en üstte görünmesini sağlamak gibi.)

blog app-urls.py yeni hali:

from django.urls import path
from .views import PostListView
from . import views

urlpatterns = [
path('', PostListView.as_view(), name="blog-home"),
path('hakkinda/', views.hakkinda, name="blog-hakkında"),
]


2. Şimdi projemizde detailview sınıfının kullanımı görelim.

blog app- views.py dosyasının açın:

Bu sefer generic sınıfı görünümünden detailview dosyamıza eklenir. Bununla ilgili aşağıdaki kodu en üste ekleyelim.

from django.views.generic import ListView, Detailview

a. Post a ait detail görünüm için sınıf temelli kodlarımızı yazalım. 

*blog app- views.py dosyasına aşağıdaki kodları ekleyin:

class PostDetailView(DetailView):
model = Post

*blog apps-urls.py dosyasına aşağıdaki kodları ekleyin: 

NOT: Aşağıdaki kodlarda en üste PostDetailView eklendi. Ardından path tanımlandığını görüyoruz. Path de geçen pk (primary key demektir) o postun( gönderinin) int tipinde bir numarasıdır. Her postun bir id si yani pk sı vardır. 

...
from .views import PostListView, PostDetailView
...

urlpatterns = [
.....

path('Post/<int:pk/>', PostDetailView.as_view(), name="post-detail"),
....
]


Evet post detail kodlarımızı yazdık ancak henüz detail sayfamız yok(post_detail.html yok) şimdi o detail sayfamızı oluşturalım. Bunun için aşağıdaki adımları takip edin:

* blog projenizde sırasıyla klasör ağacında blog app-templates-blog sırasıyla klasöre ulaşın ve üzerinden sağ tuş-yeni-HTML dosyası ekleyin  ve oraya post_detail.html ismini verin. 
post_detail.html dosyası home page e benziyor ve ordan kopyasını alıp birkaç değişiklikle bu sayfamızda aşağıdaki gibi hazırlanmış oldu.Kodlar aşağıdadır.

post_detail.html dosyası:

{% extends 'blog/base.html' %}
{% block content %}

<div class="container">

<img class="rounded-circle" width="60" height="60" src="{{ object.author.profile.image.url }}">
<div class="card-header-pills">
<div class="card-header">
<div>
<a class="mr-2" href="#" >{{ object.author }}</a>
<small class="text-muted"> {{ object.date_posted|date:"F d, Y"}}</small>
</div>
<h1 class="card-title" > {{ object.title }} </h1>
<p class="card-body"> {{ object.content }} </p>
<p>{{ post.content }}</p>
</div>
</div>
</div>

{% endblock %}
Şimdi post a ulaşılıp ulaşılmadığını test edelim. RUNSERVER dedikten sonra tarayıcıya şöyle yazıp test edin.
http://127.0.0.1:8000/post/4/   ENTER a basıldığında 4 pk nolu post sayfanızda açılmış olması gerekir.

b. Bu adımda artık anasayfada bulunan bir post a tıklandığında ilgili post un detail-ayrıntı sayfasını ulaşılabilir yapalım.

* home.html dosyasını açın aşağıdaki satırı bulun ve yapılan değişikliği sizde uygulayın:

<h1><a class="card-title" href="{% url 'post-detail' post.id %}" >
{{ post.title }}</a></h1>


3. Şimdi projemizde createview sınıfının kullanımı görelim. Bu adım kullanıcının yeni post oluşturması-bu postu güncellemesi veya silmesi işlemlerini uygulamaya çalışacağız. bunun için aşağıdaki adımları izleyin.

a. blog apps- views.py dosyasını açın:

*Bu dosyada en üste aşağıdaki satırın sorunu CreateView ekleyin.

....
from django.views.generic import ListView, DetailView, CreateView
....

*Yine bu dosyada PostCreateView isimli class ı tanımlayalım. Bu işi yapan kod aşağıdaki gibidir.

class PostCreateView(CreateView):
model = Post
fields = ['title', 'context']

b. blog apps- urls.py dosyasına geçin kodları aşağıdaki gibi güncelleyin

* Bu dosyada en üste PostCreateView kodunu ekleyin:

...
from .views import PostListView, PostDetailView, PostCreateView
...

* Yine bu dosyada(urls.py de) urls tanımlaması yapılması gerekir bunun için kodlar aşağıdaki gibidir:

urlpatterns = [
....
,
....,
path('post/new/', PostCreateView.as_view(), name="post-create"),
....,
]


Şimdi yaptıklarımızı TEST edelim. 

Tarayıcıya şöyle yazıp ENTER a basalım:

http://127.0.0.1:8000/post/new/ ENTER a basınca POST ile ilgili sayfa gelmesi gerekir. Post a başlık ve içerik yazılıp POST düğmesine basınca POSTumuz oluşturulamaz çünkü bu postu yazan bir profil olmalı veya bu posta ait bir  bir id olması gerekir. Yani login olmuş bir kullanıcı olması gerekir. Bu kullanıcı yeni postlar (gönderiler) paylaşabilmelidir.

Şimdi bu problemin nasıl çözüldüğüne bakalım:

blog apps-views.py gir:

Aşağıdaki kodda def ile bir fonksiyon tanımlandı. Bu fonksiyon yeni bir post sırasında post edilmeden önce postu bir örneğini(instance alır) ve o postu o anki login olmuş kullanıcıya ait olmasını sağlar.

class PostCreateView(CreateView):
....
....

def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)

Artık post gönderilebilir duruma geldi. Artık son gönderilen post anasayfada en üstte yerini aldı.(Tabi biz bunu mauel görebiliyoruz). Ama biz bu post işlemi gerçekleştiğinde sayfayı otomatik istediğimiz bir yere yönlendirmeyi görelim.

blog apps- model.py gir:

*en üste aşağıdaki kodu ekle

...
...
...
from django.urls import reverse

* aşağıdaki kod eklenir. reverse string değer alır. reverse ile İnstance alınan postun id isini yani pk gibi değerleri yakalar. 

def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})


ŞİMDİDE POST GÖNDERMEK İSTİYORUZ AMA OTURUM AÇIK MI DİYE KONTROL ETMEK İSTİYORUZ?

Daha önce fonksiyon temelli decorators kullnarak login kontrolü yapmıştık. Eğer şimdi bu kontrolü sınıf temelli yapmak istiyourz. Bu durum da django da  mix-ins kullanımı yapmak gerekir.

blog apps-views.py gir:

*Bu dosyada en üste aşağıdaki kodu girelim.

...
from django.contrib.auth.mixins import LoginRequiredMixin
...
...

* Yine aynı yerde aşağıdaki kodu ekleyelim. Sadece  LoginRequiredMixin parametre olarak  eklendiğine dikkat edin.

class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'context']

Bu adımları dikkatli yaptıysanız eğer TEST edebiliriz. Bunun için

http://127.0.0.1:8000/login/?next=/post/new/ ENTER la giriş yapıldığında yeni post oturum açılmadığı için gerçekleşmedi ve sizi login sayfasına yönlendirmiş oldu.

ŞİMDİ OLUŞTURDUĞUMUZ POST U UPDATE-GÜNCELLEME İŞLEMLERİNİN NASIL YAPILACAĞINI GÖRELİM.

blog apps- views.py dosyasına gir:

* Bu dosyada en üste aşağıdaki kodu girelim.(UpdateView eklendiğine dikkat edin.)

...
...
from django.views.generic import ListView, DetailView, CreateView, UpdateView
...


* Şimdi yine aynı dosyada aşağıdaki kodu ekleyin. Buradaki kodumuzyine burada yer alan PostCreateView a benziyor bu neden o bölümü kopyalıp değişiklik yapabilirsiniz. Update işlemleri için kodların son hali aşağıdaki gibidir.

class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'context']

def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)

* Şimdi de update işlmeleri için urls.py de yolu tanımlayalım.

blog apps- urls.py dosyasını açın:

Aşağıdaki kodda dikkat ederseniz üst kısmı PostUpdateView eklendi. urlspatterns kısmında da path eklendiğine dikkat edin. Diğer kısımlar zaten kodunuz ekli olması gerekir.

...
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView
...

urlpatterns = [
...

...
...
path('post/<int:pk>/update/', PostUpdateView.as_view(), name="post-update"),
...
]

Yukaıdaki kodları ekledikten sonra güncelleme yapıp yapamadığımızı test edelim. 

Bunun için Tarayıcıya : http://127.0.0.1:8000/post/8/update/ yazıp ENTER a basalım. 

Artık karşınıza update etme sayfanızın geldiğini göreceksiniz. Bilgileri değiştirip post edebilirsiniz. Ancak burada bir istemediğimiz durum var. Sorun şu bu haliyle tüm diğer kullanıcıların post ları da update edebilir durumdadır. Bunu düzeltmek için yani kullanıcı sadece kendi post-gönderilende değişiklik yapabilmesi için aşağıdaki adımları izlemek gerekir.

SIRADAKİ ADIMDA POST UPDATE-GÜNCELLEME İŞİNİ SADECE HER KULLANICI SADECE KENDİ POSTLARINI GÜNCELLEYEBİLMESİ VEYA DEĞİŞRİREBİLMESİ GEREKİR.

Bu işlemi yapabilmek için yine  mix-in leri kullanacağız. 

blog apps- views.py dosyasına gir:

* Bu dosyada en üste aşağıdaki kodu girelim.( UserPassesTestMixin  eklendiğine dikkat edin.)

...
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
...
...

* Şimdi yine bu dosyada ilgili kodları yazalım. Aşağıdaki kodda UserPassesTestMixin parametre olarak eklenmiş. Bu kodda test_func fonksiyonu tanımlanmış. bu fonksiyon açık olan oturumdaki kullanıcının kendi postunu mu güncellemek istiyor onu test eden bir fonksiyondur.

class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
...
...

def form_valid(self, form):
...
...

def test_func(self):
post =
self.get_object()
if self.request.user == post.author:
return True
return False


ŞİMDİ DE DELETEVİEW YANİ POST U SİLMEK İSTERSEK KODLARI NASIL YAZMALIYIZ. BU İŞLEM DETAİLVİEW İLE BENZERDİR. ŞİMDİ BU ADIMLARI GÖRELİM.

1. blog apps-views.py gir:

*Bu dosya içinde en üste DeleteView sınıfını ekleyerek o sınıfı kullanacağımızı söylemiş olduk.

...
...
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
...

* Yine bu dosyada en alta aşağıdaki kodu ekleyebilirsiniz. Burada kodlar DetailView a çok benzer. Yine bu kodlarda post u silme işlemi yaparken kullanıcının login olup olmadığı kontrol ediliyor bunun için mix-ins lerdan miras alarak kontroller yapıldı. def komutu ile de tıpkı PostUpdateView da olduğu gibi post ile kullanıcı eşleşiyor mu kontrolünün yapıldığına dikkat edin.
Silme onaylandığında gideceği yeri anlatan komut da success_url = '/' şeklindedir.

class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = Post success_url = '/'

def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False


2. blog apps- urls girin:

* url rotayı yazalım.

En üste PostDeleteView kodunun eklendiğine dikkat edin. urls pattern kısmında silme işlemini yapacak rota gösterilmiştir.

...
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView
....

urlpatterns = [
...

...
...
...
path('post/<int:pk>/delete/', PostDeleteView.as_view(), name="post-delete"),
...
]

* Şimdide Post u silmek istediğinize emin misin diye soracak bir HTML sayfasının hazırlanması aşamasını yapalım. Bunun için sırayla

Fareyle Blog-templates-blog  klasörü üzerine gelinir sağ tuş-yeni- HTML döküman seçilir ve dosyaya post_confirm_delete.html adı verilir. Bu dosyanın içeriğindeki kodlar aşağıdaki gibidir.

( Daha önce oluşturduğumuz post_form.html dosyasından kodları kullanabilirsiniz.)

{% extends 'blog/base.html' %}

{% block content %}
<div class="content">
<form method="post">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Post u Sil</legend>
<h2>Bu "{{ object.title }}" post u silmek istediğinize emin misiniz?</h2>

</fieldset>
<div class="form-group">
<button type="submit" class="btn btn-outline-danger">Eminim Sil!</button>
<a class="btn btn-outline-secondary" href="{% url 'post-detail' object.id %}">Vazgeç-İptal</a>

</div>
</form>

</div>
{% endblock content %}


LOGİN OLMUŞ BİR KULLANICININ POST GÖNDERMEK İSTEDİĞİNDE ULAŞACAĞI TIKLAMASI GEREKEN LİNKİ BASE.HTML DOSYAMIZDA YERİNİZ ALSIN. ŞİMDİ BU İŞLMELERİN NASIL YAPILDIĞINI GÖRELİM.



Yorum Gönder

0 Yorumlar