2010-04-27 14 views
5

Konu modelinde aynı m2m alanlara sahip iki modelim (ModelParent ve ModelChild) var. ModelChild, ModelParent üzerinde bir dış tuşa sahiptir ve ModelChild, admin sayfasında ModelParent için satır içi olarak tanımlanmıştır.django - ModelAdmin ve satır içi çizgileri nasıl geçilir?

### models.py ### 
    class Subject(Models.Model): 
    pass 

    class ModelParent(models.Model): 
    subjects_parent = ManyToManyField(Subject) 

    class ModelChild(models.Model): 
    parent = ForeignKey(ModelParent) 
    subjects_child = ManyToManyField(Subject) 

### admin.py ### 
    class ModelChildInline(admin.TabularInline): 
     model = ModelChild 

    class ModelParentAdmin(admin.ModelAdmin): 
    inlines = [ModelChildInline] 

    admin.site.register(ModelParent, ModelParentAdmin) 

olsa önemli bir kısıtlama var ModelChild en subjects_child alan subject_parent onun subjects_parent ile yaptığı herhangi konuyu başvuru olmamalıdır.

Dolayısıyla, her iki model için de Yönetici sayfasında aynı Konuyu (subject_parent ve subject_child) seçersem, bunu nasıl doğrulayabilirim? Yalnızca bir alan değişirse, onu db'ye göre doğrularsınız, ancak her ikisi de değişirse (subject_parent ve subject_child)? Her iki formu da kaydetmeden önce nasıl doğrulayabilirim?

+0

Neden form için temiz() içinde doğrulamıyor, alan_spesifik temiz değil? Bu şekilde, kontrol etmeniz gereken tüm alanlar önceden temizlenmiş olacaktır. Emin olmadığınız tek şey, her iki veri kümesine de ulaşıp ulaşamayacağınız, ya da sadece temizlik için() ModelParent'in verilerinin() ... –

+1

Thx'i öneri olarak alabilir. Bunu zaten yaptım, ancak formları ile sadece ana formu (ModelParentAdmin için form) doğrulayabilir ve ayrı ayrı formüle edebilir (yalnızca db'ye karşı). Onlara birlikte erişebildiğim tek yer ModelParentAdmin sınıfında. Ancak bu sınıfın bir clean() yöntemi yoktur. Bu sınıfın save_formsets (...) yönteminde aramadan önce onları doğrulayabileceğimi düşünebilirim, ancak ValidationError ("error") 'i yükseltmek üzerine hiçbir şey yakalanmaz. – blazt

cevap

5

, Bütün formları birlikte doğrulayabiliyorsunuz. Her iki fonksiyon vardı:

def is_cross_valid(self, form, formsets): 
    return True 

çok yeni sınıf tam olarak çalışması gerekir: Böyle tanımlanır

#... 
formsets_validated = all_valid(formsets) 
cross_validated = self.is_cross_valid(form, formsets) 
if formsets_validated and form_validated and cross_validated: 
#... 

yeni fonksiyon is_cross_valid (...):

#... 
if all_valid(formsets) and form_validated: 
#... 

olarak değiştirildi is_cross_valid (...) işlevini değiştirmezseniz, ModelAdmin ile aynıdır. :)

###admin.py### 
class ModelAdminWithInline(admin.ModelAdmin): 
    def is_cross_valid(self, form, formsets): 
    return True 

    def add_view(self, request, form_url='', extra_context=None): 
    #modified code 

    def change_view(self, request, object_id, extra_context=None): 
    #modified code 

class ModelChildInline(admin.TabularInline): 
    model = ModelChild 

class ModelParentAdmin(ModelAdminWithInline): 
    inlines = [ModelChildInline] 

    def is_cross_valid(self, form, formsets): 
    #Do some cross validation on forms 
    #For example, here is my particular validation: 
    valid = True 

    if hasattr(form, 'cleaned_data'): 

     subjects_parent = form.cleaned_data.get("subjects_parent") 

     #You can access forms from formsets like this: 
     for formset in formsets: 
     for formset_form in formset.forms: 
      if hasattr(formset_form, 'cleaned_data'): 

      subjects_child = formset_form.cleaned_data.get("subjects_child") 
      delete_form = formset_form.cleaned_data.get("DELETE") 

      if subjects_child and (delete_form == False): 
       for subject in subjects_child: 
       if subject in subjects_parent: 
        valid = False 
        #From here you can still report errors like in regular forms: 
        if "subjects_child" in formset_form.cleaned_data.keys(): 
        formset_form._errors["subjects_child"] = ErrorList([u"Subject %s is already selected in parent ModelParent" % subject]) 
        del formset_form.cleaned_data["subjects_child"] 
        else: 
        formset_form._errors["subjects_child"] += ErrorList(u"Subject %s is already selected in parent ModelParent" % subject]) 

     #return True on success or False otherwise. 
     return valid 

admin.site.register(ModelParent, ModelParentAdmin) 

çözüm biraz hackish ama çalışır:

Şimdi benim admin.py buna benzemez. Hatalar düzenli ModelForm ve ModelAdmin sınıflarıyla aynıdır. Django 1.2 (kısa zamanda piyasaya sürülmelidir), model doğrulama sağlamalıdır, bu yüzden bu sorunun daha güzel çözülebileceğini umuyorum.

2

Yönetici sınıflarında clean() yöntemi yoktur. Formları öyle. Her yönetici sınıfında form adı verilen bir parametre vardır. Varsayılan formu (normal ModelAdmin formu) genişletir, clean() yöntemini uygular ve formu yönetici sınıfına eklersiniz. Örnek: admin.ModelAdmin dan ModelAdminWithInline adlı yeni bir sınıf miras ve fonksiyon is_cross_valid (öz, biçim, formsets) aramak yöntemler add_view (...) ve change_view (...) değiştirdiniz

class SomeForm(ModelForm): 
    #some code 
    def clean(self): 
    #some code 
class SomeAdminClass(ModelAdmin): 
#some code 
form = SomeForm 
#more code 
+2

Bunu zaten yaptım, ancak bununla birlikte yalnızca formları DB _separately_'a karşı doğrulayabilirim. Aynı konuyu bir yönetici sayfasına ModelParent.subjects_parent ve ModelChild.sujects_child eklerseniz (bu, satır içi satırlarla olur). Bir form, diğerinin aynı konuyu seçtiğini ve böylece ikisinin de kurtarıldığını bilmiyor. Bunun nedeni, her iki formun da validasyonunun DB'ye kaydedilmeden önce gerçekleşmesidir, bu yüzden hiçbiri diğerinin yaptığı değişiklikleri görmez. – blazt

+0

Şimdi anlıyorum. Bu bazı şeyleri karmaşıklaştırır.Bu koruma seviyesi, her iki formun da kullanabildiği katmanda uygulanmalıdır. Sorununuza doğrudan bir çözüm bilmiyorum, ancak bu tür bir koruma model katmanında veya doğrudan DBMS'de uygulanmalıdır. Django belgelerine veya en kötü durumda DBMS belgelerine bakın. – Klop