You'd have to write a custom plugin that added an event listener for the entries.saveEntry event.
Inside the event listener, you could check if the entry being saved has a true value for the featured Lightswitch field, and if so – pull all other entries with a true value for that same field (in the same section), setting their featured attribute to false before re-saving them.
Something like the below would go into your plugin's primary class:
public function init()
{
parent::init();
craft()->on('entries.saveEntry', function (Event $event) {
$entry = $event->params['entry'];
if ($entry->section->handle !== 'news' || !$entry->featured) {
return false;
}
// Get all entries from the same section with a `true` value for the Lightswitch field
$entries = craft()->elements->getCriteria(ElementType::Entry, array(
'section' => 'news',
'featured' => true,
'id' => 'not ' . $entry->id,
'limit' => null,
))->findAll();
// Update all other entries' Lightswitch field value to `false`
foreach ($entries as $entry) {
$entry->getContent()->setAttribute('featured', false);
craft()->entries->saveEntry($entry);
}
});
}
If you're new to plugin development in Craft, I'd suggest looking at the Business Logic plugin template or the pluginfactory.io app – also it'd be a good idea to read the official docs on the subject.
If you don't want to write a plugin, you could also solve this by foregoing the featured field for the entries. If you added a featuredNewsStory Entries field to a Global Set instead (and limited the Entries field to 1 entry), you'd make sure that there was only ever one featured news story in the system. The editiorial workflow would suffer, though – publishing a new, featured news story in this manner would mean that the editor would first have to create the story, then pop into the Global Set after saving the entry to actually mark it as "featured".
Anyway, here's how you could pull the featured news story from a global, as well as the other news stories that aren't featured:
{% set featuredNewsStory = yourGlobalSetHandle.featuredNewsStory.first() %}
{% set otherNewsStories = craft.entries.section('news').id(featuredNewsStory ? 'not ' ~ featuredNewsStory.id : null) %}
Of course, there is another possible "workaround" here: continue with your current solution, but add another clause; making sure that the featured news story pulled is the newest one only:
{% set featuredNewsStory = craft.entries.section('news').featured(1).order('postDate desc').limit(1).first() %}
{% set otherNewsStories = craft.entries.section('news').id(featuredNewsStory ? 'not ' ~ featuredNewsStory.id : null) %}
With the above in place, you could just communicate to your client that "if you set more than one entry to be featured, only the newest one will actually display as featured" or the like.