Tag Archives: Django

Genel

Django Modellerinde ManyToMany Alanların Belirli Bir Filtreye Göre Limitlenmesi

Sistem genelinde taglayabildiğiniz tüm nesne tipleri ile ilgili tag verilerinin tek bir tabloda tutulduğunu düşünelim. Bu durumda tag kayıtlarını bir şekilde sınıflandırmamız ve ilgili nesnelerin sadece kendisiyle ilgili tipteki taglere sahip olabilmesini sağlamalıyız. Bu yapıyı sağlayabilmek için ManyToManyField tanımlaması yapılırken limit_choice_to parametresi kullanılarak ilişkili tablonun neye göre filtreleneceğini dict olarak tanımlamamız gerekir.

Böylece django admin tarafında da kullanıcının ilgili kaydı editlerken manytomany alanda yalnızca kendisiyle ilgili kayıtları görmesi/seçebilmesi sağlanır.

Aşağıda örnek veri modeli yeralıyor.

from django.db import models


class Tag(models.Model):
    TAG_TYPES = (
        ('article', 'Article'),
        ('video', 'Video'),
    )
    slug = models.SlugField(max_length=50)                                     
    name = models.CharField(max_length=50)   
    tag_type = models.CharField(max_length=30)    


class Article(models.Model):
    slug = models.SlugField(max_length=80)
    title = models.CharField(max_length=80)
    content = models.TextField()
    tags = models.ManyToManyField(Tag, limit_choices_to={'tag_type': 'article'})


class Video(models.Model):
    slug = models.SlugField(max_length=50)
    name = models.CharField(max_length=50)
    url = models.UrlField()
    tags = models.ManyToManyField(Tag, limit_choices_to={'tag_type': 'video'})
Genel

Django REST Framework İle RESTFul Web Servisi Geliştirme

django-restframework-logo
Django REST Framework, Django uygulamalarınız için RESTFul web servisi geliştirmenize olanak sağlayan oldukca kullanışlı bir python paketi. Benzeri diğer bir python kütüphanesi olan Tastypie ile karşılaştırdığımda ilk bakışta anlaması/öğrenmesi oldukca kolay göründüğünü söylemeliyim.

Django REST Framework ile RESTFul web servisi geliştirmek, aslında bildiğimiz django view lerini kullanarak uygulama geliştirmeye oldukca benziyor. Kendi view sınıf ve dekoratörleri djangodaki class ve function based viewler gibi kodlama yapmanıza olanak sağlıyor.

Hızlı başlangıç için: şuradaki
Kütüphanenin güncel kaynak kodları için: buradaki
bağlantıları inceleyebilirsiniz.

Dilerseniz hemen ilk örnek uygulamamızı yazmak için yeni bir virtual environment oluşturalım ve aktif hale getirelim.

$ virtualenv myblog-env
$ cd myblog-env
$ source bin/activate

Ben bu örnek için Django 1.6.6 kullanacağım.

$ pip install django==1.6.6

ve… Django REST Framework paketinin kurulumunu gerçekleştirelim. Ben bu örnek için paketin bugünki güncel sürümü olan 2.4.0 sürümünü kuracağım.

$ pip install djangorestframework==2.4.0

Evet… Artık geliştirmeye hazırız. Hemen django projemizi ve uygulamamızı oluşturalım.

$ django-admin.py startproject myblog
$ cd myblog
$ python manage.py startapp blog

Hemen basitce bir Post modeli oluşturalım.

myblog/blog/models.py:

from django.contrib.auth.models import User
from django.db import models


class Post(models.Model):
	title = models.CharField(length=80)
	content = models.TextField()
	author = models.ForeignKey(User)

Uygulamamızı settings.py dosyasındaki INSTALLED_APPS bölümüne ekleyelim.

myblog/myblog/settings.py:

...
INSTALLED_APPS = (
...
	'rest_framework',
	'blog',
...
)
...

Tablolarımızı yaratalım…

$ python manage.py syncdb

An itibarıyla temel bir uygulama geliştirebilecek şartlara sahibiz. Bir adet veri modelimiz var ve bir API vasıtasıyla bu modele veri girişi yaptırmak istiyoruz. Başlarken, Django REST Framework kütüphanesi ile web servisi geliştirmenin, class veya function based viewler ile bildiğimiz django uygulaması geliştirmekten çok da farklı olmadığından söz etmiştik. Bilinen django view leri, sunu katmanından gelen veriyi işleyip HTTPResponse tipinde yeni bir obje dönmekteydi. Django REST Framework tarafında ise kullanıcıdan alınan veriler veya kullanıcı tarafına gönderilen veriler Serializer objeleri üzerinden API viewleri ile haberleşir.

Serializer nesneleri, uygulama altında serializers.py isimli python dosyalarında barındırılırlar.

Post modülümüz için yeni bir Serializer objesi oluşturalım.

myblog/blog/serializers.py:

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


