2012-02-28 1 views
0

좀 장고이 유사한 구조를 가진 모델이 있습니다 상속 아이들의 두 종류가있다, 그래서 기본적으로어떻게 현재보고 인스턴스에 관련된 새로운 모델 인스턴스 생성 페이지에 링크를

class Grandparent(models.Model): 
    name = models.CharField(max_length=80) 

class Parent(models.Model): 
    name = models.CharField(max_length=80) 
    grandparent = models.ForeignKey(Grandparent, related_name='children') 

class Child(models.Model): 
    parent = models.ForeignKey(Parent, related_name='children') 

class ChildA(Child) 
    something = models.CharField(max_length=80) 
    anotherthing = models.IntegerField() 

class ChildB(Child) 
    anything = models.CharField(max_length=80) 
    hello = models.BooleanField() 

을 실질적으로 추상적 인 Child 모델입니다. (그래서 추상적 인 것이 아니기 때문에 외래 키를 사용할 수 있습니다.)

질문 - 첫 번째 모델 (Grandparent)의 관리 페이지에서 새로운 Parent 모델의 생성 페이지로 연결되는 링크를 어떻게 만들 수 있습니까? 해당 Parent 모델에는 현재 표시된 grandparent 페이지 ID로 채워진 Grandparent 외래 키 필드가 있어야합니다.

를 인라인가 마음에 오는 일이 있습니다,하지만 난 인라인가 중첩 될 수 없기 때문에 사용할 수 없습니다와 나는 Parent 페이지에서 ChildAChildB 내부 필드를 조작을 필요로한다.

+0

흠 ... 아니. 내가 의미했던 것이 아니다. 어쩌면 몇 가지 사항을 명확히하기 위해 일부 필드를 변경했습니다. – Ohad

+0

내 첫 번째 대답은 그 때 당신이 필요로하는 것입니다. –

답변

1

대답은 두 단계로 구성

# your_app_name/admin.py  
from django import forms 
from django.utils.safestring import mark_safe 
from django.contrib import admin 
from django.core.exceptions import ObjectDoesNotExist 

# 1. Override `Grandparent`'s and `Parent`'s `ModelAdmin` forms: 
# 
# Create a widget with a hyperlink to `Parent` admin form 
# with `Grandparent`'s primary key as `GET` parameter. 
# Place it in `Grandparent`'s `ModelAdmin`: 

class AddParentAdminWidget(forms.Widget): 

    def __init__(self, obj, attrs=None): 
     self.object = obj 
     super(AddParentAdminWidget, self).__init__(attrs) 

    def render(self, name, value, attrs=None): 
     if self.object.pk: 
      return mark_safe(
       u"""<a class="button" href="../../../%(app_label)s/%(object_name)s/add/?grandparent_pk=%(object_pk)s">%(linktitle)s</a> 
       """ %\ 
       { 
        'app_label': Parent._meta.app_label, 
        'object_name': Parent._meta.object_name.lower(), 
        'object_pk': self.object.pk, 
        'linktitle': 'Add new Parent instance with prepopulated Grandparent field.', 
        } 
      ) 
     else: 
      return mark_safe(u'') 

# Add a dummy `add_new_parent_link` field to `Grandparent's` form 
# just to be able to replace it with your previously created widget. 

class GrandparentAdminForm(forms.ModelForm): 
    add_new_parent_link = forms.CharField(label = 'Add new parent instance', required = False) 

    def __init__(self, *args, **kwargs): 
     super(GrandparentAdminForm, self).__init__(*args, **kwargs) 
     # instance is always available, it just does or doesn't have pk. 
     self.fields['add_new_parent_link'].widget = AddParentAdminWidget(self.instance) 

    class Meta: 
     model = Grandparent 

class GrandparentAdmin(admin.ModelAdmin): 
    form = GrandparentAdminForm 

# 2. Set initial data in `Parent`'s `ModelForm` 
# 
# (do this by accessing the `request` object, 
# which is set in `ParentAdmin` code below): 

class ParentAdminForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     self.request = kwargs.pop('request', None) 
     super(ParentAdminForm, self).__init__(*args, **kwargs) 
     if self.request.GET.get('grandparent_pk', False): 
      try: 
       grandparent_pk = int(self.request.GET.get('grandparent_pk', ''),) 
      except ValueError: 
       pass 
      else: 
       try: 
        Grandparent.objects.get(pk = grandparent_pk) 
       except ObjectDoesNotExist: 
        pass 
       else: 
        self.initial['grandparent'] = grandparent_pk 

    class Meta: 
     model = Parent 

# Add your children as regular `StackedInline`'s 

class ChildInline(admin.StackedInline): 
    model = Child 

class ChildAInline(admin.StackedInline): 
    model = ChildA 

class ChildBInline(admin.StackedInline): 
    model = ChildB 

class ParentAdmin(admin.ModelAdmin): 
    form = ParentAdminForm 

    def get_form(self, request, obj=None, **kwargs): 
     """ 
     Use a trick to be able to access `request` object in `ParentAdminForm`. 
     Yes, unfortunately we need it [http://stackoverflow.com/a/6062628/497056] 
     to access `request` object in an admin `ModelForm` (as of `Django` 1.4). 
     Hopefully, this will be fixed in newer versions. 
     """ 
     AdminForm = super(ParentAdmin, self).get_form(request, obj, **kwargs) 
     class ModelFormMetaClass(AdminForm): 
      """ 
      We need this metaclass 
      to be able to access request in a form 
      """ 
      def __new__(cls, *args, **kwargs): 
       kwargs['request'] = request 
       return AdminForm(*args, **kwargs) 

     return ModelFormMetaClass 

    inlines = [ 
     ChildInline, 
     ChildAInline, 
     ChildBInline, 
     ] 

admin.site.register(Grandparent, GrandparentAdmin) 
admin.site.register(Parent, ParentAdmin) 
+0

글쎄, 나는 그것을 작동시키지 못했습니다 ... 나는 초보자인데 장황한 대답에 모든 것을 알아낼 수 없었습니다. 좀 더 경험이 많으면 프로젝트에서 더 자세히 살펴볼 것입니다. 감사. – Ohad

+0

아마도 두 가지 이상의 문제가 있지만 4 단계에서 잘못 처리 한 것 같습니다. get ('parent_pk')에 액세스 할 수 없습니다. 오류 메시지는 Nonetype 개체에 'get'메서드가 없다고 말했습니다. ChildAdmin 클래스 코드는 어디에 있어야합니까? 아이는 어쨌든 인라인으로 편집 중입니다. – Ohad

+0

아니요, 제 모델은 정확합니다. 나는 부모에게 3 가지 수준의 자식 트리가 아닌'Child'의 일부 필드를 상속받는 두 종류의 자식 ('ChildA','ChildB')을 갖고 싶습니다. – Ohad

관련 문제