2009-07-30 19 views
22

Bir kullanıcı ve profillerini aynı anda ekleyebilmem/düzenleyebilmem için aşağıdaki yönetici ayarlarına sahibim.Django Yöneticisi'nde bir satır içi nasıl gerekir?

class ProfileInline(admin.StackedInline): 
    """ 
    Allows profile to be added when creating user 
    """ 
    model = Profile 


class UserProfileAdmin(admin.ModelAdmin): 
    """ 
    Options for the admin interface 
    """ 
    inlines = [ProfileInline] 
    list_display = ['edit_obj', 'name', 'username', 'email', 'is_active', 
     'last_login', 'delete_obj'] 
    list_display_links = ['username'] 
    list_filter = ['is_active'] 
    fieldsets = (
     (None, { 
      'fields': ('first_name', 'last_name', 'email', 'username', 
       'is_active', 'is_superuser')}), 
     ) 
    ordering = ['last_name', 'first_name'] 
    search_fields = ['first_name', 'last_name'] 

admin.site.register(User, UserProfileAdmin) 

Sorun kullanıcı eklerken Profil satır içi şeklinde alanların iki gerekli gerekmektedir olduğunu. Satır girilmemişse satır içi form doğrulanmaz. Yine de satır içi gerekli hale getirmek için var mı, böylece boş bırakılamaz?

cevap

29

Carl'ın tavsiyesini aldım ve çok daha iyi bir uygulama yaptıktan sonra cevabım hakkındaki yorumumda bahsettiğim hack-ish'ı yaptım. Benim forms.py itibaren

:

from django.forms.models import BaseInlineFormSet 


class RequiredInlineFormSet(BaseInlineFormSet): 
    """ 
    Generates an inline formset that is required 
    """ 

    def _construct_form(self, i, **kwargs): 
     """ 
     Override the method to change the form attribute empty_permitted 
     """ 
     form = super(RequiredInlineFormSet, self)._construct_form(i, **kwargs) 
     form.empty_permitted = False 
     return form 

Ve admin.py

class ProfileInline(admin.StackedInline): 
    """ 
    Allows profile to be added when creating user 
    """ 
    model = Profile 
    extra = 1 
    max_num = 1 
    formset = RequiredInlineFormSet 


class UserProfileAdmin(admin.ModelAdmin): 
    """ 
    Options for the admin interface 
    """ 
    inlines = [ProfileInline] 
    list_display = ['edit_obj', 'name', 'username', 'email', 'is_active', 
     'last_login', 'delete_obj'] 
    list_display_links = ['username'] 
    list_filter = ['is_active'] 
    fieldsets = (
     (None, { 
      'fields': ('first_name', 'last_name', 'email', 'username', 
       'is_active', 'is_superuser')}), 
     (('Groups'), {'fields': ('groups',)}), 
    ) 
    ordering = ['last_name', 'first_name'] 
    search_fields = ['first_name', 'last_name'] 


admin.site.register(User, UserProfileAdmin) 

Bu tam benim istediğim, bu bilgileri satır içi formset validate yapar gelmez İşte benim çözümdür. Bu nedenle, profil formunda gerekli alanlar bulunduğundan, gerekli bilgilerin satır içi formda girilmemesi durumunda geçerli olur ve başarısız olur.

+1

'GenericInlineModelAdmin' kullanıyorsanız,' BaseInlineFormSet' yerine 'BaseGenericInlineFormSet' yazın. – L42y

+1

Teşekkürler! Ancak, formunuzda gerekli alanlar yoksa, boş olduğunda hala geçerli olmaz ve kaydedilmez. Maymun-formunu 'form.has_changed = lambda: True' kullanarak doldurun ve boş olmasına rağmen kurtarın. – bouke

9

Muhtemelen bunu yapabilirsiniz, ancak ellerinizi form kümesi/satır içi kodunda kirletmeniz gerekir. Her şeyden

