hyperion/models/util.py
async def get_neighbourhood(postcode_like: PostCodeLike) -> Optional[Neighbourhood]:
    """
    Gets a police neighbourhood from the database.
    Acts as a middleware between us and the API, caching results.
    :param postcode_like: The UK postcode to look up.
    :return: The Neighbourhood or None if the postcode does not exist.
    :raises CachingError: If the needed neighbourhood is not in cache, and the fetch isn't responding.

    todo save locations/links
    """
    try:
        postcode = await get_postcode(postcode_like)
    except CachingError as e:
        raise e
    else:
        if postcode is None:
            return None
        elif postcode.neighbourhood is not None:
            return postcode.neighbourhood

    try:
        data = await fetch_neighbourhood(postcode.lat, postcode.long)
    except ApiError as e:
        raise CachingError(f"Neighbourhood not in cache, and could not reach API: {e.status}")

    if data is not None:
        neighbourhood = Neighbourhood.from_dict(data)
        locations = [Location.from_dict(neighbourhood, postcode, location) for location in data["locations"]]
        links = [Link.from_dict(neighbourhood, link) for link in data["links"]]

        with Neighbourhood._meta.database.atomic():
            neighbourhood.save()
            postcode.neighbourhood = neighbourhood
            postcode.save()
            for location in locations:
                location.save()
            for link in links:
                link.save()
    else:
        neighbourhood = None
    return neighbourhood
async def get_neighbourhood(postcode_like: PostCodeLike) -> Optional[Neighbourhood]:
    """
    Gets a police neighbourhood from the database.
    Acts as a middleware between us and the API, caching results.
    :param postcode_like: The UK postcode to look up.
    :return: The Neighbourhood or None if the postcode does not exist.
    :raises CachingError: If the needed neighbourhood is not in cache, and the fetch isn't responding.

    todo save locations/links
    """
    try:
        postcode = await get_postcode(postcode_like)
    except CachingError as e:
        raise e
    else:
        if postcode is None:
            return None
        elif postcode.neighbourhood is not None:
            return postcode.neighbourhood

    try:
        data = await fetch_neighbourhood(postcode.lat, postcode.long)
    except ApiError as e:
        raise CachingError(f"Neighbourhood not in cache, and could not reach API: {e.status}")

    if data is not None:
        neighbourhood = Neighbourhood.from_dict(data)
        locations = [Location.from_dict(neighbourhood, postcode, location) for location in data["locations"]]
        links = [Link.from_dict(neighbourhood, link) for link in data["links"]]

        with Neighbourhood._meta.database.atomic():
            neighbourhood.save()
            postcode.neighbourhood = neighbourhood
            postcode.save()
            for location in locations:
                location.save()
            for link in links:
                link.save()
    else:
        neighbourhood = None
    return neighbourhood
Gets a police neighbourhood from the database.
    Acts as a middleware between us and the API, caching results.
    :param postcode_like: The UK postcode to look up.
    :return: The Neighbourhood or None if the postcode does not exist.
    :raises CachingError: If the needed neighbourhood is not in cache, and the fetch isn't responding.

    todo save locations/links