Kategori arşivi: Django

Django Framework hakkında Türkçe bilgiler, ipuçları, kod örnekleri, örnek projeler, sorunlar ve çözümler, fikir alışverişi, düşünceler ve daha fazlası

Django Uygulamalarında Varnish Cache Kullanımı

Varnish web sitelerini hızlandırmak için kullanılan bir Reverse Proxy aracıdır. Ziyaretçilere asıl sunucu gibi gözüken bir ara katman vekilidir. Cache aldığı dosyaları bellek üzerinde tutabilir.

Django üzerinde geliştirdiğiniz bir proje zamanla alıp yürürse ve uygulama üzerinde tuttuğunuz Cache(Yani önbellek) zamanla işe yaramamaya başlarsa yapılandırmanız içerisine Varnish ekleyebilirsiniz.

Aşağıda bulunan yapılandırmayı kullanarak Django üzerinde statik dosyaların 1 yıl, sayfa ve diğer bileşenlerin ise 15 dakikalık önbelleklerini tutabilirsiniz.

Yapılandırmaya önbellek silme bileşenleri eklemediğimi özellikle hatırlatayım.

Django Komutları

Django uygulaması geliştirirken özellikle kullandığımız komut ve kısayollar bu belgede gösterilmiştir.

#KomutAçıklama
1./manage.py makemigrations Django’ya modellerinde değişiklik yaptığınızı ve bu değişikliklerin saklanmasını istediğinizi söyler.
2./manage.py sqlmigrateAdlandırılan migrasyonda SQL komutlarını ekrana yazdırır. Aktif bir veritabanı bağlantısı gerektirir.
3./manage.py checkVeri tabanına dokunmadan ve herhangi bir migrasyon yapmadan sorunları tespit etmek için kullanılır.
4./manage.py migrateuygulanmamış tüm migrasyonları alır ve veritabanınıza uygular. Modelde yapılan bütün değişiklikleri veri tabanına yazmakla görevlidir.
5./manage.py dumpdata –exclude auth.permission –exclude contenttypes > db.json Veritabanı yedeğini .json formatı olarak alır.
6./manage.py loaddata db.jsonVeritabanı yedeğinden geri yükleme.

Python 3 sürümü üzerine temel kurulum ve virtualenv ayarlama

#KomutAçıklama
1virtualenv -p python3 envSanal ortam oluşturmak için gerekli olan klasörü oluşturur
2source env/bin/activateSanal ortamı etkinleştirmek için kullanılır
3pip install djangoEtkinleştirdiğimiz sanal ortamımızda django uygulamamızı kurar
4pip install -r requirements.txtDjango bağımlılıklarının requirements.txt aracılığı ile kurulumu
5django-admin.py startproject testtest adında yeni bir proje başlatır.
6./manage.py runserverDjango sunucusunu başlatır.
7python3 manage.py runserver 0.0.0.0:8001Django sunucusunu spesifik bir port ile başlatır.
8python3 manage.py createsuperuser Django için yetkili kullanıcı oluşturmak
9CTRL + CÇalışan django sunucusunu kapatır.
10deactivateSanal ortamı devre dışı bırakır.

Django Form Yapısı Ve İş Akışı

Django, formlarla çalışabilmemizi sağlayan kapsamlı bir takım enstrümanlar sunan özel bir yapıya sahiptir. Bu yapı özellikleri arasında, tek bir konumda form işlevselliği tanımlama, veri doğrulama ve Django modelleri ile entegrasyonlar yer alır, şimdi ufak bir örnek ile durumun nasıl işlediğine kısaca bakalım.

Form oluşturulması için django uygulamamız içerisinde forms.py adlı bir dosya oluşturuyoruz. İçerisini ise aşağıdaki gibi oluşturuyorum. Djangoda formların belirli bir dosya içerisinde bulunması gerekmediğinide hatırlatırım. Yani isterseniz forms.py oluşturmak yerine, uygulama dosyalarınızın içerisinde de barındırabilirsiniz. Örneğin: models.py veya views.py içerisinde formlar yer alabilirler.

