복붙노트

[PYTHON] 한 객체의 장고 관리 페이지에서 관련 객체의 관리 페이지로 링크를 어떻게 추가합니까?

PYTHON

한 객체의 장고 관리 페이지에서 관련 객체의 관리 페이지로 링크를 어떻게 추가합니까?

django-admin에서 중첩 된 인라인이 없다는 것을 다루기 위해 특별한 경우를 두 개의 템플릿에 넣고 관리자 변경 페이지와 두 모델의 인라인 관리자 사이에 링크를 만듭니다.

내 질문은 : 관리자 변경 페이지 또는 한 모델의 인라인 관리자에서 템플릿의 불쾌한 해킹없이 관리자 변경 페이지 또는 관련 모델의 인라인 관리자로 연결되는 링크를 어떻게 만듭니 까?

모든 모델의 관리자 변경 페이지 또는 인라인 관리자에게 적용 할 수있는 일반적인 솔루션을 원합니다.

블로그 관리 페이지의 인라인과 자체 관리 페이지가있는 하나의 모델 인 게시물 (실제 이름이 아님)이 있습니다. 인라인 할 수없는 이유는 외부 키가있는 모델을 가지고 편집 할 때만 의미가 있으며 블로그로 편집 할 때 의미가 있다는 것입니다.

사후 관리 페이지의 경우 "fieldset.html"의 일부를 다음과 같이 변경했습니다.

{% if field.is_readonly %}
    <p>{{ field.contents }}</p>
{% else %}
    {{ field.field }}
{% endif %}

{% if field.is_readonly %}
    <p>{{ field.contents }}</p>
{% else %}
    {% ifequal field.field.name "blog" %}
        <p>{{ field.field.form.instance.blog_link|safe }}</p>
    {% else %}
        {{ field.field }}
    {% endifequal %}
{% endif %}

blog_link가 모델의 메소드 인 블로그 관리 페이지에 대한 링크를 작성하려면 다음을 수행하십시오.

def blog_link(self):
      return '<a href="%s">%s</a>' % (reverse("admin:myblog_blog_change",  
                                        args=(self.blog.id,)), escape(self.blog))

field.field.form.instance 외부에서 블로그 인스턴스의 ID를 찾을 수 없습니다.

게시물이 인라인 인 블로그 관리자 페이지에서 "stacked.html"의 일부를 다음과 같이 수정했습니다.

<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;
<span class="inline_label">{% if inline_admin_form.original %}
    {{ inline_admin_form.original }}
{% else %}#{{ forloop.counter }}{% endif %}</span>

<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;
<span class="inline_label">{% if inline_admin_form.original %}
    {% ifequal inline_admin_formset.opts.verbose_name "post" %}
    <a href="/admin/myblog/post/{{ inline_admin_form.pk_field.field.value }}/">
            {{ inline_admin_form.original }}</a>
{% else %}{{ inline_admin_form.original }}{% endifequal %}
{% else %}#{{ forloop.counter }}{% endif %}</span>

게시물 관리 페이지에 대한 링크를 만들 때부터 여기에서 외래 키 필드에 저장된 ID를 찾을 수있었습니다.

나 자신을 반복하지 않고 관리자 양식에 링크를 추가하는 것이 더 좋고 더 일반적인 방법이라고 확신합니다. 뭐야?

