İçeriğe geç

Django Unique Together

Giriş.

Merhabalar.

Constraintler (kısıtlamalar), ilişkisel veritabanlarında üzerinde çalışılan tablonun sütunlarına uygulanan kurallara verilen isimdir. Bu kısıtlamalar ile tablo üzerinde tutulacak verinin güvenirliğini ve doğruluğunu sağlarız.

Kısıtlamalar, bir sütun seviyesinde veya tablo seviyesinde olabilir. Sütun düzeyindeki kısıtlamalar yalnızca bir sütuna, tablo düzeyindeki sınırlamalar ise tüm tabloya uygulanır.

SQL’ de en yaygın kullanılan kısıtlamalardan bazılarına göz atacak olursak;

  • NOT NULL CONSTRAINT  – Bir sütunun NULL değerine sahip olmamasını sağlar.
  • DEFAULT CONSTRAINT – Hiçbir değer belirtilmediğinde, sütun için varsayılan bir değer sağlar.
  • UNIQUE CONSTRAINT – Belirli bir sütun veya sütundaki değerlerin benzersiz olmasını sağlar.

Bu yazıda UNIQUE CONSTRAINT ve unique together üzerine konuşacağız.

Unique Constraint – Unique Together.

Bir sütunun değerini tablo içerisinde benzersiz yapmak istediğimizde yapmamız gereken aslında çok basit. Tanımlanan alana unique=True parametresini geçmek o sütunda tutulan değerleri tablo içerisinde benzersiz yapacaktır.

Fakat bazı durumlarda tek bir sütundan ziyade tablo içerisinde tutulan diğer alanlara da bağlı olacak şekilde kısıtlamalar getirebiliriz. Açıklayacak olursak;

Bir otel rezervasyon sisteminde, aynı oda aynı tarih için birden fazla kez rezerve edilemez veya bir kitap değerlendirme uygulamasında bir kullanıcı aynı kitabı birden fazla kez değerlendiremez vs.

Şanslıyız ki Django böyle bir kısıtlamayı çok kolay bir şekilde yapabileceğimiz bir altyapıya sahip.

Aşağıdaki gibi 2 basit modelimiz olduğunu varsayalım. Ve biz her bir kullanıcının, aynı kitabı yalnızca bir defa değerlendirmesini istiyoruz.

from django.db import models
from django.core.validators import MaxValueValidator, MinValueValidator
from django.conf import settings
class Book(models.Model):
    name = models.CharField(max_length=100)

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


class Review(models.Model):
    reviewer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    rate = models.SmallIntegerField(
        validators=[MaxValueValidator(10), MinValueValidator(0)]
    )

    def __str__(self) -> str:
        return f"{self.ebook.name} rate {self.rate}"

Bu hali ile bir kullanıcı bir kitabı birden fazla kez değerlendirebilir. Kısıtlamanın getirilebilmesi için ise model Meta classda bir değişiklik yapacağız.

class Review(models.Model):
    # fields
    class Meta:
        unique_together = [("reviewer", "ebook")]

Not. unique_together hala kullanılabilir fakat Django 2.2 ile birlikte bu tarz kısıtlamaları yönetmek için UniqueConstratint sınıfı eklendi. unique_together yerine  kullanmak daha fazla esneklik ve özelleştirme sağlayacaktır. Eğer Django 2.2 üzeri bir sürüm ile çalışıyorsanız, aynı tanımlamayı aşağıdaki gibi yapmanız önerilmekte. unique_together ileriki sürümlerde kaldırılacak.

class Review(models.Model):
    # fields

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["reviewer", "book"], name="unique name for your constraint"
            )
        ]

Sürümünüze göre kullanımı seçtikten sonra, makemigrations ve migrate komutları ile gerekli şema değişikliğini yapalım.

Test!

from django.conf import settings
from django.db.utils import IntegrityError
from django.test import TestCase
from model_bakery import baker

from .models import Book, Review

class ModelUniquenessTestCase(TestCase):
    def setUp(self) -> None:
        self.user = baker.make(settings.AUTH_USER_MODEL)
        self.book = baker.make(Book)
        self.review = baker.make(Review, reviewer=self.user, book=self.book)

    def test_review_uniqueness(self):
        with self.assertRaises(
            IntegrityError, msg="Unique together integrity exception not raised"
        ):
            baker.make(Review, reviewer=self.user, book=self.book)

Gerekli kısıtlamayı uygulayarak verinin doğruluğundan ve güvenirliğinden emin olduk.

model_bakery yabancı mı geldi? 🤔 Testlerinde kullanacağın model nesnelerini ve ilişkilerini dert etmek istemiyor ve hakkında okumak istersen link burada.

Sonuç.

Django ile tablo genelinde unique constraint oluşturmak bu kadar basit. Ayrıca validasyonları da dert etmenize gerek yok. ModelForm veya ModelSerializer nesnenin oluşturulması sırasında validate_unique metodu yardımıyla gerekli kontrolleri yapıyor olacak ve siz verinin doğruluğundan her zaman emin olacaksınız.

Django ve constraint sınıfları hakkında daha fazla okumak isterseniz.

İyi günler!

Tarih:Blog

İlk Yorumu Siz Yapın

Bir cevap yazın

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

Göster
Gizle