untested, but it should work theoretically:
add_filter('get_attached_file', function($path, $file, $attachment_id){
// get the post object of the current attachment
$att = get_post($attachment_id);
// prepend attachment post parent ID to the file name
return substr_replace($path, "{$att->post_parent}/{$file}", -strlen($file));
});
Another filter, attempts to “fix” the path returned by WP’s upload handler:
add_filter('wp_handle_upload', function($results){
global $post;
if(empty($post))
return $results;
extract($results);
$uploads = wp_upload_dir();
$file = str_replace($uploads['basedir'], "{$uploads['basedir']}/{$post->ID}", $file);
$url = str_replace($uploads['baseurl'], "{$uploads['baseurl']}/{$post->ID}", $url);
return compact('file', 'url', 'type');
});
This will not work if the media uploader doesn’t expose the current post inside the global $post variable.