{Django Öğreniyorum}
Günümüz kusursuzcuları için ağ çatısı

İlk Django Uygulamanızı Yazma, Bölüm 4

Bu sayfa Öğretici 3‘ün kaldığı yerden devam ediyor. Anket uygulamasına devam ediyoruz ve basit biçim işleme ve kodumuzu kesme üzerine odaklanacağız.

Basit bir biçim yazın

Şablonun bir HTML <form> öğesi içerdiği şekilde, son öğreticide geldiğimiz aşamadaki anket ayrıntısı şablonunu güncelleyelim. (‘anketler/ayrinti.html’):

anketler/templates/anketler/ayrinti.html


  <h1>{{ soru.soru_metni 	}}</h1>

  {% if hata_mesaji %}<p><strong>{{ hata_mesaji 	}}</strong></p>{% endif %}

  <form action="{% url 'anketler:oy' soru.id %}" method="post">
  {% csrf_token %}
  {% for secim in soru.secim_set.all %}
      <input type="radio" name="secim" id="secim{{ forloop.counter 	}}" value="{{ choice.id 	}}" />
      <label for="secim{{ forloop.counter 	}}">{{ secim.secim_metni 	}}</label><br />
  {% endfor %}
  <input type="submit" value="Vote" />
  </form>

Hızlı bir özet:

Şimdi, gönderilen verileri işleyen ve onunla birlikte bir şey yapan bir Django görünümü oluşturalım. Öğretici 3‘te, bu satırı içeren yoklama uygulamaları için bir URLconf oluşturduk:

anketler/urls.py


  path('<int:soru_id>/oy/', views.oy, name='oy'),

Ayrıca, oy() işlevinin kukla bir uygulamasını oluşturduk. Hay de, gerçek bir sürüm oluşturalım. anketler/views.py dosyasına aşağıdakileri ekleyin:

anketler/views.py


  from django.shortcuts import get_object_or_404, render
  from django.http import HttpResponseRedirect, HttpResponse
  from django.urls import reverse

  from .models import Secim, Soru
  # ...
  def oy(request, soru_id):
      soru = get_object_or_404(Soru, pk=soru_id)
      try:
          secim_secildi = soru.secim_set.get(pk=request.POST['secim'])
      except (KeyError, Secim.DoesNotExist):
          # Soruyu oylama biçimini yeniden görüntüleme.
          return render(request, 'anketler/ayrinti.html', {
              'soru': soru,
              'hata_mesaji': "Herhangi bir seçim yapmadınız.",
          })
      else:
          secim_secildi.oylar += 1
          secim_secildi.save()
          # POST verileri her zmaan bir HttpResponseRedirect döndürür. Bu, bir kullanıcı "geri" düğmesine basarsa verilerin iki kez gönderilmesini önler.
          return HttpResponseRedirect(reverse('anketler:sonuclar', args=(soru.id,)))
          

Bu kod, bu derste henüz ele almadığımız birkaç şeyi içermektedir:

Öğretici 3‘de belirtildiği gibi, request bir HttpRequest nesnesidir. HttpRequest nesneleri hakkında daha fazla bilgi için istek ve yanıt (request ve response) belgelerine bakın.

Birisi bir soruyu oylamaya başladıktan sonra, oylama() görünümü sorunun sonuçlar sayfasına yönlendirilir. Bu görünümü yazalım:

anketler/views.py


  from django.shortcuts import get_object_or_404, render


  def sonuclar(request, question_id):
      soru = get_object_or_404(Soru, pk=question_id)
      return render(request, 'anketler/sonuclar.html', {'soru': soru})

Bu, Öğretici 3‘deki ayrinti() görünümüyle hemen hemen aynıdır. Tek fark şablon adıdır. Bu fazlalığı sonra çözeceğiz.

Şimdi bir anketler/sonuclar.html şablonu oluşturun:

anketler/templates/anketler/sonuclar.html


  <h1>{{ soru.soru_metni }}</h1>

  <ul>
  {% for secim in soru.secim_set.all %}
      <li>{{ secim.secim_metni }} -- {{ secim.oylar }} oy{{ secim.oylar|pluralize }}</li>
  {% endfor %}
  </ul>

  <a href="{% url 'oylar:ayrinti' soru.id %}">Tekrar oyla?</a>

Şimdi, tarayıcınızda “/anketler/1/” adresine gidin ve soruyu oylayın. Her oy verdiğinizde güncellenen bir sonuç sayfası görmelisiniz. Bir seçeneği seçmeden biçimi gönderirseniz, hata iletisini görmelisiniz.

Not

oy() görüntüsü kodumuz küçük bir sorun yaşıyor. Önce secim_secildi nesnesini veritabanından alır. Sonra oyların yeni değerini hesaplar ve daha sonra veritabanına geri kaydeder. Ağ sitenizin iki kullanıcısı aynı anda oy kullanmaya kalkarsa, bu yanlış olabilir: Aynı değeri her iki oy içinde alır. Ardında her iki kullanıcı için 43’ün yeni değeri hesaplanır ve kaydedilir. Ancak beklenen değerin sonucu 44 olur.

Buna yarış durumu denir. eğer ilgileniyorsanız bu sorunu nasıl çözebileceğinizi öğrenmek için yarış şartlarından kaçma F() konusunu okuyabilirsiniz.


Genel görünümler kullanın: Az kod daha iyidir

ayrinti() (Öğretici 3‘den) ve sonuclar() görünümleri çok basittir. Yukarıda belirtildiği gibi gereğinden fazla… Anketlerin bir listesini görüntüleyen index() görünümüne benzer.