class UserSerializer(serializer.HyperlinkModelSerializer):
	class Meta:
		model = User
		fields = ('url', 'username', 'email', 'groups')


class PostSerializer(serializer.HyperlinkModelSerializer):
	class Meta:
		model = Post
		fields = ('title', 'content', 'author')

Serializer objeleri doğrudan modeli temsil edebilecekleri gibi serializer.Serializer sınıfından türetilerek özel bir veri tipi için de kişiselleştirilmiş Serializer objeleri oluşturulabilir.

Sıra geldi kullanıcıdan gelen istekleri karşılamaya. Model ve serializer kodlamasını tamamladığımıza göre artık Post modelimiz için yeni bir view(lar) oluşturabiliriz. Django REST Framework başta da belirttiğimiz gibi aynı Django uygulamalarında olduğu gibi class ve function based viewlar oluşturabilmemize izin veriyordu. Ben örnek uygulamamız için kolay okunabilmesi nedeniyle class base view tercih edeceğim.

from blog.serializers import PostSerializer

from django.http import Http404

from rest_framework import views
from rest_framework.response import Response
from rest_framework import status


class PostList(views.APIView):
	def get(self, request, format=None):
		posts = Post.objects.all()
		serializer = PostSerializer(posts, many=True)
		return Response(serializer.data)

	def post(self, request, format=None):
		serializer = PostSerializer(data=request.DATA)
		if serializer.is_valid():
			serializer.save()
			return Response(serializer.data, status=status.HTTP_201_CREATED)
		return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class PostDetail(views.APIView):
    def get_object(self, pk):
        try:
            return Post.objects.get(pk=pk)
        except Post.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        post = self.get_object(pk)
        serializer = PostSerializer(snippet)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        post = self.get_object(pk)
        serializer = PostSerializer(post, data=request.DATA)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        post = self.get_object(pk)
        post.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Gördüğünüz üzere Post modeli için GET, PUT, POST, DELETE isteklerine cevap verebilen detail ve list viewlerimizi oluşturduk.

Django REST Framework class based view lerin method handle etmeyen halleri gibi tanımlayabileceğimiz ViewSet denilen uyarlamaları da kullanabilmemize olanak sunar. ViewSetler farklı kütüphanelerde Resource gibi farklı şekillerde de isimlendirilerler.

from blog.models import Post
from blog.serializers import PostSerializer

from rest_framework import viewsets


class PostViewSet(viewsets.ModelViewSet):
	queryset = Post.objects.all()
	serializer_class = PostSerializer

Bu yazı Django REST Framework kütüphanesini başlangıç seviyesinde tanıtmayı amaçladığından şimdlilik bu bölümü anlatmayacağım. Merak edenler dökümaın şu bölümünü inceleyebilirler.

Class based viewlerimizi oluşturduğumuza göre sıra geldi router a viewlerimizi kayıt etmeye.

myblog/myblog/urls.py:

from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
from blog import views

urlpatterns = patterns('',
    url(r'^post/$', views.PostList.as_view()),
    url(r'^post/(?P<pk>[0-9]+)/$', views.PostDetail.as_view()),
)

urlpatterns = format_suffix_patterns(urlpatterns)

Artık uygulamamız istekleri kabul etmeye hazır. Örnek istek oluşturup yanıtını göstermeye üşendiğim için işin en zevkli kısmınıı size bırakıyorum :)

Django REST Framework konusunda anlatılacak çok şey var. Kullanışlı ve son derece esnek. Detaylı dökümantasyon ve örnekler için Django REST Framework Resmi Web Sitesi‘ni ziyaret edebilirsiniz.

Genel

Django Uygulamalarının Apache Üzerinde Sanal Ortam (virtualenv) İle Birlikte Çalıştırılması

Django framework ile geliştirdiğiniz python uygulamalarınızı, apache2 üzerinde virtualenv ile birlikte çalıştırmak için aşağıdaki işlemleri sırasıyla gerçekleştirmelisiniz.

– Şayet sunucunuzda mevcut bir apache kurulumu varsa aşağıdaki apache bileşenlerinin kurulumunu gerçekleştiriniz.

$ sudo apt-get install apache2.2-common apache2-mpm-prefork apache2-utils libexpat1 ssl-cert

– Apache yi restart ediniz ve tarayıcınızdan istek göndererek halen sorunsuz ve çalışır durumda olduğundan emin olunuz.

$ sudo /etc/init.d/apache2 restart

– Apache için wsgi modülünün kurulumunu gerçekleştiriniz.

$ sudo apt-get install libapache2-mod-wsgi

– Virtual environment üstündeki python projeniz için /etc/apache2/sites-available/ dizininde aşağıdaki gibi yeni bir sanal host dosyası oluşturunuz. (Örnek dosyamızın adi sizinsite.com olsun)

