İçeriğe geç

Django get_absolute_url

Merhabalar. get_absolute_url metodu Django ile geliştirilmiş bir projede mutlaka karşınıza çıkmıştır. Bu metod üzerinde çalışılan nesnenin proje içersindeki mutlak konumunu (yani url) işaret etmektedir ve Django için özel anlama sahiptir. Bizim için nesnelerin urllerini basit ve kendimizi tekrar etmeyeceğimiz şekilde tutmak.

Ne var ki bu isim Django topluluğu tarafından standart belirlenmiş olsa da siz istediğiniz bir isimlendirmeyi seçebilirsiniz. Bugün bu metod ve bir kaç ipucuna ve kavramanın neden önemli olduğuna göz atacağız 😉

Basit bir model.

Halihazırda posts uygulaması altında yaşayan şöyle ufak bir akışımız olsun. Model, view urller ve templateler.

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    slug = models.SlugField(unique=True)

    def __str__(self) -> str:
        return self.title

Viewlar.

from posts.models import Post
from django.views.generic import DetailView, ListView

class PostDetailView(DetailView):
    model = Post

class PostListView(ListView):
    model = Post

Urls.

from posts.views import PostDetailView, PostListView
from django.urls import path

app_name = "posts"
urlpatterns = [
    path("posts/", PostListView.as_view(), name="post-list"),
    path("posts/detail/<slug:slug>/", PostDetailView.as_view(), name="post-detail"),
]

Templateler.

Önce listeleme sayfası.

<!--posts/post_list.html-->
<ul>
    {% for object in object_list %}
    <p>{{object.title}} <a href="detail/{{object.slug}}/">detail link </a></p>
    {% endfor %}
</ul>
<!--posts/post_detail.html-->
<h1>
    {{object.title}}
</h1>
<p>
    {{object.content}}
</p>

Detay sayfasını da ekledikten Django’nun tam bir çevrimini tamamlayarak MVT yapısını oluşturduk 🙂

Fakat eğer dikkat ettiyseniz listeleme sayfasında her nesne için belirtilen yol hardcoded ve fazlasıyla kırılgan. Gelecekte gönderilerin contents/ endpointi altına taşınacağı bir senaryoda doğrudan detay sayfasına yönlendirme yapan bütün templateler tespit edilmeli ve yeni yapıya göre düzenlenmelidir.

Hmm buna bir çözümümüz var sanırım.. named views kullansak mesela aşağıdaki gibi?

<p>{{object.title}} <a href="{% url 'posts:post-detail' slug=object.slug %}">detail link </a></p>

Evet bu da güzel bir yaklaşım. Artık hardcoded olmayan urllerimiz var ve sunulan posts url’i değisse bile değişiklikler templatelerimizi etkilemeyecektir. Fakat gelen bir istek doğrultusunda slug yerine pk ile unique identifier kullanmamız gerekirse? Cevap… Ne yazık ki aynı, teker teker tüm templatelerin değişmesi gerek 🙁

get_absolute_url sahneye!

Yazının en başında da belirttiğimiz üzere kendimizi tekrar etmemeli ve süreci mümkün olan en basit şekle indirgemeliyiz. E o zaman indirelim!

get_absolute_url metodu genellikle ilgili modele tanımlanır ve bizim örneğimiz için aşağıdaki gibidir;

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    slug = models.SlugField(unique=True)

    def get_absolute_url(self):
        from django.urls import reverse

        return reverse("posts:post-detail", kwargs={"slug": self.slug})

django.urls altında yaşayan reverse fonksiyonu yardımı ile named view bulunur gerekli url parametreleri geçirilir ve mutlak url oluşturulur. Bu modelden türetilen her nesne artık bir mutlak url sahibidir.

Template’i aşağıdaki gibi güncelledikten sonra herhangi bir url değişikliği veya unique identifier değişikliğinde sadece bu metodu yeni şemaya göre güncellemek yeterli olacaktır.

<p>{{object.title}} <a href="{{ object.get_absolute_url }}">detail link </a></p>

Ek bilgi. Bunun yanında get_absolute_url metodu create ve update (CBV kullanıyorsanız) işlemlerinde ilgili view’da bir success_url tanımlı değil ise fallback olarak kullanılır. Yani işlem sonrası devam edilecek bir url tanımlamamanız durumunda, doğrudan nesnenin mutlak urline yönlendirilirsiniz.

Django Rest ve get_absolute_url.

Kavramayı daha da kolaylaştırması adına bir de DRF üzerinde bir kullanım örneğine göz atalım.

REST tasarım ilkelerine göre üzerinde çalışılan resourceların kaynaklarını, cevap içinde istemciye iletmek iyi bir yaklaşımdır. İstemci dönen kaynaklar üzerinden ilerleyerek işlemlerine devam edebilir.

Uygulamayı biraz daha geliştirelim ve artık gönderilerimizin listesini bir API üzerinden sunalım. Bu işlem sırasında da resource kaynaklarını cevaba ekleyelim.

Serializer.

from rest_framework import serializers

class PostSerializer(serializers.ModelSerializer):
    resource_url = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = "__all__"

    def get_resource_url(self, obj):
        return self.context["request"].build_absolute_uri(obj.get_absolute_url())

API view.

from rest_framework.generics import ListAPIView

class PostListApi(ListAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

Urls.

urlpatterns = [
    # other urls.
    path("api/posts/", PostListApi.as_view(), name="post-list-api"),
]

Son değişikliklerden sonra basit API endpointimizi ziyaret edecek olursak;

$ http --body :8000/api/posts/
[
    {
        "content": "Lorem ipsum dolor samet.",
        "id": 1,
        "resource_url": "http://localhost:8000/posts/detail/post-1/",
        "slug": "post-1",
        "title": "Post 1"
    }
]

Request üzerinden resource url’i build ettik. Harika!

Umarım bir model nesnesi ve get_absolute_url in önemli bağlantısını aktarabilmişimdir. 🙂

Bonus.

Eğer çok fazla modeliniz var ve absolute url metodlarını modellerinizde barındırmaktansa tek bir yerden yönetmek istiyorsanız veya kullandığınız 3rd party uygulamaların doğrudan modellerine erişemeyeceğiniz durumlarda, absolute urlleri settings üzerinde ABSOLUTE_URL_OVERRIDES kullanarak yönetebilirsiniz.

Kullanımı aşağıdaki gibi ve oldukça kolay.

from django.urls import reverse

ABSOLUTE_URL_OVERRIDES = {
    "posts.post": lambda obj: reverse("posts:post-detail", kwargs={"slug": obj.slug}),
    "your_app.your_model": lambda obj: reverse(
        "your_app:url-name", kwargs={"identifier": obj.identifier}
    ),
}

Artık Django içinde nesnelerin mutlak urllerini akılcı bir şekilde nasıl yönetebileceğiniz ve neden önemli olduğu hakkında bilgiye sahipsiniz.

Umarım yararlı ve keyifli bulmuşsunuzdur.

Bu blogda daha fazla Django ile alakalı okumak isterseniz..

Görüşmek üzere!

 

 

 

Tarih:Blog

İlk Yorumu Siz Yapın

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Göster
Gizle