Bu görünümler, temel ağ geliştirmesinin ortak bir örneğini temsil eder: URL’den geçirilen bir değiştirgeye göre veritabanından veri alma, bir şablon yükleme ve işlenmiş şablonu iade etme. Bu çok yaygın olduğu için Django ‘genel görünümler’ örgüsü olarak adlandırılan bir kısayol sağlar.

Genel görünümler, yaygın kalıpları bir uygulama yazmak için Python kodunu yazmak zorunda kalmadığınız noktada soyutlar.

Anket uygulamamızı genel görünüm örgüsünü kullanacak şekilde dönüştürelim. Böylece kendi kodumuzdan bir demek silebiliriz. Dönüşümü yapmak için birkaç adım atmamız gerekecek. Yapacağımız şeyler:

Ayrıntılar için okumaya devam edin.

Kod karışıklığı neden olur?

Genel olarak, bir Django uygulaması yazarken, jenerik görünümlerin sorununuza iyi uyum sağlayıp sağlamadığını değerlendireceksiniz ve kodunuzu ara ara yeniden biçimlendirmek yerine baştan kullanacaksınız. Ancak bu öğretici kısıtlı olarak, çekirdek kavramlara odaklanmak için şu ana kadar “uzun yoldan” görünümleri anlattı.

Bir hesap makinesini kullanmaya başlamadan önce temel matematiği öğrenmelisin meselesi…

URLconf değiştirin

İlk olarak, anketler/urls.py URLconf’i açın ve şu şekilde değiştirin:

anketler/urls.py


from django.urls import path

from . import views

app_name = 'anketler'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.AyrintiView.as_view(), name='ayrinti'),
    path('<int:pk>/sonuclar/', views.SonuclarView.as_view(), name='sonuclar'),
    path('<int:soru_id>/oy/', views.oy, name='oy'),
]

İkinci ve üçüncü desenlerin yol dizelerinde eşleşen desenin adı soru_id’den pk’ya geçtine dikkat edin.


Görünümleri değiştirin

Sırada… Eski dizin, ayrıntı ve sonuç görünümlerimizi kaldıracağız. Bunun yerine Django’nun genel görünümlerini kullanacağız. Bunu yapmak için anketler/views.py dosyasını açın ve şu şekilde değiştirin:

anketler/views.py


  from django.shortcuts import get_object_or_404, render
  from django.http import HttpResponseRedirect
  from django.urls import reverse
  from django.views import generic

  from .models import Secim, Soru


  class IndexView(generic.ListView):
      tema_adi = 'anketler/index.html'
      baglam_nesnesinin_adi = 'son_sorular_listesi'

      def get_queryset(self):
          """En son yayınlanan 5 soruyu getir."""
          return Soru.objects.order_by('-yayim_tarihi')[:5]


  class AyrintiView(generic.DetailView):
      model = Soru
      tema_adi = 'anketler/ayrinti.html'


  class SonuclarView(generic.DetailView):
      model = Soru
      tema_adi = 'anketler/sonuclar.html'


  def oy(request, soru_id):
      ... # bundan sonra değişiklik gerekmiyor.

Burada iki genel görünüm kullanıyoruz: ListeView ve AyrintiView. Her iki görünümde de “nesnelerin listesi gösteriliyor”. Belirli bir nesne türü için ayrıntı sayfası görüntüleme kavramlarını özetlemek gerekir.

Varsayılan olarak, AyrintiView genel görünümü // _ayrinti.html adlı bir şablon kullanır. Bizim durumumuzda "anketler/soru_ayrinti.html" şablonu kullanacaktır. tema_adi özniteliği, doğal oalrak oluşturulmuş varsayılan şablon adı yerine belirli bir şablon adı kullanmasını Django'ya söylemek için kullanır. Ayrıca, sonuç listesi görünümü için tema_adi da belirtilir. Bu, sonuç görünümün ve ayrıntı görünümün arkasında bir AyrintiView olmasına rağmen işlendiğinde farklı bir görünüme sahip olmasını sağlar.

Benzer şekide, ListeView genel görünümü // _liste.html olarak adlandırılan varsayılan şablonu kullanır. ListeView'a mevcut "anketler/index.html" şablonumuzu kullanmasını söylemek için tema_adi kullanıyoruz.

Öğreticinin önceki bölümlerinde şablonlara soru ve son_sorular_listesi bağlam değişkenlerini içeren bir bağlam verilmiştir. AyrintiView için soru değişkeni doğal olarak sağlanır. Çünkü Django modeli (Soru) kullanıyoruz. Django bağlam değişkeni için uygun bir ad belirleyebiliyor. Bununla birlikte, ListeView iin doğal olarak oluşturulan bağlam değişkeni soru_listesi’dir. Bunu geçersiz kulmak için bunun yerine son_sorular_listesi’i kullanmak istediğimizi belirten baglam_nesnesinin_adi niteliğini sağlıyoruz. Seçeneksel yaklaşım olarak şablonlarınızı yeni varsayılan içerik değişkenleriyle eşleşecek şekilde değiştirebilirsiniz. Ancak Django’ya istediğiniz değişkeni kullanmasını söylemek çok daha kolaydır.

Sunucuyu çalıştırın ve genel görünümlere dayalı yeni anket uygulamanızı kullanın.

Genel görünümler hakkında ayrıntılı bilgi için genel görünüm belgelerine bakın.

Biçimlere ve genel görünümlere uygun olduğunda, anket uygulamalarımızı denemek hakkında bilgi edinebilirsiniz. Bunun için Öğretici 5 bölümünü okuyun.