문제

Object B에 대한 외국 키로 객체 A를 편집 할 때마다 객체 B의 선택 옆에 "Add Alth"를 사용할 수 있습니다. 해당 옵션을 제거하려면 어떻게해야합니까?

객체 B를 추가 할 권한이없는 사용자를 구성했습니다. Plus 부호는 여전히 사용할 수 있지만 클릭하면 "권한 거부"라고 표시됩니다. 못 생겼어.

Django 1.0.2를 사용하고 있습니다

도움이 되었습니까?

해결책

감가 상각 된 답변

장고는 이후 이것을 가능하게했다.


대신 CSS를 사용하여 단순히 버튼을 표시하지 않는 것을 고려해 보셨습니까? 어쩌면 너무 해킹 될 수도 있습니다.

이것은 테스트되지 않았지만 생각하고 있습니다 ...

아드 다이나 로저-버튼 .CSS

#_addanother { display: none }

admin.py

class YourAdmin(admin.ModelAdmin):
    # ...
    class Media:
        # edit this path to wherever
        css = { 'all' : ('css/no-addanother-button.css',) }

이 작업을 수행 한 Django Doc- 정적 정의로서 미디어

참고/편집 : 문서에 따르면 파일은 Media_URL과 함께 선정 될 것이지만 실험에서는 그렇지 않습니다. 귀하의 마일리지가 다를 수 있습니다.

이것이 당신의 경우라면, 이것에 대한 빠른 해결책이 있습니다 ...

class YourAdmin(admin.ModelAdmin):
    # ...
    class Media:
        from django.conf import settings
        media_url = getattr(settings, 'MEDIA_URL', '/media/')
        # edit this path to wherever
        css = { 'all' : (media_url+'css/no-addanother-button.css',) }

다른 팁

(이 잘못된 대답을 멈추지 마세요 !!!)

정오표 :이 답변은 기본적으로 잘못되었으며 OP의 질문에 대답하지 않습니다. 아래를 참조하십시오.

(이것은 OP가 요청한 것처럼 외국 키 필드가 아니라 인라인 형태에만 적용됩니다)

더 간단한 솔루션, CSS 해킹 없음, 편집 Django 코드베이스 :

인라인 클래스에 이것을 추가하십시오.

max_num=0

업데이트

이것은 OP의 질문에 대답하지 않으며 요청 된대로 외국 키가 아니라 인라인 형식의 "관련"버튼을 숨기는 데 유용합니다.

내가이 답을 썼을 때, IIRC가 받아 들여진 답변은 둘 다 숨기므로 혼란스러워졌습니다.

다음 링크는 솔루션을 제공하는 것으로 보입니다 (CSS를 사용하는 숨기는 것이 가장 실현 가능한 것 같습니다. 특히 인라인 형태의 "다른 추가"버튼이있는 경우 :

Django 1.7 인라인 양식에서 추가 버튼을 제거합니다

여기에 언급 된 대부분의 솔루션이 작동하지만 더 깨끗한 방법이 있습니다. 아마도 다른 솔루션이 발표 된 후 후기 버전의 Django에서 소개되었을 것입니다. (저는 현재 Django 1.7을 사용하고 있습니다)

"다른 추가"옵션을 제거하려면

class ... #(Your inline class)

    def has_add_permission(self, request):
        return False

마찬가지로 "삭제"를 비활성화하려면? 옵션, 인라인 클래스에 다음 방법을 추가하십시오.

    def has_delete_permission(self, request, obj=None):
        return False

NB는 Django 1.5.2에서 일하고 나이가 들었습니다. 그만큼 can_add_related 재산 나타났습니다 약 2 년 전.

내가 찾은 가장 좋은 방법은 modeladmin의 get_form 함수를 무시하는 것입니다. 제 경우에는 게시물의 저자가 현재 로그인 한 사용자가되도록 강요하고 싶었습니다. 풍부한 의견과 함께 아래 코드. 정말 중요한 비트는 설정입니다 widget.can_add_related:

def get_form(self,request, obj=None, **kwargs):
    # get base form object    
    form = super(BlogPostAdmin,self).get_form(request, obj, **kwargs)

    # get the foreign key field I want to restrict
    author = form.base_fields["author"]

    # remove the green + by setting can_add_related to False on the widget
    author.widget.can_add_related = False

    # restrict queryset for field to just the current user
    author.queryset = User.objects.filter(pk=request.user.pk)

    # set the initial value of the field to current user. Redundant as there will
    # only be one option anyway.
    author.initial = request.user.pk

    # set the field's empty_label to None to remove the "------" null 
    # field from the select. 
    author.empty_label = None

    # return our now modified form.
    return form

여기에서 변화를 만드는 흥미로운 부분 get_form 그게 다 author.widget 인스턴스입니다 django.contrib.admin.widgets.RelatedFieldWidgetWrapper 마치 중 하나를 시도하고 변경하는 것처럼 formfield_for_xxxxx 함수, 위젯은 실제 양식 위젯의 인스턴스입니다.이 일반적인 외국 키 케이스에서는 django.forms.widgets.Select.

보다 django.contrib.admin.options.py 그리고 확인하십시오 BaseModelAdmin 수업, formfield_for_dbfield 방법.

당신은 이것을 볼 것입니다 :

# For non-raw_id fields, wrap the widget with a wrapper that adds
# extra HTML -- the "add other" interface -- to the end of the
# rendered output. formfield can be None if it came from a
# OneToOneField with parent_link=True or a M2M intermediary.
if formfield and db_field.name not in self.raw_id_fields:
    formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)