<VirtualHost *:80>
    ServerName sizinsite.com
    ServerAlias www.sizinsite.com
    WSGIScriptAlias / /var/www/sizinsitecom-env/project/sizinsitecom-src/wsgi.py
    WSGIProcessGroup sizinsitecom
    WSGIDaemonProcess sizinsitecom processes=5 python-path=/var/www/sizinsitecom-env/project/sizinsitecom-src:/var/www/sizinsitecom-env/lib/python2.7/site-packages threads=1
    Alias /static/ /var/www/sizinsitecom-env/project/sizinsitecom-src/static/
    <Directory /var/www/sizinsitecom-env/project/sizinsitecom-src/>
        <Files wsgi.py>
            Order deny,allow
            allow from all
        </Files>
    </Directory>
    <Directory /var/www/sizinsitecom-env/project/sizinsitecom-src/static/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
    </Directory>


    ErrorLog ${APACHE_LOG_DIR}/sizinsitecom-error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn

    CustomLog ${APACHE_LOG_DIR}/sizinsite-access.log combined
</VirtualHost>

– sanal host u aktif hale getirin.

$ sudo a2ensite sizinsite.com

– Yeni sanal host un aktif olması için apache servisini yeniden başlatın veya konfigürasyonu reload edin.

$ sudo service apache2 restart

Hepsi bu kadar.

Programa Dilleri ve Çatıları

Django Framework Template Etiketlerinde User Objesine Erişmek

Aslında django kullanıcıları için muhtemelen çok basit bir konu ancak benim gibi yeni başlayanlar için sorun olabilecek konulardan biri olduğu için yazıyı sizinle paylaşmak istedim.

Problem:
Django öğrenmek için yazdığım blog projesinde kullanıcıya gösterdiğim blog postunun yeni comment girişi alanını, comment blog postuna veya başka bir comment e yanıt olarak girilebileceğinden inclusion_tag yaptım. Ancak inclusion tag in include ettiği template içinde user objesine ulaşamıyorum.

Çözüm:
Uzun stackoverflow okumlarından sonra inclusion_tag e parametre olarak takes_context göndersem de tag e parametre olarak gelen context içinde user objesinin gelmediğini öğrendim. Bunun yerine view tarafında, ilgili actionda return edilen render fonksiyonuna parametre olarak, context_instance için RequestContext göndermem gerekiyormuş. Böyle olunca tag e parametre olarak gelen context içinde user objesinin yeraldığını gördüm.

Problemi çözmek için aşağıdaki adımları uyguladım:

1. view tarafında django.template içindeki RequestContext objesini import ettim.
myapp/views.py:

from django.template import RequestContext

2. İlgili template tag i kullanacağım view ın aksiyonunda return ettiğim render() fonksiyonuna context_instance olarak RequestContext i gönderdim.
myapp/views.py:

def viewpost(request, post_id):
    post = get_object_or_404(Post.objects.select_related('author'), pk=post_id)
    ...
    return render(
        request, 'blog/post/detail.html', 
        {'post' : post}, 
        context_instance=RequestContext(request)
    )

3. template tag tarafında include edeceğim template e veri olarak user objesini gönderdim.
myapp/templatetags/myapp_extra.py:

@register.inclusion_tag('blog/post/blocks/comment/new.html', takes_context=True)
def show_comment_input(context):
    return {'user' : context['user']}

4. Ve… template tag imin include ettiği template kodu.
blog/post/blocks/comment/new.html:

<form action="#" method="POST" class="well" style="margin:0px">
    <h3>Write your comment or reply</h3>

    {% if not user.is_authenticated %}
    <div class="controls controls-row">
        <input type="text" placeholder="Your Name" class="span4" />
        <input type="text" placeholder="E-Mail Address" class="span4" />
    </div>
    {% endif %}
    <div class="controls controls-row">
        <textarea class="span8" placeholder="Your Comments"></textarea>
    </div>
    <div class="controls controls-row">
        <input type="submit" class="btn btn-primary" value="Submit" />
    </div>
    {% csrf_token %}
</form>

Elimdeki proje bittikten sonra gelen Edit:
Context instance olarak zaten request objesi gönderilmiş ve user objesi context’in içinde halihazırda mevcut. Dolayısıyla inclusion tag tanımlarken aşağıdaki gibi bir tanımlama yapmamıza gerek yok. Zaten takes_context dediğimizde context içeriği include edilen template e push ediliyor.
Aşağıdaki değişikliği yapabilirsiniz:
Eski:

@register.inclusion_tag('blog/post/blocks/comment/new.html', takes_context=True)
def show_comment_input(context):
    return {'user' : context['user']}

Yeni:

@register.inclusion_tag('blog/post/blocks/comment/new.html', takes_context=True)
def show_comment_input(context):
    pass

Kaynaklar:
http://stackoverflow.com/questions/2160261/access-request-in-django-custom-template-tags
http://stackoverflow.com/questions/3337419/django-user-is-authenticated-works-some-places-not-others