from django import forms

class Contact(forms.Form):
      name = forms.CharField(required=False)
      email = forms.EmailField(label='Your email')  
      subject = forms.CharField(widget=forms.Textarea)

Burada en önemli nokta django’da formların forms.Form sınıfının bir alt sınıfı olarak alınması gerekmektedir. Bu yüzden otomatik olarak form yapısı içerisindeki bütün sınıflara eklenmesi gerekmektedir. Daha sonra, form sınıfının forms.CharField türünde ve form.EmailField türlerinden biri olan üç özellik olduğunu görebilirsiniz. Bu form alanı tanımları, belirli özelliklere karşılık gelir ve girdiyi kısıtlar.

Örneğin, forms.CharField girdinin bir dizi karakter ve form olması gerektiğini belirtir. forms.EmailField ise girdinin bir e-posta olması gerektiğini belirtir. Ayrıca, her bir form alanının, girdi türünü daha da kısıtlamak için özellikler (örn. required) içerdiğini görebilirsiniz. Şimdilik bu Django form alanı türleri hakkında yeterli bilgiyi size verecektir.

Formumuzu oluşturduktan hemen sonra, gelin bu oluşturduğumuz formu projemizin views.py dosyası içerisinde nasıl kullanılabileceğine bakalım.

from django.shortcuts import render
from .forms import Contact

def contact(request):
    form = Contact()
    return render(request,'about/contact.html',{'form': form})

Oluşturduğumuz views.py içerisindeki contact fonksiyonu, önce Contact form sınıfını bir önceki örneğimizden teslim alıp başlatır ve bunu form referansına atar. Bu form başvurusu daha sonra about/contact.html şablonunda kullanılabilir hale getirilecek bir argüman olarak iletilir.

Ardından, Django’da kullandığımız şablonunun içinde Django formunu normal bir değişken olarak verebilirsiniz. standart şablon sözdizimini {{ form.as_table }} olarak kullanırsanız. Çıktısı aşağıdaki gibi olacaktır.

<tr>
	<th><label for="id_name">Name:</label></th>
	<td><input id="id_name" name="name" type="text" /></td>
</tr>
<tr>
	<th><label for="id_email">Your email:</label></th>
	<td><input id="id_email" required name="email" type="email" /></td>
</tr>
<tr>
	<th><label for="id_comment">Comment:</label></th>
	<td><textarea cols="40" id="id_comment" required name="comment" rows="10"></textarea></td>
</tr>

Django formunun HTML etiketlerine nasıl çevrildiğini gördünüz! Django formunun her form alanı için uygun HTML <input> etiketlerini nasıl ürettiğine dikkat edin (ör. Forms.EmailField(label = ‘E-postanız’), istemci tarafını bu alanı doldurmaya zorlamak adına <label> içerisine required ekler ve HTML5 tipini type="email" olarak ayarlar. ve bir e-postanın doğrulanması da bu şekilde sağlanmış olur). Ayrıca, form alanında kullanılan bir takım alanların gerekliliklerini değiştirebilirsiniz. Bunu form yapısında devredışı bırakmak için required=False olarak düzenleyin.

Ayrıca söz diziminde kullandığımız as_table ile çıktının HTML5 tablo yapısında olmasını işlerimizi kolaylaştırdığı için istedik. İsterseniz dokümantasyon aracılığı ile daha sonradan kendi yapınıza uygun olanı seçip kullanabilirsiniz.

Tüm bunları görsel bir şekilde anlatmamız gerekirse aşağıdaki şablon sizin için yeterli olacaktır.

django form yapi yeni

Django Form İş Akışı

Bu noktaya kadar anlattıklarım. Django form sınıfına dayalı boş bir form döndürdük ve teorik olarak devam ettik. Django formlarını işlevsel bir hale getirmek için eksik parçaları hadi gelin hep birlikte tamamlayalım. Eksik parçaları ekleyelim.

