26 Aralık 2013 Perşembe
16 Kasım 2013 Cumartesi
Python Metot Türleri @classmethod @staticmethod
Python sınıflarında, temel olarak 3 farklı şekilde metot tanımı yapılabilir.
- Örnek (Instance) metotları
- Statik (
@staticmethod
) metotlar - Sınıf (
@classmethod
) metotları
self
adı verilir. Statik metotlar, kendisini çağıran sınıf veya örnek hakkında herhangi bir bilgiye
sahip değildir. Bunlar, işlevini kaybetmeden, sınıf dışında da aynı şekilde tanımlanabilir. Sınıf metotları ise, otomatik
olarak, kendisini çağıran sınıfa veya örneğin sınıfına bir referans alır. Bu argümana da geleneksel olarak cls
adı verilir.Örnek (Instance) Metotları
Python'da yeni bir sınıf tanımlandığınız, yazdığınız metotlar öntanımlı olarak, örnek (instance) metotlarıdır. Örnek metotları, ilk argüman olarak, kendisini çağıran örneğe bir referans alır. Böylece, geçerli örneğin niteliklerine erişim ve müdahale imkanı bulurlar. Aşağıdaki kodları inceleyelim;
class ikisayi(object): def __init__(self, a, b): self.a = a self.b = b def toplam(self): return self.a + self.b x = ikisayi(3,5) print(x.toplam) # 1 print(ikisayi.toplam) # 2 print(x.toplam()) # 3 print(ikisayi.toplam(x)) # 4
Programın çıktısı:
#1: <bound method ikisayi.toplam of <__main__.ikisayi object at 0x021F0390>> #2: <unbound method ikisayi.toplam> #3: 8 #4: 8 Yukarıda, görmeye alışık olduğunuz türden bir sınıf tanımımız var. Bu sınıf, iki tane sayı hakkında veri tutmak için kullanılıyor. Yine, bolca karşınıza çıkacağı gibi
__init__
başlangıç metodu var. toplam
metodu ise, normal şekilde tanımlanmış, yani bir
örnek (instance) metodu. toplam
metodumuz, her örnek metodunda olduğu gibi, zorunlu bir ilk argüman alıyor. Bu argümana, çalışma
anında oluşturulmuş bir ikisayı objesi geçirilecek. Böylece, toplam metodu, hangi objenin a
niteliğiyle b
niteliğini toplaması gerektiğini bilebilecek.Program çıktısına dikkat edersek,
x.toplam
metodunun bound method
olduğunu görüyoruz.Yani, ikisayi.toplam
metodu belirtilen adresdeki ikisayi
objesine
bağlanmış. Yani, x.toplam
metodu çağırıldığında, ikisayi.toplam
metodu, ilk argüman olarak, o adresdeki objeyi alacak.Diğer yandan, aynı metoda, sınıf üzerinde eriştiğimizde, bir
unbound method
buluyoruz.Yani, bu method, herhangi bir örneğe bağlanmamış. Dolayısıyla,
otomatik bir ilk argüman almayacak. Eğer ikisayi.toplam()
şeklinde çağırırsanız, aşağıdaki hatayı alırsınız:TypeError: unbound method toplam() must be called with ikisayi instance as first argument
#3 ve #4 numaralı ifadeler aynı çıktıyı veriyor, çünkü, teknik olarak aynı şeyler. Siz,
x.toplam()
çağırdığınızda, Python bunu kendi içinde ikisayi.toplam(x)
şekline dönüştürüyor. Statik Metotlar
Statik Metotlar, kendisini hangi sınıf veya örneğin çağırdığını bilmez. Sadece kendine verilen argümanları bilir, örnek veya sınıf metotları gibi, gizli bir ilk argüman almazlar. Bu yönden bakıldığında, bu fonksiyonun sınıf içinde yazılmasıyla, sınıf dışında yazılması arasında, hiçbir fark yoktur. Ancak, aynı modül içerisindeki birçok fonksiyonu anlamsal bütünler içinde toplamak gerektiğinde kullanılabilir. Bunları tanımlamak için, metot tanımından önce@staticmethod
dekoratörü kullanılır.Sınıf Metotları
Diğer yandan, sınıf metotları, ilk argüman olarak, kendisini çağıran sınıfa veya kendisini çağıran örneğin sınıfına mecburi/otomatik bir referans alır. Bunu o sınıfın bir örneğini oluşturmak istediğiniz durumlarda (bkz: Factory) kullanabilirsiniz. Kendisini çağıran sınıfa bir referans aldığı için, alt sınıflarda da istenildiği gibi çalışacaktır. Örneğin, diyelim ki, bir telefon numarasını temsil eden bir sınıfınız var:class TelNo(object): def __init__(self, ulkekodu, alankodu, numara): self.ulkekodu = ulkekodu self.alankodu = alankodu self.numara = numara
def str_to_telno(string): return TelNo(*string.split(" ")) mytel = str_to_telno("+90 507 7997272")
str_to_telno
fonksiyonu, verilen karakter dizisini
boşluklarından bölüp, bunlardan yeni bir TelNo objesi oluşturuyor.
Telefon numarası tutabilmek
güzel ama, bu numarayı arayabilmemiz daha da güzel olurdu. Bunun için,
TelNo'nun aranabilen bir alt sınıfını oluşturalım. class AranabilenTelNo(TelNo): def ara(self): "bu numaraya VOIP üzerinden bağlantı kur" pass # gerçekten bu fonksiyonu kodlamamı beklemiyordunuz umarım :) def str_to_aranabilentelno(string): return AranabilenTelNo(*string.split(" "))
Bu yöntemin şöyle bir sıkıntısı var. Diyelim ki, ileride, mesaj atılabilen telno, mms gönderilebilen tel no vs. gibi bir çok alt sınıf tanımlayacaksınız. Her seferinde tek tek bu dönüşüm işlemini yapmak hem yorucu olacak, hem de kodlar çorba olacak.
Buna alternatif olarak,
TelNo
objesinde, from_string
isminde bir @classmethod
tanımladığımızda, ne olduğuna bakalım;class TelNo(object): def __init__(self, ulkekodu, alankodu, numara): self.ulkekodu = ulkekodu self.alankodu = alankodu self.numara = numara @classmethod def from_string(cls, string): return cls(*string.split(" ")) class AranabilenTelNo(TelNo): def ara(self): pass mytel = TelNo.from_string("+90 507 7997272") print(type(mytel)) # 1 myaranabilentel = AranabilenTelNo.from_string("+90 507 7997272") print(type(myaranabilentel)) # 2
#1: <class '__main__.TelNo'> #2: <class '__main__.AranabilenTelNo'> Program çıktısından görebileceğiniz gibi, iki sınıfın
from_string
metotları, doğru sınıfa ait objeler oluşturuyor. Böylece,
hem alt sınıf için tekrar ayrı fonksiyon yazmak zorunda kalmadık, hem de, doğru sınıfa ait bir örnek oluşturabildik.Dikkat ettiyseniz,
@classmethod
ile tanımladığımız metotları, doğrudan sınıf üzerinden çağırdık. Halbuki, Örnek (Instance) metotlarını, sınıfın bir örneği
üzerinden çağırıyorduk. Özetle, sınıfın kendisi ile ilgili işlem yapılacak durumlarda, @classmethod
kullanabiliriz.s10 Kasım 2013 Pazar
Tornado websocket client
Tornado'nun sunucu hizmetleri ile ilgili bir sürü örnek var ama istemci
olarak hele hele WebSocket için neredeyse hiçbir örnek bulamadım
internette, onun için buraya yazalım dursun, bir gün birine lazım olur.
from tornado import websocket, ioloop, gen, escape
class SocketClient():
def __init__(self):
self.headers = httputil.HTTPHeaders()
self.headers['Content-Type'] = 'application/json'
self.request = httpclient.HTTPRequest(
url = "wss://some.url",
validate_cert = False,
client_key = "client-key.pem",
client_cert = "client-cert.pem",
connect_timeout = 60,
request_timeout = 60)
def connect(self, connCallback, msgCallback):
self.request.headers = self.headers
self.__msgcallback = msgCallback
self.__conncallback = connCallback
wssConn = websocket.WebSocketClientConnection(ioloop.IOLoop.current(), self.request)
wssConn.connect_future.add_done_callback(self.__on_connResult)
def __on_connResult(self, conn):
if conn.exception() == None:
self.__wssConn = conn.result()
self.__conncallback(True)
self.__read()
else:
print(conn.exception().args)
self.__conncallback(False)
def send(self, data):
self.__wssConn.write_message(escape.utf8(json.dumps(data)))
@gen.coroutine
def __read(self):
while True:
msg = yield self.__wssConn.read_message()
if msg is None:
self.__conncallback(False)
break
self.__msgcallback(msg)
Python ile socket programlamaya giriş.
Merhabalar,
Bu yazıda, Python programlama diliyle soketlerin kullanılışı konusuna kısaca giriş yapmaya çalışacağım. Okuyucuda soketler hakkında temel bilgilerin olduğunu varsayıyorum. Bunların ne olduğu veya ne için kullanıldığı konusunda hiçbir bilgisi olmayanlar için şöyle özetleyebiliriz; soketler iletişim kanallarıdır. Bunlar aynı bilgisayarda iki işlem arası iletişim sağlayabilse de (örn: unix soketleri) bunları en çok ağ üzerinde iletişim için kullanırız. İnternetten bilgisayarınıza gelip giden tüm veriler için, mutlaka birer soket kullanılır.
Anlatıma geçmeden önce şunu da söylemek istiyorum ki, Python'daki socket modülünü lazım olmadıkça kullanmayınız. Demek istediğim şu ki, bir internet sayfası indirmek için socket açmak, HTTP başlıklarını göndermek, gerekirse yönlendirilen sayfaya yeniden soket açmak gibi bir uğraşa girmeyin. Python bu tip yaygın kullanımlar için zaten daha üst seviye modüllere sahip bir dil. Amerika'yı yeniden keşfetmeye gerek yok.
Öyleyse, Python'daki socket modülünü alternatif bulamadığımız durumlarda kullanalım. Ağ bakımı/programcılığı konusunda bu modülün kullanım alanı kendisini belli edecektir.
Bir örnekle başlayalım;
Bu örnekte bir client (ingilizcede müşteri demek) soket oluşturduk.
Bunun anlamı, bu soket kendisi veri sunmayacak, bir sunucuya bağlanacak
demek. Sunucu programlara ileriki yazılarda göz atmaya çalışacağım.
Soket oluşturma fonksiyonuna ilk verdiğimiz argüman, bu soketin adresleme şeklini gösteriyor diyebiliriz. Bunun
İkinci argüman ise bu soketin iletişim tipini gösteriyor.
Daha sonra, elimizdeki
Eğer internetle veya işletim sistemiyle ilgili bir hata oluşmadı ise, şu andan sonra soketimiz yazmak ve okumak için hazır. Bu işlemler için sırasıyla
Not: Kodlar içerisindeki adres html tagları içinde görünüyorsa,
onları kaldırın. Galiba Tumblr otomatik olarak onu linke çevirmeye
çalışıyor :/
Burada, muhtemelen yapılabilecek en kısa HTTP isteğini gerçekleştirdik. Daha sonra da, 512 byte'lar halinde okuyabildiğimiz kadar veri okuduk. İnternetten gelecek verinin tümünün ne kadar olduğunu bilmediğimiz için, boş veri okuyana kadar okumaya devam etmemiz gerekiyor. Bir yandan okudukça, bir yandan da ekrana yazmaya devam ettik.
Ekleme:
Artık
Bu yazıda konuya genel bir giriş yaptım. Bir sonraki yazıda sunucu programlarda soketlerin nasıl kullanılacağına değinmeyi planlıyorum.
Bu yazıda, Python programlama diliyle soketlerin kullanılışı konusuna kısaca giriş yapmaya çalışacağım. Okuyucuda soketler hakkında temel bilgilerin olduğunu varsayıyorum. Bunların ne olduğu veya ne için kullanıldığı konusunda hiçbir bilgisi olmayanlar için şöyle özetleyebiliriz; soketler iletişim kanallarıdır. Bunlar aynı bilgisayarda iki işlem arası iletişim sağlayabilse de (örn: unix soketleri) bunları en çok ağ üzerinde iletişim için kullanırız. İnternetten bilgisayarınıza gelip giden tüm veriler için, mutlaka birer soket kullanılır.
Anlatıma geçmeden önce şunu da söylemek istiyorum ki, Python'daki socket modülünü lazım olmadıkça kullanmayınız. Demek istediğim şu ki, bir internet sayfası indirmek için socket açmak, HTTP başlıklarını göndermek, gerekirse yönlendirilen sayfaya yeniden soket açmak gibi bir uğraşa girmeyin. Python bu tip yaygın kullanımlar için zaten daha üst seviye modüllere sahip bir dil. Amerika'yı yeniden keşfetmeye gerek yok.
Öyleyse, Python'daki socket modülünü alternatif bulamadığımız durumlarda kullanalım. Ağ bakımı/programcılığı konusunda bu modülün kullanım alanı kendisini belli edecektir.
Bir örnekle başlayalım;
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) s.connect(("www.google.com.tr", 80))
Soket oluşturma fonksiyonuna ilk verdiğimiz argüman, bu soketin adresleme şeklini gösteriyor diyebiliriz. Bunun
socket.AF_INET
olması,
bunun bildiğimiz IP adresi soketi olduğunu gösteriyor. Bunun yerine,
socket.AF_INET6
ile IPv6 kullanabiliriz. Bir de socket.AF_UNIX
var
ki, bu UNIX soketleri için kullanılıyor. Dolayısıyla her sistemde bu
sabit tanımlı olmayabilir.İkinci argüman ise bu soketin iletişim tipini gösteriyor.
socket.SOCK_STREAM
, en yaygın kullanılan TCP iletişim tipidir.
Bundan sonra en yaygın kullanılan iletişim tipi UDP için
socket.SOCK_DGRAM
sabiti kullanılır.Daha sonra, elimizdeki
s
isimli soket objesinin connect
isimli
metoduyla, soketimizi internetteki bir diğer sokete (yani sunucuya)
bağlayabiliriz. Bu metot adres türüne göre farklı argümanlar alabilir.
socket.AF_INET
için, adres ve porttan oluşan bir tuple veri tipi
alır.Eğer internetle veya işletim sistemiyle ilgili bir hata oluşmadı ise, şu andan sonra soketimiz yazmak ve okumak için hazır. Bu işlemler için sırasıyla
send
ve recv
metotları kullanılır. Aynı örnekten devam
ederek, şunu deneyebiliriz;s.send("GET / HTTP/1.1\r\nHost: www.google.com.tr\r\nConnection: Close\r\n") while True: msg = s.recv(512) # 512 byte veri okumaya çalış if not msg: # Eğer boş döndüyse, break print msg
Burada, muhtemelen yapılabilecek en kısa HTTP isteğini gerçekleştirdik. Daha sonra da, 512 byte'lar halinde okuyabildiğimiz kadar veri okuduk. İnternetten gelecek verinin tümünün ne kadar olduğunu bilmediğimiz için, boş veri okuyana kadar okumaya devam etmemiz gerekiyor. Bir yandan okudukça, bir yandan da ekrana yazmaya devam ettik.
Ekleme:
Connection: Close
header'ını eklemek önemli. Bu header
olmazsa, server yeni bir istek almak için bağlantıyı açık tutabilir. Bu
durumda, program bağlantının kapanacağını varsaydığından, bağlantının
iki ucu da diğerinden veri beklerken program donabilir. (bkz: HTTP
persistent connection)s
isimli soketimizle işimiz bitti. HTTP protokolünde, bir kez
veri okuduktan sonra bağlantı kapanır. Yeni bir sayfa okumak istersek,
sıfırdan bir soket bağlantısı gerçekleştirmemiz gerekir.Bu yazıda konuya genel bir giriş yaptım. Bir sonraki yazıda sunucu programlarda soketlerin nasıl kullanılacağına değinmeyi planlıyorum.
Python Modüllerinde __name__ Özelliğinin Kullanımı
Modüller yenilir mi, içilir mi?
Öncelikle python’da modüllerden ufak bi’ bahsedeyim. Bildiğiniz gibi bir betik içersinde kodlarımızı tekrar tekrar yazmamak için bir kez fonksiyon tanımlamamız yeterli. O fonksiyonu kullanarak kodları tekrar kullanabiliyoruz. Peki ya aynı fonksiyona başka bir Python programında da ihtiyacımız olursa ne yapacağız? Cevap tabii ki modül kullanmak.Python’da modül yazmak için birçok metod var ama bunlardan en basit ve en yaygın olanı fonksiyonlar ve değişkenler için .py uzantılı dosyaları kullanmak. Yani evet, şimdiye kadar yazdığınız her python betiği aynı zamanda birer modül. Diğer bir modül oluşturma yöntemi de C veya C++ programlama dilleri ile yazmaktır.
Yani sonuç olarak python’da modül dediğimiz şey aslında bizim yazdığımız betiklerdir. Yani yazdığımız her python betiği bir modül olarak başka bir betikte içe aktarılabilir(
import
). Modüller için ayrıca buraya bakabilirsiniz.Bir modül’ün ismi
Yavaş yavaş asıl değinmek istediğim konuya geleyim. Python’da her modülün bir ismi vardır. Python yorumlayıcısı bir modülü yorumlarken o modüldeki tüm kodları çalıştırmadan önce bazı değişkenler tanımlar. Bunlardan birisi__name__
değişkenidir. Bu değişken, o modül’ün çalıştırılma şekline göre başka değerler alır.Eğer python yorumlayıcısı bizim yazdığımız modülü ana program olarak çalıştırıyorsa
__name__
değişkeni '__main__'
değerini alır. Ancak yazmış olduğumuz modül başka bir modül içinden çağırılıyorsa bu sefer __name__
değişkeni kendi modül’ünün adını alır.Anlaşılması için bunları bir örnekle açıklayayım;
Örneğin
ornek_modul.py
isminde bir dosyaya kaydedeceğimiz şöyle bir betik yazalım:1 2 3 4 |
|
1 2 3 4 5 6 |
|
ornek_modul.py
doyasını kendi başına çalıştırısak __name__
değişkeni '__main__'
değerini alıyor. Fakat python’un etkileşimli kabuğuna girip ornek_modul
modülünü içeri aktarırsak 1. koddaki else
bloğuna düşeriz çünkü __name__
değişkeni bu defa modülün ismi olan ornek_modul
değerini almış olur.
7 Kasım 2013 Perşembe
django web framework kullanmak için rasyonel nedenler .
Merhaba arkadaşlar ben yasin aktimur, ortalama 6 senedir internet üzerinde farklı projeler geliştiriyorum ve gelirimin tamamını bu projelerindeki ürünleri satarak elde ediyorum.
ilk projelerimi herkes gibi php ile yazıp shared hosting üzerinde paylaşıyordum.
Geliştirdiğim projelerin kullanıcı sayısı olması gerektiğinden çok daha fazla sayılara eriştiriğinde profesyonel bir tercih yapmam gerekti ve şimdi o tercihi yaparken neden django’yu seçtiğimi sizlerle paylaşacağım.
Php ile geliştirilen büyük web siteleri : Wikipedia ve facebook
Wikipedia : 2001 senesinde yazılmış bir internet projesi ve şu anda var olan teknolojilerin hiç birisini kullanmıyor o yüzden 2013 yılında php için referans gösterilmesi aslında gereksiz.
Facebook : 2004 senesinde kurulduğunda markın farklı bir seçeneği yoktu fakat sonradan friendfeed’e 15 milyon $ nakit ve 32.5 milyon dolar facebook hissesini babasının hayrına vermedi bu kadar para bayılmasının nedeni aslında Python ile yazılmış alt yapısını facebook’a adapte etmekti ve ettide zaten o alt yapıyıda açık kaynak olarak paylaştı. Bu arada yazılımın ismi : tornado web server . Django gibi geniş çaplı değil sadece c10k problemine çözüm getiriyor realtime sistemler için ayrıca django ile adaptasyon sağlayabiliyor yani tek başına tornado bi işe yaramıyor denebilir.
Ruby ile geliştirilen servisler : Twitter , Hulu
Ruby tercih etmeme nedenimde tornadonun python ile yazılmış olup django ile senkrinizasyonunun yapılabilmesi realtime bir sistem kuracaksanız node.js şart lakin twitter.com ‘un mesajlaşma sistemindeki rezaleti ruby’deyki realtime eksikliğini açıkça gözler önünede seriyor.
4 Kasım 2013 Pazartesi
Paypal ipn with django
Is this your first time integrating Paypal with Django? Can't get the
signals to work? Don't know how to test django-paypal on your local
machine? Hopefully, this step-by-step blog post will address all the
above mentioned problems and more. This tutorial will cover only Paypal
Standard IPN although most of the initial steps are applicable for the
other payments methods as well.
1. Install django-paypal
There are a couple of version floating around namely:
Cramer's
is a fork from Boxall's version so it's more update. For this tutorial,
we will be using Boxall because we found Boxall's first.
- git clone git://github.com/johnboxall/django-paypal.git paypal
2. Create a PayPal developer account
- Goto https://developer.paypal.com and sign up.
- Once you're in, create a preconfigured account.
- Do this twice, one for account type Buyer and one for account type Seller
- Your dashboard should then look like this:
3. Modify settings.py file
- For the PAYPAL_RECEIVER_EMAIL, set this to the business account email you created in step 2. In this example, it is naiyun_1311845021_biz@od-eon.com
- After you have entered this, run syncdb to create the paypal tables
-
# settings.py
-
...
-
INSTALLED_APPS = (... 'paypal.standard.ipn', ...)
-
...
-
PAYPAL_RECEIVER_EMAIL = "naiyun_1311845021_biz@od-eon.com" #change this to yours
4. Create a url
# urls.py
-
from django.conf.urls.defaults import patterns, include, url
-
-
urlpatterns = patterns('',
-
# Examples:
-
url(r'^$', 'cat.homepage.views.home', name='home'),
-
url(r'^paypal/$', 'cat.homepage.views.paypal', name='paypal'),
-
-
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
-
url(r'^admin/', include(admin.site.urls)),
-
)
-
-
urlpatterns += patterns('',
-
(r'^something/hard/to/guess/', include('paypal.standard.ipn.urls')),
-
)
- Replace cat.homepage with your project.appname
5. Create a view and template
-
# views.py
-
...
-
from paypal.standard.forms import PayPalPaymentsForm
-
from django.conf import settings
-
from django.core.urlresolvers import reverse
-
-
def paypal(request):
-
-
# What you want the button to do.
-
-
paypal_dict = {
-
"business": settings.PAYPAL_RECEIVER_EMAIL,
-
"amount": "1.00",
-
"item_name": "name of the item",
-
"invoice": "unique-invoice-id",
-
"notify_url": "%s%s" % (settings.SITE_NAME, reverse('paypal-ipn')),
-
"return_url": "http://www.example.com/your-return-location/"
-
"cancel_return": "http://www.example.com/your-cancel-location/",
-
}
-
-
# Create the instance.
-
form = PayPalPaymentsForm(initial=paypal_dict)
-
context = {"form": form.sandbox()}
-
return render_to_response("paypal.html", context)
-
-
# paypal.html
-
-
{{ form }}
- Don't worry about what to put for settings.SITE_NAME first, we'll get to that in a bit
- The notify_url is the url that PayPal will try to send a POST request
- return_url is the page that Paypal redirects you to when the transaction is complete
- The form key in context renders a PayPal button. Right now we're using form.sandbox() to initiate the test process. Change this to form.render() to send the user to the real PayPal site
- You can add a "custom" key and value to the paypal_dict if you want to add a custom field later on
- If you're doing this test multiple times, you might run into an error message given by Paypal that says something like: This invoice has already been paid. For more information, please contact the merchant. To get around this, just change the invoice value everytime you try to make a purchase.
6. Now we fix the SITE_NAME
Sign up for an account at www.dyndns.com
- Add a new hostname. For service type, choose Host with IP address. Next, click on the link to populate the IP Address
- You should have something that looks like this:
- Add the Hostname to your settings.py file as SITE_NAME like so
-
# settings.py
-
...
-
SITE_NAME = 'http://nai.dyndns-free.com'
-
...
7. Run Django development server on your local IP
- For this to work, you need to configure your router to open port 80. The normal process is roughly like this:
- Goto your router IP e.g. 192.168.1.1
- Look for firewall or port forwarding
- Create an exception called 'django' or whatever with port 80 open
- Add this exception to the list of allowed applications that is tied to your computer
- Save
- Now, run Django's development server using sudo /etc/init.d/apache2 stop; sudo ./manage.py runserver 192.168.2.102:80
- Change 192.168.2.102:80 to your own IP address which you can locate by running ifconfig in bash. Retain port 80
- If all goes well, you should be able to open up in your browser the hostname you created at dyndns. In my case, nai.dyndns-free.com/paypal looks like this:
8. What goes on under the hood?
When
someone uses this button to buy something PayPal makes a HTTP POST to
your "notify_url" which comes as part of the Paypal package. PayPal
calls this Instant Payment Notification (IPN). The view
paypal.standard.ipn.views.ipn handles IPN processing. We have already
set the notify_url in step 4 as: urlpatterns += patterns('',(r'^something/hard/to/guess/', include('paypal.standard.ipn.urls')),)
When the notify_url is called, the ipn view is executed as shown below. You will need to include @csrf_exempt in the view as well
-
@require_POST
-
@csrf_exempt
-
def ipn(request, item_check_callable=None):
-
-
"""
-
PayPal IPN endpoint (notify_url).
-
Used by both PayPal Payments Pro and Payments Standard to confirm transactions.
-
http://tinyurl.com/d9vu9d
-
-
PayPal IPN Simulator:
-
https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session
-
"""
-
-
flag = None
-
ipn_obj = None
-
form = PayPalIPNForm(request.POST)
-
if form.is_valid():
-
try:
-
ipn_obj = form.save(commit=False)
-
except Exception, e:
-
flag = "Exception while processing. (%s)" % e
-
else:
-
flag = "Invalid form. (%s)" % form.errors
-
-
if ipn_obj is None:
-
ipn_obj = PayPalIPN()
-
-
ipn_obj.initialize(request)
-
-
if flag is not None:
-
ipn_obj.set_flag(flag)
-
else:
-
# Secrets should only be used over SSL.
-
if request.is_secure() and 'secret' in request.GET:
-
ipn_obj.verify_secret(form, request.GET['secret'])
-
else:
-
try:
-
ipn_obj.verify(item_check_callable)
-
except Exception, e:
-
flag = "Exception while processing. (%s)" % e
-
ipn_obj.save()
-
-
return HttpResponse("OKAY")
Just to elaborate a bit on the view, this line here ipn_obj.verify(item_check_callable) is the part that will invoke the sending of the signals. The verify() method can be found in paypal/models/standard/models.py which in turn calls the send_signals() method which can be found in paypal/models/standard/ipn/models.py
9. Final Stretch
So
now we need to set up something to receive these signals. This can live
anywhere in the project. The examples use models, so lets go with that.
-
# models.py
-
...
-
from paypal.standard.ipn.signals import payment_was_successful
-
-
def show_me_the_money(sender, **kwargs):
-
ipn_obj = sender
-
# Undertake some action depending upon `ipn_obj`.
-
if ipn_obj.custom == "Upgrade all users!":
-
Users.objects.update(paid=True)
-
print __file__,1, 'This works'
-
payment_was_successful.connect(show_me_the_money)
- If everything works ok when we click the buy now button, console should print the line 'This works'
- So, go back to your domain/paypal page. Click on the buy button link, it should re-direct you to the Paypal sandbox page. Log in using the personal account you created in step 2. Mine is naiyun_1311850509_per@od-eon.com
- Go through the buying process and if everything works, you should see something like this in your console
-
[05/Aug/2011 03:06:50] "GET /paypal/ HTTP/1.1" 200 1075
-
/home/nai/GitProjects/cat/homepage/models.pyc 1 This works
-
[05/Aug/2011 03:08:02] "POST /something/hard/to/guess/ HTTP/1.0" 200 4
Hope this tutorial has been helpful. If you
have any questions, do leave them in the comments and I 'll do my best
to answer them.
UPDATE
Just in case anyone is running into DB related problems, django-paypal uses South to handle it's model creation. So running ./manage.py syncdb will *not* create the Paypal related tables.
Kaydol:
Kayıtlar (Atom)