해결법

  1. ==============================

    1.Django 1.8의 새로운 기능 : 인라인 관리자 용 show_change_link.

    Django 1.8의 새로운 기능 : 인라인 관리자 용 show_change_link.

    인라인 모델에서 show_change_link를 True (기본값은 False)로 설정하면 인라인 오브젝트가 변경 양식에 대한 링크를 가질 수 있습니다. 여기서 인라인 오브젝트는 자체 인라인을 가질 수 있습니다.

    from django.contrib import admin
    
    class PostInline(admin.StackedInline):
        model = Post
        show_change_link = True
        ...
    
    class BlogAdmin(admin.ModelAdmin):
        inlines = [PostInline]
        ...
    
    class ImageInline(admin.StackedInline):
        # Assume Image model has foreign key to Post
        model = Image
        show_change_link = True
        ...
    
    class PostAdmin(admin.ModelAdmin):
        inlines = [ImageInline]
        ...
    
    admin.site.register(Blog, BlogAdmin)
    admin.site.register(Post, PostAdmin)
    
  2. ==============================

    2.readonly_fields 사용 :

    readonly_fields 사용 :

    class MyInline(admin.TabularInline):
        model = MyModel
        readonly_fields = ['link']
    
        def link(self, obj):
            url = reverse(...)
            return mark_safe("<a href='%s'>edit</a>" % url)
    
        # the following is necessary if 'link' method is also used in list_display
        link.allow_tags = True
    
  3. ==============================

    3.이것은 Pannu (편집자)와 Mikhail이 제안한 것에 기반한 나의 현재 솔루션입니다.

    이것은 Pannu (편집자)와 Mikhail이 제안한 것에 기반한 나의 현재 솔루션입니다.

    나는 최상위 관리자에게 변경해야 할 몇 가지 최상위 관리자 변경보기가있다. 관련 관리자는 최상위 관리자로 변경해야한다. 같은 대상. 그렇기 때문에 나는 모든 관리자 변경보기에 대해 그것의 변형을 반복하는 것이 아니라 링크 방법을 분석하려고합니다.

    클래스 데코레이터를 사용하여 callable 링크를 만들고 readonly_fields에 추가합니다.

    def add_link_field(target_model = None, field = '', link_text = unicode):
        def add_link(cls):
            reverse_name = target_model or cls.model.__name__.lower()
            def link(self, instance):
                app_name = instance._meta.app_label
                reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
                link_obj = getattr(instance, field, None) or instance
                url = reverse(reverse_path, args = (link_obj.id,))
                return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj)))
            link.allow_tags = True
            link.short_description = reverse_name + ' link'
            cls.link = link
            cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + ['link']
            return cls
        return add_link
    

    연결하는 객체에서 유니 코드를 호출하는 것보다 링크 텍스트를 가져와야하는 경우 사용자 정의 호출 가능 함수를 전달할 수도 있습니다.

    나는 이것을 다음과 같이 사용한다 :

    # the first 'blog' is the name of the model who's change page you want to link to
    # the second is the name of the field on the model you're linking from
    # so here, Post.blog is a foreign key to a Blog object. 
    @add_link_field('blog', 'blog')
    class PostAdmin(admin.ModelAdmin):
        inlines = [SubPostInline, DefinitionInline]
        fieldsets = ((None, {'fields': (('link', 'enabled'),)}),)
        list_display = ('__unicode__', 'enabled', 'link')
    
    # can call without arguments when you want to link to the model change page
    # for the model of an inline model admin.
    @add_link_field()
    class PostInline(admin.StackedInline):
        model = Post
        fieldsets = ((None, {'fields': (('link', 'enabled'),)}),)
        extra = 0
    

    당연히 Django에 패치를 적용하지 않고 블로그 관리자 변경 페이지의 Post의 인라인 관리자 내에서 SubPost 및 정의에 대한 관리자 변경보기를 중첩 할 수 있다면이 중 아무 것도 필요하지 않습니다.

  4. ==============================

    4.나는 agf의 해결책이 꽤 굉장하다고 생각합니다. 그에게 많은 명성이 있습니다. 하지만 몇 가지 더 많은 기능이 필요했습니다.

    나는 agf의 해결책이 꽤 굉장하다고 생각합니다. 그에게 많은 명성이 있습니다. 하지만 몇 가지 더 많은 기능이 필요했습니다.

    해결책:

    def add_link_field(target_model = None, field = '', app='', field_name='link',
                       link_text=unicode):
        def add_link(cls):
            reverse_name = target_model or cls.model.__name__.lower()
            def link(self, instance):
                app_name = app or instance._meta.app_label
                reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
                link_obj = getattr(instance, field, None) or instance
                url = reverse(reverse_path, args = (link_obj.id,))
                return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj)))
            link.allow_tags = True
            link.short_description = reverse_name + ' link'
            setattr(cls, field_name, link)
            cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + \
                [field_name]
            return cls
        return add_link
    

    용법:

    # 'apple' is name of model to link to
    # 'fruit_food' is field name in `instance`, so instance.fruit_food = Apple()
    # 'link2' will be name of this field
    @add_link_field('apple','fruit_food',field_name='link2')
    # 'cheese' is name of model to link to
    # 'milk_food' is field name in `instance`, so instance.milk_food = Cheese()
    # 'milk' is the name of the app where Cheese lives
    @add_link_field('cheese','milk_food', 'milk')
    class FoodAdmin(admin.ModelAdmin):
        list_display = ("id", "...", 'link', 'link2')
    

    예제가 너무 비논리적 인 것은 유감이지만 데이터를 사용하고 싶지 않습니다.

  5. ==============================

    5.템플릿 편집을하기가 어렵다는 점에 동의합니다. 관리자 변경보기 페이지에 앵커를 표시하는 사용자 정의 위젯을 만듭니다 (양식 및 인라인 양식 모두에서 사용할 수 있음).

    템플릿 편집을하기가 어렵다는 점에 동의합니다. 관리자 변경보기 페이지에 앵커를 표시하는 사용자 정의 위젯을 만듭니다 (양식 및 인라인 양식 모두에서 사용할 수 있음).

    그래서, 앵커 위젯을 사용하여 페이지의 링크를 얻기 위해 양식을 재정의했습니다.

    forms.py:

    class AnchorWidget(forms.Widget):
    
        def _format_value(self,value):
            if self.is_localized:
                return formats.localize_input(value)
            return value
    
        def render(self, name, value, attrs=None):
            if not value:
                value = u''
    
            text = unicode("")
            if self.attrs.has_key('text'):
                text = self.attrs.pop('text')
    
            final_attrs = self.build_attrs(attrs,name=name)
    
            return mark_safe(u"<a %s>%s</a>" %(flatatt(final_attrs),unicode(text)))
    
    class PostAdminForm(forms.ModelForm):
        .......
    
        def __init__(self,*args,**kwargs):
            super(PostAdminForm, self).__init__(*args, **kwargs)
            instance = kwargs.get('instance',None)
            if instance.blog:
                href = reverse("admin:appname_Blog_change",args=(instance.blog))  
                self.fields["link"] = forms.CharField(label="View Blog",required=False,widget=AnchorWidget(attrs={'text':'go to blog','href':href}))
    
    
     class BlogAdminForm(forms.ModelForm):
        .......
        link = forms..CharField(label="View Post",required=False,widget=AnchorWidget(attrs={'text':'go to post'}))
    
        def __init__(self,*args,**kwargs):
            super(BlogAdminForm, self).__init__(*args, **kwargs)
            instance = kwargs.get('instance',None)
            href = ""
            if instance:
                posts = Post.objects.filter(blog=instance.pk)
                for idx,post in enumerate(posts):
                    href = reverse("admin:appname_Post_change",args=(post["id"]))  
                    self.fields["link_%s" % idx] = forms..CharField(label=Post["name"],required=False,widget=AnchorWidget(attrs={'text':post["desc"],'href':href}))
    

    이제 ModelAdmin에서 양식 속성을 무시하고 원하는 결과를 얻어야합니다. 나는 당신이이 테이블 사이에 OneToOne 관계를 가지고 있다고 가정했다. 만약 당신이 1 대 1로 많다면 BlogAdmin 측은 작동하지 않을 것이다.

    최신 정보:     동적으로 링크를 추가하기 위해 몇 가지 사항을 변경했으며, OneToMany 문제를 블로그 게시로 해결하여이 문제를 해결할 수 있기를 바랍니다. :)

    Pastebin 이후 :    귀하의 PostAdmin에서 blog_link를 발견했습니다. 즉, 모든 게시물을 나열하는 changelist_view에 블로그 링크를 표시하려는 것입니다. 내가 맞다면 페이지에 링크를 표시하는 메소드를 추가해야합니다.

    class PostAdmin(admin.ModelAdmin):
        model = Post
        inlines = [SubPostInline, DefinitionInline]
        list_display = ('__unicode__', 'enabled', 'blog_on_site')
    
        def blog_on_site(self, obj):
            href = reverse("admin:appname_Blog_change",args=(obj.blog))
            return mark_safe(u"<a href='%s'>%s</a>" %(href,obj.desc))
        blog_on_site.allow_tags = True
        blog_on_site.short_description = 'Blog'
    

    BlogAdmin changelist_view에 게시 링크를 게시하는 경우 위와 동일하게 수행 할 수 있습니다. 저의 이전 솔루션은 각 인스턴스를 편집 할 수있는 change_view 페이지에서 한 단계 아래 링크를 보여줍니다.

    BlogAdmin 페이지에서 change_view 페이지의 게시물에 대한 링크를 표시하려면 BlogAdmin 클래스의 get_form 메소드를 무시하고 링크를 동적으로 추가하여 각 필드 세트에 동적으로 포함시켜야합니다. get_form에 self.fieldsets, 먼저 필드 집합에 튜플을 사용하지 말고 목록을 사용하십시오.

  6. ==============================

    6.agfs와 SummerBreeze의 제안을 토대로 유니 코드를보다 잘 처리하고 역방향 외부 필드 (ManyRelatedManager와 하나의 결과)를 연결할 수 있도록 데코레이터를 개선했습니다. 또한 이제 short_description을 목록 헤더로 추가 할 수 있습니다.

    agfs와 SummerBreeze의 제안을 토대로 유니 코드를보다 잘 처리하고 역방향 외부 필드 (ManyRelatedManager와 하나의 결과)를 연결할 수 있도록 데코레이터를 개선했습니다. 또한 이제 short_description을 목록 헤더로 추가 할 수 있습니다.

    from django.core.urlresolvers import reverse
    from django.core.exceptions import MultipleObjectsReturned
    from django.utils.safestring import mark_safe
    
    def add_link_field(target_model=None, field='', app='', field_name='link',
                       link_text=unicode, short_description=None):
        """
        decorator that automatically links to a model instance in the admin;
        inspired by http://stackoverflow.com/questions/9919780/how-do-i-add-a-link-from-the-django-admin-page-of-one-object-
        to-the-admin-page-o
        :param target_model: modelname.lower or model
        :param field: fieldname
        :param app: appname
        :param field_name: resulting field name
        :param link_text: callback to link text function
        :param short_description: list header
        :return:
        """
        def add_link(cls):
            reverse_name = target_model or cls.model.__name__.lower()
    
            def link(self, instance):
                app_name = app or instance._meta.app_label
                reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
                link_obj = getattr(instance, field, None) or instance
    
                # manyrelatedmanager with one result?
                if link_obj.__class__.__name__ == "RelatedManager":
                    try:
                        link_obj = link_obj.get()
                    except MultipleObjectsReturned:
                        return u"multiple, can't link"
                    except link_obj.model.DoesNotExist:
                        return u""
    
                url = reverse(reverse_path, args = (link_obj.id,))
                return mark_safe(u"<a href='%s'>%s</a>" % (url, link_text(link_obj)))
            link.allow_tags = True
            link.short_description = short_description or (reverse_name + ' link')
            setattr(cls, field_name, link)
            cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + \
                [field_name]
            return cls
        return add_link
    

    편집 : 링크가 없어져서 업데이트되었습니다.

  7. ==============================

    7.관리 클래스의 소스를 살펴보면 관리 뷰에서 '원본'이라는 컨텍스트의 개체를 사용할 수 있음을 알 수 있습니다.

    관리 클래스의 소스를 살펴보면 관리 뷰에서 '원본'이라는 컨텍스트의 개체를 사용할 수 있음을 알 수 있습니다.

    비슷한 상황이 있습니다. 변경 목록보기에 추가 된 정보가 필요했습니다. 관리자 블로그에 데이터를 추가합니다 (내 블로그에 있음).

  8. from https://stackoverflow.com/questions/9919780/how-do-i-add-a-link-from-the-django-admin-page-of-one-object-to-the-admin-page-o by cc-by-sa and MIT license