Şimdiye kadar bir Django form sınıfı tanımının hızlı bir şekilde bir HTML formuna dönüştürülebileceğini öğrendiniz. Ancak bu otomatik HTML olayı, Django form sınıfı tanımlarını kullanmanın sadece bir ufak bölümüdür. Ayrıca form değerlerini doğrulayabilir ve hataları son kullanıcıya daha hızlı gösterebilirsiniz istersenizde kendi yapınızı kurarak yolunuza devam edebilirsiniz.

<form method="POST">{% csrf_token %}

{{form.as_p}}
<input type="submit" value="Kaydet" />

</form>

Şimdi oluşturduğumuz formun tüm web formları için standart olan HTML <form> yapısını oluşturacak. method tanımını POST olarak kullandık. POST yöntemi, kullanıcı verilerini işleyen web formlarında standart bir uygulamadır. Alternatif bir yöntem olarakta GET kullanabilirsiniz. Ancak, kullanıcı tarafından sağlanan verileri aktarmak için kullanılabilecek bir seçenek değildir.(genellikle)

Action tanımlaması yapmadığımızı fark etmişsinizdir. Bu durumda istek bulunan mevcut sayfaya aktarılacaktır. {% csrf_token %} ise POST isteği yoluyla gönderildiği ve Django tarafından işlendiği durumlar için ayrılan özel bir etikettir. Django tarafından uygulanan standart bir güvenlik mekanizması olan Cross-Site Request Forgery(Siteler Arası İstek Sahtekarlığı) anlamına gelir.

CSRF’yi devre dışı bırakmak ve formlarda {% csrf_token%} Django etiketini dahil etmemek mümkün olsa da, CSRF bir güvenlik önlemi olarak çalıştığı için, {% csrf_token%} Django etiketini POST ile gelen tüm formlara eklemeye devam etmenizi öneririz.

{{form.as_p}} ise form yapısını oluştururken diğer elementlerin <p&gt ile sarılması ve çıktıların satır satır işlenmesidir. Şimdi herşey kısmen hazır olduğuna göre gelelim isteklerin işleneceği views.py düzenlemeye kodumuz aşağıdaki gibi olacak

from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import ContactForm

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/about/')
    else:
        form = ContactForm()
    return render(request,'about/contact.html',{'form':form})

Yukarıdaki örneğimizde en önemli nokta isteklerin işlendiği bölüm olan if/else yapısıdır. Yapılacak işlemlerimizi buna göre basitçe belirleyebiliriz. POST isteği gelirse ayrı, GET isteği gelirse ayrı olarak işleme alınaktır. POST mantığına daha yakından bakalım. İstek türü POST ise, gelen kullanıcı verisi var demektir, bu yüzden gelen veriye request.POST referansı ile erişir ve Django formunu onunla başlatırız. Ancak, bireysel form alanlarına erişmenin veya parça parça atamaları yapmanın gerekmediğine dikkat edin.

Bu noktada, bir kullanıcının Django form alan tanımları ile ilgili geçerli bir veri sağlayıp sağlamadığını hala bilmiyoruz (örneğin, değerler metinse veya geçerli bir e-posta değilse). Bir formun verilerini doğrulamak için, bağlı form örneğinde is_valid() yöntemini kullanmanız gerekir. Eğer form.is_valid() True ise veriler işlenir ve sonraki işlem yapılır, return ile URL’ye yönlendirme ile son bulur. form.is_valid() öğesi false ise form verilerinin hataları olduğu anlamına gelir; ve istenen şekilde ister kullanıcıya mesaj ulaştırılır istersede form tekrar gösterilir.

CSRF veya siteler arası talep sahteciliği, siber suçluların kullanıcıları bir web uygulamasında istenmeyen eylemleri gerçekleştirmeye zorlamak için kullandıkları bir tekniktir. Kullanıcılar web formlarıyla etkileşimde bulunduklarında, sipariş vermekten (örn. Ürünler, para transferleri) verilerinin değiştirilmesine (ör. Ad, e-posta, adres) kadar değişen her türlü durum değiştiren görevleri yaparlar. Çoğu kullanıcı, bir HTTPS/SSL güvenli kilit sembolü gördüklerinden veya bir web formuyla etkileşimde bulunmadan önce kullanıcı adı ve parola kullandıkları için web formlarıyla etkileşimde bulunduklarında daha yüksek güvenlik duygusu hissetmeye eğilimlidirler.

