Django modelinde selectbox kullanımı

May 27, 2018 2 minute read

Bazen bir model field’ında kullanımı sınırlandırmak veya veriyi denetlemek için basit çözümlere ihtiyacımız var. Örneğin, bir araba markası sorulduğunda kullanıcının kafadan veri girişini engellemek veya Opel - opel gibi büyük - küçük farklarından dolayı oluşacak gereksiz seçenek bölünmelerini önlemek gerekir.

Django notlarım‘da sürekli dile getirdiğim konu var, bir şeye ihtiyaç duyduğunuzda:

  1. Mutlaka Django’nun kendi dökümantasyonuna bir göz atın.
  2. Mutlaka başkaları nasıl çözmüş diye araştırın.

Django dökümantasyonundaki bir örneği alalım ve onun üzerinden gidelim:

class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    YEAR_IN_SCHOOL_CHOICES = (
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
    )
    year_in_school = models.CharField(max_length=2, choices=YEAR_IN_SCHOOL_CHOICES, default=FRESHMAN)

    def is_upperclass(self):
        return self.year_in_school in (self.JUNIOR, self.SENIOR)

Bazen öyle şeyler oluyor ki, bir modele ihtiyaç duymadan bu seçeneklere çeşitli katmanlarda erişmek gerekebiliyor veya bu tip seçenekleri herhangi bir model tanımlamadan, örneğin formda kullanmak durumunda kalabiliyorsunuz, o zaman da “Bunu models.py‘de tuttuk, öbürünü niye forms.py‘ye yazdık?” diye kendinize sorabilirsiniz. Ben bu tip ortak kullanılan şeyleri, ilgili uygulama içinde choices.py veya utils.py gibi bir dosya oluşturup kullanıyorum. Örneğin:

# hello_student/utils.py

class StudentChoice(object):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'

    @classmethod
    def get_choices(cls):
        choices = (
            (cls.FRESHMAN, "Freshman"),
            (cls.SOPHOMORE, "Sophomore"),
            (cls.JUNIOR, "Junior"),
            (cls.SENIOR, "Senior"),
        )
        return choices
# hello_student/models.py
from hello_student.utils import StudentChoice


class Student(models.Model):
    year_in_school = models.CharField(
        max_length=2, choices=StudentChoice.get_choices(), default=StudentChoice.FRESHMAN)

    def is_upperclass(self):
        return self.year_in_school in (StudentChoice.JUNIOR, StudentChoice.SENIOR)

Form’da da kullansak, View katmanında da kullansak benim yöntemim hep bu. Seçenekleri gruplamak istersek:

# hello_student/utils.py
class StudentChoice(object):
    ...
    @classmethod
    def get_choices(cls):
        choices = (
            ("Starting class", (
                (cls.FRESHMAN, "Freshman"),
                (cls.SOPHOMORE, "Sophomore"),
            )),
            ("Upper class", (
                (cls.JUNIOR, "Junior"),
                (cls.SENIOR, "Senior"),
            ))
        )
        return choices

Grouped choices

Peki, seçenekleri taşıdık, varsayılan seçenek ayarını da aynı yerde tutsak?

# hello_student/utils.py
class StudentChoice(object):
    ...
    @classmethod
    def get_default(cls):
        return cls.FRESHMAN
# hello_student/models.py

class Student(models.Model):
    year_in_school = models.CharField(
        max_length=2, choices=StudentChoice.get_choices(), default=StudentChoice.get_default())

Hatta bir şey daha yapalım, seçenekle ilgili yardımcı fonksiyonları da aynı yerden yönetelim:

# hello_student/utils.py

class StudentChoice(object):
    ...
    @classmethod
    def is_upperclass(cls, choice):
        return choice in (cls.JUNIOR, cls.SENIOR)

Bu durumda üst sınıf olup olmadığı kontrolünü şöyle yapardık:

is_upperclass = StudentChoice.is_upperclass(student.year_in_school)

Böylece models.py dosyamızı biraz daha temiz tutmuş olduk. Bunu alışkanlık haline getirirsek, projenin herhangi bir yerinde selectbox, multiple selectbox ve benzeri bir şey ihtiyacımız olduğunda nereye bakacağımızı bilmiş oluruz.