2009-09-07 21 views
5

Bir nesnenin benzersiz olduğundan emin olmak ve bir kullanıcı kaydetmeye çalıştığında (örneğin, yönetici aracılığıyla) bir hata atmak istiyorum. Eşsiz olarak, nesnenin bazı özniteliklerinin, diğer nesnelerinkiyle aynı değerleri taşıyabileceğini kastediyorum, ancak TÜM, başka bir nesnenin değerleriyle aynı olamaz. Ben yanılmıyorsamDRY benzersiz nesneleri Django

, ben şöyle yapabilirsiniz:

class Animal(models.Model): 
    common_name = models.CharField(max_length=150) 
    latin_name = models.CharField(max_length=150) 
    class Meta: 
     unique_together = ("common_name", "latin_name") 

Ama sonra her zaman modeli planı ayrı (örneğin yeni bir alan eklemek veya varolan alanın adını değiştirmek için) Ayrıca, unique_together'a atanan parantez içindeki alanların listesini de düzenlemek zorundayım. Basit bir modelle, bu tamam, ama önemli bir ile, refactoring sırasında gerçek bir güçlük olur.

unique_together parantezindeki alan adları listesini yazmayı tekrarlamaktan nasıl kaçınamıyorum? Modelin alanlarının listesini bir değişkene geçirmenin ve bu değişkeni unique_together yerine atamanın bir yolu var mı?

+1

+1 (veya soyut temel sınıf Model uzanan ve metaclass geçersiz kılma türetmek) - büyük soru. Yapabileceğini sanmıyorum, ama başkalarının fikirlerini duymakla ilgileniyorum. –

+0

+1 - Birisi güzel bir çözüm bulabilirse gerçekten ilginç. Denedim ama bunu yansıtma yoluyla yapamayacağınız için, çünkü Hayvan sınıfındaki özellikleri okuyamazsınız (Hayvanın o anda tam olarak tanımlanmadığı açıktır). – FlorianH

+0

irc: //irc.freenode.net/django üzerinde jtiai soruyu tartışmak için biraz zaman harcadı ve kendi "AllUniqueModel" sınıfımı ekleyebileceğimi, standart "Model" i ekleyebildiğimi ve tüm alanları enjekte etmek için bazı metaclass sihrini yapabileceğimi önerdi standart oluşturma prosedürüyle işlendikten sonra unique_togerther. ' Jtiai'nin ne anlama geldiğinden emin değilim, ama umduğumdan daha karmaşık bir çözüm gibi geliyor. – sampablokuper

cevap

4

Refactoring modelleri yapmak için oldukça pahalı bir şeydir:

  • alan adları nesne özelliklerini karşılık beri Sen modeller kullanılarak tüm kodunu değiştirmek gerekecektir
  • Sen Django beri el ile değiştirmek zorunda kalacak Bunu sizin için yapamıyorum (en azından Django ile çalıştığımda en son kullandığım sürüm)

Bu nedenle, model meta sınıfındaki benzersiz alan adlarının listesini güncellemenin en az sorun olduğunu düşünüyorum. endişelenmeli üzeresin.

DÜZENLEME: Eğer gerçekten "birlikte benzersiz" olmalıdır senin tüm alanları bunu yapmak istiyor ve , o zaman freenode adam haklı ve özel bir metaclass yazmak gerekecek. Bu oldukça karmaşık ve hatasızdır, ayrıca kodunuzu Django'nun gelecekteki sürümleriyle uyumsuz hale getirebilir.

Django'nun ORM "sihir", Model genel temel sınıfının ModelBase (django.db.models.base.ModelBase) meta sınıfı tarafından denetlenir. Bu sınıf, sınıf tanımınızı tüm alanlarla ve Meta bilgileriyle almaktan ve kodunuzda kullanacağınız sınıfı daha sonra oluşturmaktan sorumludur. Kendi metaclass kullanmak

  1. Alt Sınıf ModelBase: Burada

    size hedefe ulaşmak nasıl bir reçetedir.
  2. geçersiz kılma yöntemi __new__(cls, name, bases, dict)
  3. Meta üyesini (dict["Meta"]) yanı sıra toplanan alanlarının adlarına dayalı tüm alan üyeleri
  4. Set meta.unique_together toplamak için dict inceleyin.
  5. Çağrı süper uygulama (ModelBase.__new__)
  6. Kullanım sihirli eleman __metaclass__ = MyMetaclass kullanarak tüm benzersiz modelleri için özel metaclass
+1

Prototipleme aşamasında, refactoring modelleri ucuzdur, ancak çoğaltma kodu pahalıdır, bu yüzden benim sorum. Açıkçası, üretimde, bu farklı bir meseledir, fakat benim sorduğum soruya iyi bir cevap verilebilirse, bu, en azından üretimde geri dönüş yapıldığında almam gereken adımlardan * birini * azaltacaktır. – sampablokuper

+1

Uzun cevap için güncellenmiş yanıtımı görün, belki de bunun çok karmaşık olabileceğini anlayacaksınız. –

+2

Yanıtınızı güncellediğiniz için teşekkür ederiz. Evet, bunu başarmak için oldukça sıkıntı olduğunu görüyorum. Hmm. Django sadece ** benzersiz \ _together = (tümü) ** veya somesuch belirtme seçeneği sunabilirse veya Meta seçeneklerine geçmek için alan listeleri oluşturmak için kendileri üzerinde iç gözlem gerçekleştirebilselerdi çok güzel olurdu. . Ya da her ikisi de :) – sampablokuper

İlgili konular