diff --git a/Yesod/Form/Fields.hs b/Yesod/Form/Fields.hs
--- a/Yesod/Form/Fields.hs
+++ b/Yesod/Form/Fields.hs
@@ -31,6 +31,15 @@
       -- * File 'AForm's
     , fileAFormReq
     , fileAFormOpt
+      -- * Options
+    , selectField'
+    , radioField'
+    , Option (..)
+    , OptionList (..)
+    , mkOptionList
+    , optionsPersist
+    , optionsPairs
+    , optionsEnum
     ) where
 
 import Yesod.Form.Types
@@ -48,7 +57,7 @@
 import Control.Monad (when, unless)
 import Data.List (intersect, nub)
 import Data.Either (rights)
-import Data.Maybe (catMaybes)
+import Data.Maybe (catMaybes, listToMaybe)
 
 import qualified Blaze.ByteString.Builder.Html.Utf8 as B
 import Blaze.ByteString.Builder (writeByteString, toLazyByteString)
@@ -59,13 +68,17 @@
 import qualified Data.ByteString.Lazy as L
 import Data.Text (Text, unpack, pack)
 import qualified Data.Text.Read
-import Control.Monad.IO.Class (liftIO)
+import Control.Monad.Trans.Class (lift)
 
 import Control.Applicative ((<$>))
 import qualified Data.Map as Map
-import Yesod.Handler (newIdent)
+import Yesod.Handler (newIdent, liftIOHandler)
 import Yesod.Request (FileInfo)
 
+import Yesod.Core (toSinglePiece, GGHandler, SinglePiece)
+import Yesod.Persist (selectList, runDB, Filter, SelectOpt, YesodPersistBackend, Key, YesodPersist, PersistEntity, PersistBackend)
+import Control.Arrow ((&&&))
+
 #if __GLASGOW_HASKELL__ >= 700
 #define WHAMLET whamlet
 #define HAMLET hamlet
@@ -290,18 +303,24 @@
     }
 
 selectField :: (Eq a, RenderMessage master FormMessage) => [(Text, a)] -> Field sub master a