Birincisi, her zaman kimse bu durumda formset formu ve asla birden fazla olacaksa istediğini düşünüyorum, bu yüzden size ProfileInline içinde max_num = 1 ve extra = 1 set isteyeceksiniz.

Temel sorun, formda her "ek" (yani boş) formun BaseFormSet._construct_form passes empty_permitted=True olmasıdır. Bu parametre, formunun değişmemesi durumunda onaylamayı atlamasını belirtir. Sadece form için empty_permitted = False değerini ayarlamanın bir yolunu bulmanız yeterlidir.

Satırınızda use your own BaseInlineFormset subclass yapabilirsiniz, bu da yardımcı olabilir. _construct_form öğesinin ** kwargs aldığını ve her bir Form örneğine iletilen kwarkları geçersiz kılmasına izin verdiğine dikkat ederek, Formset alt sınıfınızdaki _construct_forms değerini geçersiz kılabilir ve boş bırakılmış bir dosyaya sahip olabilirsiniz: _construct_form için her çağrıda false = false. Downside orada iç API'lere güveniyorsunuz (ve _construct_forms yeniden yazmak zorunda).

Alternatif olarak, ProfileInline üzerinde get_formset yöntemi geçersiz deneyebilirsiniz ve ebeveynin get_formset çağırdıktan sonra elle döndürülen formset içindeki formu karıştırmak: etrafında

def get_formset(self, request, obj=None, **kwargs): 
    formset = super(ProfileInline, self).get_formset(request, obj, **kwargs) 
    formset.forms[0].empty_permitted = False 
    return formset 

Çal ve iş yapmak yapabileceğini görmek !

+0

Teşekkür bakın.Ben bir çözüm buldum ama çok hack-ish, ve özellikle bununla gurur duymuyorum. ModelAdmin için add_view'i geçersiz kıldım ve tüm kodu varsayılan görünümden kopyalayıp formset değerlerini değiştirdim. Bunu daha temiz bir şekilde uygulayıp uygulayamayacağımı görmek için önerilerinize bir göz atacağım. Yolcular için teşekkürler! –

7

Bunu yapmanın en kolay ve en doğal yolu fomset clean() yoluyladır:

class RequireOneFormSet(forms.models.BaseInlineFormSet): 
    def clean(self): 
     super().clean() 
     if not self.is_valid(): 
      return 
     if not self.forms or not self.forms[0].cleaned_data: 
      raise ValidationError('At least one {} required' 
            .format(self.model._meta.verbose_name)) 

class ProfileInline(admin.StackedInline): 
    model = Profile 
    formset = RequireOneFormSet 

(this Matthew Flanagan's snippet esinlenerek ve aşağıda Mitar yaptığı yorum Django 1.11 ve 2.0 çalışmak için test).

+2

Mükemmel! Ben bunu biraz değiştirdim, eğer self.is_valid() değilse, 'self.errors' üzerinden manüel olarak gidip' self.model._meta.verbose_name' kullanılır. – Mitar

16

Şimdi Django 1.7 ile min_num parametresini kullanabilirsiniz. Artık RequiredInlineFormSet sınıfına ihtiyacınız yok.

bilgi için https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.min_num

class ProfileInline(admin.StackedInline): 
    """ 
    Allows profile to be added when creating user 
    """ 
    model = Profile 
    extra = 1 
    max_num = 1 
    min_num = 1 # new in Django 1.7 


class UserProfileAdmin(admin.ModelAdmin): 
    """ 
    Options for the admin interface 
    """ 
    inlines = [ProfileInline] 
    ... 


admin.site.register(User, UserProfileAdmin) 
+0

Bu, yalnızca gösterilen satır içi sayısını kontrol eder. Herhangi bir içeriğin doldurulmasını gerektirmez. – spookylukey

+5

Satır içi gereken alanlardan birine sahipse, satır içi içeriğin de doldurulup doldurulmadığını denetler. – quick

+1

Onaylanan çalışma :) – Geotob

İlgili konular