Bir CSRF saldırısı, web uygulamasında sosyal mühendislik ve lax uygulama güvenliğine büyük ölçüde dayanır; bu nedenle, saldırı vektörü diğer güvenlik önlemlerine (örn. HTTPS/SSL, güçlü parola) bakılmaksızın çalışır.

django csrf temsili

Görebildiğiniz gibi, bir CSRF saldırısı gerçekleştirmek için, bir kullanıcının belirli bir sitede aktif bir oturuma sahip olması ve bir kullanıcının bir eylemi veya bir eylemi gerçekleştiren bir sayfayı tıklatması için kandırılması yeterlidir. Bu nedenle terimin adı: “Siteler arası”, istek orijinal siteden gelmiyor, çünkü bu siber suçlunun sahte bir isteğidir.

Web formları, bir kullanıcı için benzersiz olan ve bir oturum tanımlayıcısına benzer bir son kullanma süresine sahip , genellikle bir CSRF belirteci şeklinde adlandırılan benzersiz bir alan daha içermelidir.

django tokenli koruma

UWSGI ve NGINX ile Django Uygulaması Nasıl Kullanılır

Django, kodunuzu test etmek için oldukça basit bir web sunucusu ile gelir ve bu sunucu ile siteyi test aşamasında sorunsuz bir şekilde çalıştırıp kullanabiliriz, ancak uygulamanın geliştirilme aşaması tamamlandıktan sonra yayına alma sırasında bu web sunucunun kullanılması önerilmez.

Bu yüzden araya harici bir web sunucusu eklememiz gerekir. Bunun için biz makalemizde uWSGI kullanacağız. Diğer uygulamalara göre hız bakımından olumlu yönde bir artış söz konusu olacak. Ayrıca statik içerikleri de NGINX ile sunacağız.

Kullanacağımız yapı ise şu şekilde olacak

uwsgi django nginx diagrami

uWSGI’ye socket oluşturmasını sağlıyoruz ve protokol aracılığı ile NGINX kardeşimizin servis etmesini ve dış dünyaya açılmasını sağlıyoruz.
Django 1.4 sürümünden sonra zaten wsgi modülü otomatik kendisi oluşturduğundan dolayı python tarafında yapacağımız bir şey kalmamış oluyor. Sadece modülün yerini bulmamız ve not almamız bizim için yeterli

Şimdi gerekli enstrümanların kurulumuna geçiyoruz. Debian 9 için aşağıdaki işlemleri yaparak bize lazım olan paketleri sisteme dahil ediyoruz.

apt install uwsgi nginx

uWSGI sisteme dahil edileceği sırada. Sistem için NGINX kurulumu da yapılacak isterseniz güncel sürüme yükseltebilirsiniz. Mevcut NGINX sürümü 1.10.3 kurulacak.
NGINX kurulduktan sonra yapılandırma dosyamız içerisine aşağıdaki satırları ekliyoruz. Bu sayede dış dünya ile django uygulamamız iletişim kurmuş oluyor.

    location / {
        include         uwsgi_params;
        uwsgi_pass      127.0.0.1:8000;
    }

Yaptıklarımız bunlarla da sınırlı kalmayacak. uWSGI üzerinde bir takım ayarlamalarda yapmamız gerekecek
Uygulamamız için örnek oluşturması adına benim kullandığım uwsgi.ini yapılandırma dosyası aşağıdaki gibidir.

[uwsgi]
plugins = python3
thread=3
master=1
max-requests = 50000
env = DJANGO_SETTINGS_MODULE=TPaste.settings
module = TPaste.wsgi:application
chdir = /home/mertcan/myproject
socket = 127.0.0.1:8000
logto = /tmp/django.log

