You could automate writing a recursive ntoh method for your struct with a macro or similar, but unless you have a lot of such structs (or a lot of struct fields), it’s probably easier to just write ntoh methods by hand:
Base.ntoh(x::Q) = Q(ntoh(x.a), ntoh(x.b))
Base.ntoh(x::P) = P(ntoh(x.a), ntoh(x.b), ntoh(x.c), ntoh(x.d))
Then just do ntoh.(reinterpret(P, bytes)).
To define both ntoh and hton, you can use a simpler metaprogramming trick:
for f in (:ntoh, :hton)
@eval Base.$f(x::Q) = Q($f(x.a), $f(x.b))
@eval Base.$f(x::P) = P($f(x.a), $f(x.b), $f(x.c), $f(x.d))
end