최선의 방법은 서브 클래스를 만드는 것이라고 생각합니다 ModelAdmin (결국 서브 클래스입니다 BaseModelAdmin), 새로운 클래스에 대한 모델을 기준으로 formfield_fo_dbfield 그리고 그것이 위젯을 조건부로 감싸지 않도록하십시오. RelatedFieldWidgetWrapper.

관련 객체를 추가 할 권한이없는 사용자가있는 경우 RelatedFieldWidgetWrapper 추가 링크를 표시하지 않아야합니까? 어쩌면 이것은 언급 할 가치가있는 것입니다. Django Trac?

나는 다음 접근법을 사용합니다 형태 그리고 inlineform

Django 2.0, Python 3+

형태

class MyModelAdmin(admin.ModelAdmin):
    #...
    def get_form(self,request, obj=None, **kwargs):

        form = super().get_form(request, obj, **kwargs)
        user = form.base_fields["user"]

        user.widget.can_add_related = False
        user.widget.can_delete_related = False
        user.widget.can_change_related = False

        return form  

인라인 형태

class MyModelInline(admin.TabularInline):
    #...
    def get_formset(self, request, obj=None, **kwargs):

        formset = super().get_formset(request, obj, **kwargs)
        user = formset.form.base_fields['user']

        user.widget.can_add_related = False
        user.widget.can_delete_related = False
        user.widget.can_change_related = False

        return formset

답변 @SlipStream어떻게 솔루션을 구현하려면 viz. Formfield의 위젯의 속성을 무시함으로써, 그러나 제 생각에는 get_form 이것을하기에 가장 논리적 인 장소는 아닙니다.

답변 @Cethegeek어디 솔루션을 구현하려면 viz. 연장에서 formfield_for_dbfield, 그러나 명시적인 예를 제공하지는 않습니다.

왜 사용 formfield_for_dbfield? 그것의 Docstring 양식 필드를 엉망으로 만들기위한 지정된 후크라고 제안합니다.

주어진 데이터베이스 필드 인스턴스의 양식 필드 인스턴스를 지정하려면 후크.

또한 (약간) 클리너 및 명확한 코드를 허용하고 보너스로 추가 양식을 쉽게 설정할 수 있습니다. Field 속성, 와 같은 initial 가치 및/또는 disabled (예시 여기), 그것들을 추가함으로써 kwargs (전화하기 전에 super).

따라서 두 가지 답변을 결합합니다 (OP의 모델이 ModelA 그리고 ModelB, 그리고 ForeignKey 모델 필드가 명명되었습니다 b):

class ModelAAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, request, **kwargs):
        # optionally set Field attributes here, by adding them to kwargs
        formfield = super().formfield_for_dbfield(db_field, request, **kwargs)
        if db_field.name == 'b':
            formfield.widget.can_add_related = False
            formfield.widget.can_change_related = False
            formfield.widget.can_delete_related = False
        return formfield

# Don't forget to register...
admin.site.register(ModelA, ModelAAdmin)

참고 : 인 경우 ForeignKey 모델 필드가 있습니다 on_delete=models.CASCADE,, can_delete_related 속성입니다 False 기본적으로, 원천 ~을 위한 RelatedFieldWidgetWrapper.

나는 django 2.x를 사용하고 있으며 적어도 내 경우에는 최상의 솔루션을 찾았다 고 생각합니다.

"저장 및 다른 추가"버튼에 HTML 파일이 켜져 있습니다. your_python_installation\Lib\site-packages\django\contrib\admin\templates\admin\subtmit_line.html.

  1. 해당 HTML 파일을 복사하여 프로젝트에 페이팅하십시오. your_project\templates\admin\submit_line.html.
  2. 원하는대로 버튼 코드를 주석/삭제하십시오.

{#{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}#}

이 문제가 이미 답변된다는 것을 알고 있습니다. 그러나 미래의 누군가가 나와 비슷한 경우를 가지고있을 것입니다.

Cethegeek 답변을 기반으로 나는 이것을 만들었다 :

class SomeAdmin(admin.ModelAdmin):
    form = SomeForm

    def formfield_for_dbfield(self, db_field, **kwargs):
        formfield = super(SomeAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == 'some_m2m_field':
            request = kwargs.pop("request", None)
            formfield = self.formfield_for_manytomany(db_field, request, **kwargs)  # for foreignkey: .formfield_for_foreignkey
            wrapper_kwargs = {'can_add_related': False, 'can_change_related': False, 'can_delete_related': False}
            formfield.widget = admin.widgets.RelatedFieldWidgetWrapper(
                formfield.widget, db_field.remote_field, self.admin_site, **wrapper_kwargs
            )
        return formfield

django.contrib.admin.widgets.py

(django install dir) /django/contrib/admin/widgets.py : 239 행과 244 행 사이에 모든 것을 주석

 if rel_to in self.admin_site._registry: # If the related object has an admin interface:
        # TODO: "id_" is hard-coded here. This should instead use the correct
        # API to determine the ID dynamically.
        output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
            (related_url, name))
        output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Add Another')))
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top