Şimdi bu işlemleri otomatize etmek ve birazda bizim işlerimizi kolaylaştırmak için supervisor kuralım ve üzerinde gereken yapılandırmayı yapalım. Bunun için sisteme aşağıdaki komut aracılığı ile enstrümanın kurulumunu tamamlayalım.

apt install supervisor

Django uygulamamız için gereken yapılandırmayı /etc/supervisor/conf.d/ içerisine yapacağız. Benim oluşturduğum ve kullanacağım yapılandırma şu şekilde

[program:uwsgi]
user = mertcan
command=/usr/local/bin/uwsgi --ini /home/mertcan/uwsgi.ini
autostart=true
autorestart=true
stderr_logfile = /var/log/uwsgi_err.log
stdout_logfile = /var/log/uwsgi_out.log
stopsignail = QUIT

Yapılandırma dosyamızı supervisorümüze kabul ettirmemiz gerekiyor bunun için ise supervisorctl reread komutunu vermeniz yeterli bu sayede yapılandırma dosyalarını yenilemiş oluyoruz. Oluşturduğumuz yapılandırma dosyasındaki değişikliği tamamlamak için supervisorctl update komutu ile işlemlerimizi sonlandırıyoruz.


Setting up Django and your web server with uWSGI and nginx

Django ReCaptcha Eklenti Düzenleme

Günlerden bir gün django projesi ile baya içli dışlı olmuştuk ve recaptcha uygulaması gerekiyordu. Var olan uygulamaya da baktık kurması dert kurcalaması dert bizde düşündük zaten açık kaynak kodlu kodları kendi içimize alalım hem daha sonradan değişiklik yapılacaksa bize kod bakımından kolay olur.

İlk önce tabi düşündük sıfırdan yazalım diye ancak daha sonradan uğraşmak istemedik. Aşağıdakileri sırasıyla projenize dahil etmeniz yeterli.

fields.py

import os
import sys
import socket
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_text as smart_unicode
from StreamingTwitter.widgets import ReCaptcha
from StreamingTwitter.ReCaptcha import submit

TEST_PUBLIC_KEY = '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
TEST_PRIVATE_KEY = '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'


class ReCaptchaField(forms.CharField):
    default_error_messages = {
        'captcha_invalid': _('Incorrect, please try again.'),
        'captcha_error': _('Error verifying input, please try again.'),
    }

    def __init__(self, public_key=None, private_key=None, use_ssl=None,
                 attrs=None, *args, **kwargs):
        """
        ReCaptchaField can accepts attributes which is a dictionary of
        attributes to be passed to the ReCaptcha widget class. The widget will
        loop over any options added and create the RecaptchaOptions
        JavaScript variables as specified in
        https://developers.google.com/recaptcha/intro
        """
        if attrs is None:
            attrs = {}
        public_key = public_key if public_key else 
            getattr(settings, 'RECAPTCHA_PUBLIC_KEY', TEST_PUBLIC_KEY)
        self.private_key = private_key if private_key else 
            getattr(settings, 'RECAPTCHA_PRIVATE_KEY', TEST_PRIVATE_KEY)
        self.use_ssl = use_ssl if use_ssl is not None else getattr(
            settings, 'RECAPTCHA_USE_SSL', True)

        self.widget = ReCaptcha(
            public_key=public_key, use_ssl=self.use_ssl, attrs=attrs)
        self.required = True
        super(ReCaptchaField, self).__init__(*args, **kwargs)

    def get_remote_ip(self):
        f = sys._getframe()
        while f:
            if 'request' in f.f_locals:
                request = f.f_locals['request']
                if request:
                    remote_ip = request.META.get('REMOTE_ADDR', '')
                    forwarded_ip = request.META.get('HTTP_X_FORWARDED_FOR', '')
                    ip = remote_ip if not forwarded_ip else forwarded_ip
                    return ip
            f = f.f_back

    def clean(self, values):
        super(ReCaptchaField, self).clean(values[1])
        recaptcha_challenge_value = smart_unicode(values[0])
        recaptcha_response_value = smart_unicode(values[1])

        if os.environ.get('RECAPTCHA_TESTING', None) == 'True' and 
                        recaptcha_response_value == 'PASSED':
            return values[0]

        if not self.required:
            return

        try:
            check_captcha = submit(
                recaptcha_challenge_value,
                recaptcha_response_value, private_key=self.private_key,
                remoteip=self.get_remote_ip(), use_ssl=self.use_ssl)

        except socket.error:  # Catch timeouts, etc
            raise ValidationError(
                self.error_messages['captcha_error']
            )

        if not check_captcha.is_valid:
            raise ValidationError(
                self.error_messages['captcha_invalid']
            )
        return values[0]