-selectField = selectFieldHelper
-    (\theId name inside -> [WHAMLET|<select ##{theId} name=#{name}>^{inside}|])
-    (\_theId _name isSel -> [WHAMLET|<option value=none :isSel:selected>_{MsgSelectNone}|])
-    (\_theId _name value isSel text -> [WHAMLET|<option value=#{value} :isSel:selected>#{text}|])
+selectField = selectField' . optionsPairs
 
+selectField' :: (Eq a, RenderMessage master FormMessage) => GGHandler sub master IO (OptionList a) -> Field sub master a
+selectField' = selectFieldHelper
+    (\theId name inside -> [WHAMLET|<select ##{theId} name=#{name}>^{inside}|]) -- outside
+    (\_theId _name isSel -> [WHAMLET|<option value=none :isSel:selected>_{MsgSelectNone}|]) -- onOpt
+    (\_theId _name value isSel text -> [WHAMLET|<option value=#{value} :isSel:selected>#{text}|]) -- inside
+
 multiSelectField :: (Show a, Eq a, RenderMessage master FormMessage) => [(Text, a)] -> Field sub master [a]
 multiSelectField = multiSelectFieldHelper
     (\theId name inside -> [WHAMLET|<select ##{theId} multiple name=#{name}>^{inside}|])
     (\_theId _name value isSel text -> [WHAMLET|<option value=#{value} :isSel:selected>#{text}|])
 
 radioField :: (Eq a, RenderMessage master FormMessage) => [(Text, a)] -> Field sub master a
-radioField = selectFieldHelper
+radioField = radioField' . optionsPairs
+
+radioField' :: (Eq a, RenderMessage master FormMessage) => GGHandler sub master IO (OptionList a) -> Field sub master a
+radioField' = selectFieldHelper
     (\theId _name inside -> [WHAMLET|<div ##{theId}>^{inside}|])
     (\theId name isSel -> [WHAMLET|
 <div>
@@ -363,39 +382,76 @@
     selectParser xs | not $ null (["", "none"] `intersect` xs) = Right Nothing
                     | otherwise = (Right . Just . map snd . catMaybes . map (\y -> lookup y pairs) . nub . map fst . rights . map Data.Text.Read.decimal) xs
 
+data OptionList a = OptionList
+    { olOptions :: [Option a]
+    , olReadExternal :: Text -> Maybe a
+    }
+
+mkOptionList :: [Option a] -> OptionList a
+mkOptionList os = OptionList
+    { olOptions = os
+    , olReadExternal = flip Map.lookup $ Map.fromList $ map (optionExternalValue &&& optionInternalValue) os
+    }
+
+data Option a = Option
+    { optionDisplay :: Text
+    , optionInternalValue :: a
+    , optionExternalValue :: Text
+    }
+
+optionsPairs :: [(Text, a)] -> GGHandler sub master IO (OptionList a)
+optionsPairs = return . mkOptionList . zipWith (\external (display, internal) -> Option
+    { optionDisplay = display
+    , optionInternalValue = internal
+    , optionExternalValue = pack $ show external
+    }) [1 :: Int ..]
+
+optionsEnum :: (Show a, Enum a, Bounded a) => GGHandler sub master IO (OptionList a)
+optionsEnum = optionsPairs $ map (\x -> (pack $ show x, x)) [minBound..maxBound]
+
+optionsPersist :: ( YesodPersist master, PersistEntity a, PersistBackend (YesodPersistBackend master) (GGHandler sub master IO)
+                  , SinglePiece (Key (YesodPersistBackend master) a)
+                  )
+               => [Filter a] -> [SelectOpt a] -> (a -> Text) -> GGHandler sub master IO (OptionList (Key (YesodPersistBackend master) a, a))
+optionsPersist filts ords toDisplay = fmap mkOptionList $ do
+    pairs <- runDB $ selectList filts ords
+    return $ map (\(key, value) -> Option
+        { optionDisplay = toDisplay value
+        , optionInternalValue = (key, value)
+        , optionExternalValue = toSinglePiece key
+        }) pairs
+
 selectFieldHelper
         :: (Eq a, RenderMessage master FormMessage)
         => (Text -> Text -> GWidget sub master () -> GWidget sub master ())
         -> (Text -> Text -> Bool -> GWidget sub master ())
         -> (Text -> Text -> Text -> Bool -> Text -> GWidget sub master ())
-        -> [(Text, a)] -> Field sub master a
-selectFieldHelper outside onOpt inside opts = Field
-    { fieldParse = return . selectParser
-    , fieldView = \theId name val isReq ->
+        -> GGHandler sub master IO (OptionList a) -> Field sub master a
+selectFieldHelper outside onOpt inside opts' = Field
+    { fieldParse = \x -> do
+        opts <- opts'
+        return $ selectParser opts x
+    , fieldView = \theId name val isReq -> do
+        opts <- fmap olOptions $ lift $ liftIOHandler opts'
         outside theId name $ do
-            unless isReq $ onOpt theId name $ not $ (render val) `elem` map (pack . show . fst) pairs
-            flip mapM_ pairs $ \pair -> inside
+            unless isReq $ onOpt theId name $ not $ render opts val `elem` map optionExternalValue opts
+            flip mapM_ opts $ \opt -> inside
                 theId
                 name
-                (pack $ show $ fst pair)
-                ((render val) == pack (show $ fst pair))
-                (fst $ snd pair)
+                (optionExternalValue opt)
+                ((render opts val) == optionExternalValue opt)
+                (optionDisplay opt)
     }
   where
-    pairs = zip [1 :: Int ..] opts -- FIXME use IntMap
-    rpairs = zip (map snd opts) [1 :: Int ..]
-    render (Left _) = ""
-    render (Right a) = maybe "" (pack . show) $ lookup a rpairs
-    selectParser [] = Right Nothing
-    selectParser (s:_) = case s of
+    render _ (Left _) = ""
+    render opts (Right a) = maybe "" optionExternalValue $ listToMaybe $ filter ((== a) . optionInternalValue) opts
+    selectParser _ [] = Right Nothing
+    selectParser opts (s:_) = case s of
             "" -> Right Nothing
             "none" -> Right Nothing
-            x -> case Data.Text.Read.decimal x of
-                    Right (a, "") ->
-                        case lookup a pairs of
-                            Nothing -> Left $ SomeMessage $ MsgInvalidEntry x
-                            Just y -> Right $ Just $ snd y
-                    _ -> Left $ SomeMessage $ MsgInvalidNumber x
+            x -> case olReadExternal opts x of
+                    Nothing -> Left $ SomeMessage $ MsgInvalidEntry x
+                    Just y -> Right $ Just y
 
 fileAFormReq :: (RenderMessage master msg, RenderMessage master FormMessage) => FieldSettings msg -> AForm sub master FileInfo
 fileAFormReq fs = AForm $ \(master, langs) menvs ints -> do
@@ -429,7 +485,6 @@
 
 fileAFormOpt :: (RenderMessage master msg, RenderMessage master FormMessage) => FieldSettings msg -> AForm sub master (Maybe FileInfo)
 fileAFormOpt fs = AForm $ \(master, langs) menvs ints -> do
-    liftIO $ print menvs
     let (name, ints') =
             case fsName fs of
                 Just x -> (x, ints)
diff --git a/Yesod/Form/Functions.hs b/Yesod/Form/Functions.hs
--- a/Yesod/Form/Functions.hs
+++ b/Yesod/Form/Functions.hs
@@ -31,6 +31,7 @@
     , check
     , checkBool
     , checkM
+    , customErrorMessage
     ) where
 
 import Yesod.Form.Types
@@ -309,3 +310,8 @@
             Right Nothing -> return $ Right Nothing
             Right (Just a) -> fmap (either (Left . SomeMessage) (Right . Just)) $ f a
     }
+
+-- | Allows you to overwrite the error message on parse error.
+customErrorMessage :: SomeMessage master -> Field sub master a -> Field sub master a
+customErrorMessage msg field = field { fieldParse = \ts -> fmap (either
+(const $ Left msg) Right) $ fieldParse field ts }
diff --git a/yesod-form.cabal b/yesod-form.cabal
--- a/yesod-form.cabal
+++ b/yesod-form.cabal
@@ -1,5 +1,5 @@
 name:            yesod-form
-version:         0.3.2.1
+version:         0.3.3
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -15,6 +15,7 @@
 library
     build-depends:   base                      >= 4        && < 5
                    , yesod-core                >= 0.9      && < 0.10
+                   , yesod-persistent          >= 0.2      && < 0.3
                    , time                      >= 1.1.4    && < 1.3
                    , hamlet                    >= 0.10     && < 0.11
                    , shakespeare-css           >= 0.10     && < 0.11
