Sourcing data format from multiple different structures
Don't abuse inner lists

This:

self.name = ' '.join([data.get('name').get(key) for key in ['first_name', 'last_name']])


should be

self.name = ' '.join(data.get('name', {}}.get(key) for key in ('first_name', 'last_name'))


Note the following:


Generators don't need to go in a list if they're just being passed to a function (join) that needs an iterable
Give an empty dictionary as the default for the first get so that the second get doesn't explode
Use a tuple instead of the last list because the data are immutable


Use set logic

This:

return all(key in data for key in ('name', 'workEmail'))


is effectively asking "are both 'name' and 'workEmail' in data?" There's a better way to ask this - with a set.

needed = {'name', 'workEmail'}
return needed.issubset(set(data))


If data can be stored as a set once outside of this function, it will increase efficiency.

Read more here: https://docs.python.org/3/tutorial/datastructures.html#sets

Don't needlessly materialize generators

This:

# Instantiate Person from data
persons = [Person(data) for data in [dict_a, dict_b]]

# Store persons that fit the database model
persons = [PersonModel(**person.__dict__) for person in persons]


makes a generator, saves it to a list in memory, consumes that list, makes a second generator, and stores that generator in a second list in memory. Instead:

persons = [PersonModel(**Person(data).__dict__)
           for data in (dict_a, dict_b)]


Again, the last inner list should be a tuple.

Parsing heuristics

It's not useful to write separate parsing classes for formats A and B in this case, because they aren't declared by the API so have no meaning. Write a translation routine for every member you extract from the JSON. Do a series of attempts against known paths in the data to get the members out.