widgets.py

from StreamingTwitter.ReCaptcha import displayhtml
from django.utils.safestring import mark_safe
from django import forms
from django.conf import settings

TEST_PUBLIC_KEY = '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'


class ReCaptcha(forms.widgets.Widget):
    if getattr(settings, "NOCAPTCHA", False):
        recaptcha_response_name = 'g-recaptcha-response'
        recaptcha_challenge_name = 'g-recaptcha-response'
    else:
        recaptcha_challenge_name = 'recaptcha_challenge_field'
        recaptcha_response_name = 'recaptcha_response_field'

    def __init__(self, public_key=None, use_ssl=None, attrs=None, *args,
                 **kwargs):
        self.public_key = public_key or getattr(settings, 'RECAPTCHA_PUBLIC_KEY', TEST_PUBLIC_KEY)
        if attrs is None:
            attrs = {}
        self.use_ssl = use_ssl if use_ssl is not None else getattr(
            settings, 'RECAPTCHA_USE_SSL', True)
        self.js_attrs = attrs
        super(ReCaptcha, self).__init__(*args, **kwargs)

    def render(self, name, value, attrs=None):
        return mark_safe(u'%s' % displayhtml(
            self.public_key,
            self.js_attrs, use_ssl=self.use_ssl))

    def value_from_datadict(self, data, files, name):
        return [
            data.get(self.recaptcha_challenge_name, None),
            data.get(self.recaptcha_response_name, None)
        ]

ReCaptcha.py

import json
from django.conf import settings
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from urllib.parse import urlencode
from urllib.request import build_opener, ProxyHandler, Request, urlopen

DEFAULT_API_SSL_SERVER = "//www.google.com/recaptcha/api"
DEFAULT_API_SERVER = "//www.google.com/recaptcha/api"
DEFAULT_VERIFY_SERVER = "www.google.com"
DEFAULT_WIDGET_TEMPLATE = 'captcha/captcha.html'

API_SSL_SERVER = getattr(settings, "CAPTCHA_API_SSL_SERVER",
                         DEFAULT_API_SSL_SERVER)
API_SERVER = getattr(settings, "CAPTCHA_API_SERVER", DEFAULT_API_SERVER)
VERIFY_SERVER = getattr(settings, "CAPTCHA_VERIFY_SERVER",
                        DEFAULT_VERIFY_SERVER)
WIDGET_TEMPLATE = getattr(settings, "CAPTCHA_WIDGET_TEMPLATE",
                          DEFAULT_WIDGET_TEMPLATE)


def want_bytes(s, encoding='utf-8', errors='strict'):
    if isinstance(s, str):
        s = s.encode(encoding, errors)
    return s


class RecaptchaResponse(object):
    def __init__(self, is_valid, error_code=None):
        self.is_valid = is_valid
        self.error_code = error_code


def displayhtml(public_key,
                attrs,
                use_ssl=True,
                error=None):
    """Gets the HTML to display for reCAPTCHA
    public_key -- The public api key
    use_ssl -- Should the request be sent over ssl? (deprecated)
    error -- An error message to display (from RecaptchaResponse.error_code)"""

    error_param = ''
    if error:
        error_param = '&error=%s' % error

    if use_ssl:
        server = API_SSL_SERVER
    else:
        server = API_SERVER

    return render_to_string(
        WIDGET_TEMPLATE,
        {'api_server': server,
         'public_key': public_key,
         'error_param': error_param,
         'options': mark_safe(json.dumps(attrs, indent=2)),
         'options_dict': attrs,
         })


