سؤال

كلما قمت بتحرير الكائن A مع مفتاح أجنبي للاعتراض ب، يتوفر خيار Plus "إضافة آخر" بجوار خيارات الكائن B. كيف يمكنني إزالة هذا الخيار؟

قمت بتكوين مستخدم بدون حقوق لإضافة كائن B. لا تزال علامة Plus متوفرة، ولكن عندما أقوم بالنقر فوقه، فإنه يقول "تم رفض الإذن". انها قبيحة.

أنا أستخدم Django 1.0.2

هل كانت مفيدة؟

المحلول

إهمال الإجابة

وقد جعل django منذ ذلك الحين.


هل فكرت بدلا من ذلك باستخدام CSS لمجرد عدم إظهار الزر؟ ربما هذا هو القليل من القليل جدا.

هذا غير مهتم، لكنني أفكر ...

no-addanother-button.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',) }

نصائح أخرى

(توقف عن رفع هذه الإجابة الخاطئة !!!)

errata. : هذه الإجابة مخطئة أساسا، ولا يجيب على سؤال OP. انظر أدناه.

(هذا ينطبق فقط على النماذج المضمنة، وليس الحقول الرئيسية الأجنبية كما طلب المرجع)

حل أبسط، لا CSS هاك، لا تحرير django codebase:

أضف هذا إلى فئة مضمنة:

max_num=0

تحديث

هذا لا يجيب على سؤال OP، وهو مفيد فقط لإخفاء زر "إضافة ذات الصلة" للنماذج المضمنة، وليس مفاتيح أجنبية حسب الطلب.

عندما كتبت هذه الإجابة، أيقظ IIRC الإجابة المقبولة على حد سواء، وهذا هو السبب في أنني حصلت على الخلط.

يبدو أن الروابط التالية توفر حل (على الرغم من أن الاختباء باستخدام CSS يبدو أن أكثر الأشياء ممكنة للقيام بها، خاصة إذا كانت "إضافة أزرار" أخرى من FKs في النماذج المضمنة):

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 خاصية بدا منذ حوالي عامين.

أفضل طريقة وجدتها هي تجاوز وظيفة get_form's modeladmin الخاص بك. في حالتي، أردت إجبار مؤلف منشور أن تكون مسجلا حاليا في المستخدم. الرمز أدناه مع تعليقات وفيرة. الشيء المهم حقا هو إعداد 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، بيثون 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. عن طريق تجاوز السمات لتوفير عنصر واجهة المستخدم، ولكن، في رأيي، 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 %}#}

أعرف أن هذه المشكلة قد أجاب بالفعل. ولكن ربما شخص ما في المستقبل لديه قضية مماثلة معي.

بناء على إجابة CESHEGEEK INT.

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.widget.py.

(django تثبيت dir) /django/contrib/admin/widget.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