Ticket #3987: diff-dynamic.3.diff

File diff-dynamic.3.diff, 8.6 KB (added by Baptiste <baptiste.goupil@…>, 8 years ago)

security fix : the choice of an item not in the list of choices must fail

  • db/models/fields/related.py

     
    544544        setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related))
    545545
    546546    def formfield(self, **kwargs):
    547         defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.all()}
     547        defaults = {'form_class': forms.ModelChoiceField}
     548        #To prevent an useless query
     549        if not 'queryset' in kwargs:
     550            defaults['queryset'] = self.rel.to._default_manager.all()
    548551        defaults.update(kwargs)
    549552        return super(ForeignKey, self).formfield(**defaults)
    550553
     
    605608            cls._meta.one_to_one_field = self
    606609
    607610    def formfield(self, **kwargs):
    608         defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.all()}
     611        defaults = {'form_class': forms.ModelChoiceField}
     612        if not 'queryset' in kwargs:
     613            defaults['queryset'] = self.rel.to._default_manager.all()
    609614        defaults.update(kwargs)
    610615        return super(OneToOneField, self).formfield(**defaults)
    611616
     
    711716        return getattr(obj, self.attname).all()
    712717
    713718    def formfield(self, **kwargs):
    714         defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()}
     719        defaults = {'form_class': forms.ModelMultipleChoiceField}
     720        if not 'queryset' in kwargs:
     721            defaults['queryset'] = self.rel.to._default_manager.all()
    715722        defaults.update(kwargs)
    716723        # If initial is passed in, it's a list of related objects, but the
    717724        # MultipleChoiceField takes a list of IDs.
  • newforms/models.py

     
    170170        if value in ('', None):
    171171            return None
    172172        try:
    173             value = self.queryset.model._default_manager.get(pk=value)
     173            value = self.queryset.get(pk=value)
    174174        except self.queryset.model.DoesNotExist:
    175175            raise ValidationError(ugettext(u'Select a valid choice. That choice is not one of the available choices.'))
    176176        return value
     
    193193        final_values = []
    194194        for val in value:
    195195            try:
    196                 obj = self.queryset.model._default_manager.get(pk=val)
     196                obj = self.queryset.get(pk=val)
    197197            except self.queryset.model.DoesNotExist:
    198198                raise ValidationError(ugettext(u'Select a valid choice. %s is not one of the available choices.') % val)
    199199            else:
  • contrib/admin/options.py

     
    103103    raw_id_fields = ()
    104104    fields = None
    105105
    106     def formfield_for_dbfield(self, db_field, **kwargs):
     106    def formfield_for_dbfield(self, db_field, request, **kwargs):
    107107        """
    108108        Hook for specifying the form Field instance for a given database Field
    109109        instance.
     
    113113        # For ManyToManyFields with a filter interface, use a special widget.
    114114        if isinstance(db_field, models.ManyToManyField) and db_field.name in (self.filter_vertical + self.filter_horizontal):
    115115            kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
    116             return db_field.formfield(**kwargs)
     116            if hasattr(self, 'dynamic_%s_choices' % db_field.name):
     117                formfield = db_field.formfield(queryset = getattr(self, 'dynamic_%s_choices' % db_field.name)(request, db_field.rel.to), **kwargs)
    117118
    118119        # For DateTimeFields, use a special field and widget.
    119120        if isinstance(db_field, models.DateTimeField):
     
    133134
    134135        # For ForeignKey or ManyToManyFields, use a special widget.
    135136        if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
     137            if hasattr(self, 'dynamic_%s_choices' % db_field.name):
     138                formfield = db_field.formfield(queryset = getattr(self, 'dynamic_%s_choices' % db_field.name)(request, db_field.rel.to), **kwargs)
     139            else:
     140                formfield = db_field.formfield(**kwargs)
    136141            if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
    137                 kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
    138                 return db_field.formfield(**kwargs)
     142                formfield.widget = widgets.ForeignKeyRawIdWidget(db_field.rel)
    139143            else:
    140144                # Wrap the widget's render() method with a method that adds
    141145                # extra HTML to the end of the rendered output.
    142                 formfield = db_field.formfield(**kwargs)
    143146                formfield.widget.render = widgets.RelatedFieldWidgetWrapper(formfield.widget.render, db_field.rel)
    144                 return formfield
     147            return formfield
     148       
     149        if isinstance(db_field, (models.OneToOneField)) and hasattr(self, 'dynamic_%s_choices' % db_field.name):
     150            return db_field.formfield(queryset = getattr(self, 'dynamic_%s_choices' % db_field.name)(request, db_field.rel.to), **kwargs)
    145151
    146152        # For any other type of field, just call its formfield() method.
    147153        return db_field.formfield(**kwargs)
     
    414420            # Object list will give 'Permission Denied', so go back to admin home
    415421            post_url = '../../../'
    416422
    417         ModelForm = forms.form_for_model(model, formfield_callback=self.formfield_for_dbfield)
     423        ModelForm = forms.form_for_model(model, formfield_callback=lambda f, **kwargs: self.formfield_for_dbfield(f, request, **kwargs))
    418424
    419425        inline_formsets = []
    420426        if request.POST:
     
    422428            if opts.has_field_type(models.FileField):
    423429                new_data.update(request.FILES)
    424430            form = ModelForm(new_data)
    425             for FormSet in self.get_inline_formsets():
     431            for FormSet in self.get_inline_formsets(request):
    426432                inline_formset = FormSet(data=new_data)
    427433                inline_formsets.append(inline_formset)
    428434            if all_valid(inline_formsets) and form.is_valid():
    429435                return self.save_add(request, model, form, inline_formsets, '../%s/')
    430436        else:
    431437            form = ModelForm(initial=request.GET)
    432             for FormSet in self.get_inline_formsets():
     438            for FormSet in self.get_inline_formsets(request):
    433439                inline_formset = FormSet()
    434440                inline_formsets.append(inline_formset)
    435441
     
    467473        if request.POST and request.POST.has_key("_saveasnew"):
    468474            return self.add_view(request, form_url='../../add/')
    469475
    470         ModelForm = forms.form_for_instance(obj, formfield_callback=self.formfield_for_dbfield)
     476        ModelForm = forms.form_for_instance(obj, formfield_callback=lambda f, **kwargs: self.formfield_for_dbfield(f, request, **kwargs))
    471477
    472478        inline_formsets = []
    473479        if request.POST:
     
    475481            if opts.has_field_type(models.FileField):
    476482                new_data.update(request.FILES)
    477483            form = ModelForm(new_data)
    478             for FormSet in self.get_inline_formsets():
     484            for FormSet in self.get_inline_formsets(request):
    479485                inline_formset = FormSet(obj, new_data)
    480486                inline_formsets.append(inline_formset)
    481487
     
    483489                return self.save_change(request, model, form, inline_formsets)
    484490        else:
    485491            form = ModelForm()
    486             for FormSet in self.get_inline_formsets():
     492            for FormSet in self.get_inline_formsets(request):
    487493                inline_formset = FormSet(obj)
    488494                inline_formsets.append(inline_formset)
    489495
     
    610616        ]
    611617        return render_to_response(template_list, extra_context, context_instance=template.RequestContext(request))
    612618
    613     def get_inline_formsets(self):
     619    def get_inline_formsets(self, request):
    614620        inline_formset_classes = []
    615621        for opts in self.inlines:
    616             inline = inline_formset(self.model, opts.model, formfield_callback=opts.formfield_for_dbfield, fields=opts.fields, extra=opts.extra)
     622            inline = inline_formset(self.model, opts.model, formfield_callback=lambda f, **kwargs: opts.formfield_for_dbfield(f, request, **kwargs), fields=opts.fields, extra=opts.extra)
    617623            inline_formset_classes.append(inline)
    618624        return inline_formset_classes
    619625
Back to Top