def request(*args, **kwargs):
    """
    Make a HTTP request with a proxy if configured.
    """
    if getattr(settings, 'RECAPTCHA_PROXY', False):
        proxy = ProxyHandler({
            'http': settings.RECAPTCHA_PROXY,
            'https': settings.RECAPTCHA_PROXY,
        })
        opener = build_opener(proxy)

        return opener.open(*args, **kwargs)
    else:
        return urlopen(*args, **kwargs)


def submit(recaptcha_challenge_field,
           recaptcha_response_field,
           private_key,
           remoteip,
           use_ssl=False):
    if not (recaptcha_response_field and recaptcha_challenge_field and
                len(recaptcha_response_field) and len(recaptcha_challenge_field)):
        return RecaptchaResponse(
            is_valid=False,
            error_code='incorrect-captcha-sol'
        )

    if getattr(settings, "NOCAPTCHA", False):
        params = urlencode({
            'secret': want_bytes(private_key),
            'response': want_bytes(recaptcha_response_field),
            'remoteip': want_bytes(remoteip),
        })
    else:
        params = urlencode({
            'privatekey': want_bytes(private_key),
            'remoteip': want_bytes(remoteip),
            'challenge': want_bytes(recaptcha_challenge_field),
            'response': want_bytes(recaptcha_response_field),
        })

    params = params.encode('utf-8')

    if use_ssl:
        verify_url = 'https://%s/recaptcha/api/verify' % VERIFY_SERVER
    else:
        verify_url = 'http://%s/recaptcha/api/verify' % VERIFY_SERVER

    if getattr(settings, "NOCAPTCHA", False):
        verify_url = 'https://%s/recaptcha/api/siteverify' % VERIFY_SERVER

    req = Request(
        url=verify_url,
        data=params,
        headers={
            'Content-type': 'application/x-www-form-urlencoded',
            'User-agent': 'Stream reCAPTCHA Python'
        }
    )

    httpresp = request(req)
    if getattr(settings, "NOCAPTCHA", False):
        data = json.loads(httpresp.read().decode('utf-8'))
        return_code = data['success']
        return_values = [return_code, None]
        if return_code:
            return_code = 'true'
        else:
            return_code = 'false'
    else:
        return_values = httpresp.read().decode('utf-8').splitlines()
        return_code = return_values[0]

    httpresp.close()

    if (return_code == "true"):
        return RecaptchaResponse(is_valid=True)
    else:
        return RecaptchaResponse(is_valid=False, error_code=return_values[1])

Ardından projenizde nerede kullanacaksanız. Direk olarak oraya aşağıdaki gibi bir ekleme yaparak html içerisine çağırmanız yeterli

views.py dosyanızın içerisine aşağıdaki satırları ekleyin.

re_captcha = {'captcha': FormWithCaptcha()}

HTML dosyanız içerisine de

{{ captcha }}

Tam olarak çalışmasını istiyorsak settings.py dosyasına şu kısımları da eklemeyi unutmayın

RECAPTCHA_PUBLIC_KEY = '6Le61ykTAAAAACmvsDyHdzYHei_xkS4fNjEYFgmO'
RECAPTCHA_SECRET_KEY = '6Le61ykTAAAAABEXwzMb9r_-J8kr9VfoNa0jWk_'
NOCAPTCHA = True

Recaptcha özelliği otomatik olarak gelecek ve kolaylıkla yönetebileceksiniz. Ayrıca bu eklenti ile birden fazla sayfada ReCaptcha özelliğini aktif edip kullanabilmenize imkan sağlar diğerleri gibi sadece tek sayfada kullanılabilir bir şekilde ayarlanmamıştır.