mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixed #20836 -- Ensure that the ForeignKey's to_field attribute is properly considered by the admin's interface when creating related objects.
Many thanks to Collin Anderson for the report and patch and to Peter Sheats for the test.
This commit is contained in:
@@ -44,6 +44,7 @@ from django.views.decorators.csrf import csrf_protect
|
||||
|
||||
|
||||
IS_POPUP_VAR = '_popup'
|
||||
TO_FIELD_VAR = '_to_field'
|
||||
|
||||
HORIZONTAL, VERTICAL = 1, 2
|
||||
# returns the <ul> class for a given radio_admin field
|
||||
@@ -932,6 +933,8 @@ class ModelAdmin(BaseModelAdmin):
|
||||
'content_type_id': ContentType.objects.get_for_model(self.model).id,
|
||||
'save_as': self.save_as,
|
||||
'save_on_top': self.save_on_top,
|
||||
'to_field_var': TO_FIELD_VAR,
|
||||
'is_popup_var': IS_POPUP_VAR
|
||||
})
|
||||
if add and self.add_form_template is not None:
|
||||
form_template = self.add_form_template
|
||||
@@ -951,13 +954,20 @@ class ModelAdmin(BaseModelAdmin):
|
||||
opts = obj._meta
|
||||
pk_value = obj._get_pk_val()
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
|
||||
msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)}
|
||||
# Here, we distinguish between different save types by checking for
|
||||
# the presence of keys in request.POST.
|
||||
|
||||
if IS_POPUP_VAR in request.POST:
|
||||
to_field = request.POST.get(TO_FIELD_VAR)
|
||||
if to_field:
|
||||
attr = str(to_field)
|
||||
else:
|
||||
attr = obj._meta.pk.attname
|
||||
value = obj.serializable_value(attr)
|
||||
return SimpleTemplateResponse('admin/popup_response.html', {
|
||||
'pk_value': escape(pk_value),
|
||||
'pk_value': escape(pk_value), # for possible backwards-compatibility
|
||||
'value': escape(value),
|
||||
'obj': escapejs(obj)
|
||||
})
|
||||
|
||||
@@ -988,6 +998,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||
"""
|
||||
Determines the HttpResponse for the change_view stage.
|
||||
"""
|
||||
|
||||
opts = self.model._meta
|
||||
pk_value = obj._get_pk_val()
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
@@ -1224,6 +1235,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||
title=_('Add %s') % force_text(opts.verbose_name),
|
||||
adminform=adminForm,
|
||||
is_popup=IS_POPUP_VAR in request.REQUEST,
|
||||
to_field=request.REQUEST.get(TO_FIELD_VAR),
|
||||
media=media,
|
||||
inline_admin_formsets=inline_admin_formsets,
|
||||
errors=helpers.AdminErrorList(form, formsets),
|
||||
@@ -1297,6 +1309,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||
object_id=object_id,
|
||||
original=obj,
|
||||
is_popup=IS_POPUP_VAR in request.REQUEST,
|
||||
to_field=request.REQUEST.get(TO_FIELD_VAR),
|
||||
media=media,
|
||||
inline_admin_formsets=inline_admin_formsets,
|
||||
errors=helpers.AdminErrorList(form, formsets),
|
||||
@@ -1443,6 +1456,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||
selection_note_all=selection_note_all % {'total_count': cl.result_count},
|
||||
title=cl.title,
|
||||
is_popup=cl.is_popup,
|
||||
to_field=cl.to_field,
|
||||
cl=cl,
|
||||
media=media,
|
||||
has_add_permission=self.has_add_permission(request),
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
{% endblock %}
|
||||
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.model_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %}
|
||||
<div>
|
||||
{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
|
||||
{% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1" />{% endif %}
|
||||
{% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}" />{% endif %}
|
||||
{% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
|
||||
{% if errors %}
|
||||
<p class="errornote">
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
{% block object-tools-items %}
|
||||
<li>
|
||||
{% url cl.opts|admin_urlname:'add' as add_url %}
|
||||
<a href="{% add_preserved_filters add_url is_popup %}" class="addlink">
|
||||
<a href="{% add_preserved_filters add_url is_popup to_field %}" class="addlink">
|
||||
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head><title></title></head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
opener.dismissAddAnotherPopup(window, "{{ pk_value }}", "{{ obj }}");
|
||||
opener.dismissAddAnotherPopup(window, "{{ value }}", "{{ obj }}");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -22,7 +22,7 @@ def admin_urlquote(value):
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def add_preserved_filters(context, url, popup=False):
|
||||
def add_preserved_filters(context, url, popup=False, to_field=None):
|
||||
opts = context.get('opts')
|
||||
preserved_filters = context.get('preserved_filters')
|
||||
|
||||
@@ -48,6 +48,9 @@ def add_preserved_filters(context, url, popup=False):
|
||||
if popup:
|
||||
from django.contrib.admin.options import IS_POPUP_VAR
|
||||
merged_qs[IS_POPUP_VAR] = 1
|
||||
if to_field:
|
||||
from django.contrib.admin.options import TO_FIELD_VAR
|
||||
merged_qs[TO_FIELD_VAR] = to_field
|
||||
|
||||
merged_qs.update(parsed_qs)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ from django.utils.http import urlencode
|
||||
|
||||
from django.contrib.admin import FieldListFilter
|
||||
from django.contrib.admin.exceptions import DisallowedModelAdminLookup
|
||||
from django.contrib.admin.options import IncorrectLookupParameters, IS_POPUP_VAR
|
||||
from django.contrib.admin.options import IncorrectLookupParameters, IS_POPUP_VAR, TO_FIELD_VAR
|
||||
from django.contrib.admin.util import (quote, get_fields_from_path,
|
||||
lookup_needs_distinct, prepare_lookup_value)
|
||||
|
||||
@@ -25,7 +25,6 @@ ORDER_VAR = 'o'
|
||||
ORDER_TYPE_VAR = 'ot'
|
||||
PAGE_VAR = 'p'
|
||||
SEARCH_VAR = 'q'
|
||||
TO_FIELD_VAR = 't'
|
||||
ERROR_FLAG = 'e'
|
||||
|
||||
IGNORED_PARAMS = (
|
||||
|
||||
@@ -248,16 +248,18 @@ class RelatedFieldWidgetWrapper(forms.Widget):
|
||||
return self.widget.media
|
||||
|
||||
def render(self, name, value, *args, **kwargs):
|
||||
from django.contrib.admin.views.main import TO_FIELD_VAR
|
||||
rel_to = self.rel.to
|
||||
info = (rel_to._meta.app_label, rel_to._meta.model_name)
|
||||
self.widget.choices = self.choices
|
||||
output = [self.widget.render(name, value, *args, **kwargs)]
|
||||
if self.can_add_related:
|
||||
related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name)
|
||||
url_params = '?%s=%s' % (TO_FIELD_VAR, self.rel.get_related_field().name)
|
||||
# TODO: "add_id_" is hard-coded here. This should instead use the
|
||||
# correct API to determine the ID dynamically.
|
||||
output.append('<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> '
|
||||
% (related_url, name))
|
||||
output.append('<a href="%s%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> '
|
||||
% (related_url, url_params, name))
|
||||
output.append('<img src="%s" width="10" height="10" alt="%s"/></a>'
|
||||
% (static('admin/img/icon_addlink.gif'), _('Add Another')))
|
||||
return mark_safe(''.join(output))
|
||||
|
||||
Reference in New Issue
Block a user