Hi Amirouche,
Good questions, let me try answer:
On 30/01/2017 17:58, Amirouche Boubekki wrote:
> a) I am not sure what's the purpose of defining validation fields in the
> model. Isn't validation orthogonal to model representation? For
> instance, how do you define multiple validation scheme for a single model?
We think of Fields as metadata about the model - what you'd call its
.name if you were a human; what security restrictions apply etc.
ValidationConstraints are also added to Fields: the fact that, say, an
Investment's .amount should be an Integer > 0, is metadata, and is a
constraint that should always hold. It is part of the domain.
In many circumstances it also makes sense to say that a certain Field is
also required data for its domain object to be complete. Like an
Investment that does not make sense without an .amount.
However, some ValidationConstraints may be different depending on the
context where they are used. This is sometimes true of whether or not
something is required or not.
For this case, we have special methods on Fields that you can use to get
copies of them, with just certain things modified. For example:
Field.as_required()
http://www.reahl.org/docs/3.2/component/modelinterface.d.html#reahl.component.modelinterface.Field.as_required
Field.as_optional()
http://www.reahl.org/docs/3.2/component/modelinterface.d.html#reahl.component.modelinterface.Field.as_optional
or the more general versions:
Field.as_with_validation_constraint
http://www.reahl.org/docs/3.2/component/modelinterface.d.html#reahl.component.modelinterface.Field.as_with_validation_constraint
Field.as_without_validation_constraint
http://www.reahl.org/docs/3.2/component/modelinterface.d.html#reahl.component.modelinterface.Field.as_without_validation_constraint
That said, you do not HAVE to always put these on actual domain objects.
They just have to be on objects of some sort. You can even put them on a
Widget like a Form for something if you'd like. We sometimes create a
class that acts more like an interface to the domain where it makes
sense like here:
http://www.reahl.org/docs/3.2/domain/systemaccountmodel.d.html#accountmanagementinterface
> b) There is magic at play here through @exposed decorator. That's a
> pattern I've never seen before, no problem with that but I was said
> using the @property decorator for hiding runtime operation is only
> "maintenance" trick to avoid big refactoring. Is the use of a pseudo
> @property legit?
All @properties are basically "derived attributes" of an object.
Meaning, the object does not have an instance attribute holding onto the
result of the property, it needs to execute a method to compute it on
the fly. This is no different. It has no side-effects and should do
nothing other than to compute the .fields of the object in question. I
can't see a problem with that ;-)
> c) Can someone use "self" to define the fields? For what purpose? I
> don't understand the purpose of self in fields method.
Well, it is a method, so has to have a self argument. BUT, yes, you
absolutely do need it in some cases. For example, perhaps you want to be
able to compute whether the currently logged-in user has access to the
specific object instance the field is bound to. How would you do that
without having access to the actual instance?
Our involved security example can be referenced for this, here are such
fields:
def fields(self, fields):
fields.name = Field(label='Name',
required=self.can_be_added(),
writable=Action(self.can_be_added))
fields.email_address = EmailField(label='Email',
required=True,
writable=Action(self.can_be_edited))
(For the full example, see:
http://www.reahl.org/docs/3.2/tutorial/accesscontrolinc3.d.html )
> d) I don't see the point in using this representation instead of the
> declarative ORM-like pattern used in Django and others form validation
> libraries. Why this choice of API?
Good question! The trouble is that we want to use our Fields AND and ORM
together. If something like SqlAlchemy declares things like .name and
.email_address in the namespace of the class (as in the precise example
you cite), then we cannot do the same trick for Reahl Fields as well.
The names are already in use by SqlAlchemy declarative.
So, we have to find an approach that does not clash with that.
We do have an alternative in the code (not documented) that can be used
something like this:
https://github.com/reahl/reahl/blob/master/reahl-component/reahl/component_dev/test_field.py#L246
There are some problems with that approach though, which is why we are
not advocating it: often, to define a Field, you need access to the
instance (the self of the previous question), and this class-level
approach does not allow for that.
>
> In the following chapter the events method is presented in “Buttons
> allow users to act” the first “Augmenting a model with Events”
> <
http://www.reahl.org/docs/3.2/tutorial/buttonwidgets.d.html>, the
> following snippet appears:
>
> |
>
> classAddress(Base):
> __tablename__='addressbook2_address'
>
> id =Column(Integer,primary_key=True)
> email_address=Column(UnicodeText)
> name =Column(UnicodeText)
>
> @exposed
> deffields(self,fields):
>
fields.name=Field(label='Name',required=True)
> fields.email_address=EmailField(label='Email',required=True)
>
> defsave(self):
> Session.add(self)
>
> * @exposed
> defevents(self,events):*
> *events.save=Event(label='Save',action=Action(self.save))*
>
> |
>
> Again the same @exposed decorator is used to declare what seems to be
> onclick event handlers which seems to be kind of analogous to Django
> views or Controller in MVC pattern.
>
> e) What's the purpose of Event
> <
http://www.reahl.org/docs/3.2/component/modelinterface.d.html?highlight=event#reahl.component.modelinterface.Event>?
> What's the purpose of Action
> <
http://www.reahl.org/docs/3.2/component/modelinterface.d.html?highlight=action#reahl.component.modelinterface.Action>?
An Event is a logical thing that may happen, in response to which the
domain should possibly change.
An Action is some code that can be executed. Actions contain the
necessary code to map incoming data to parameters for method calls, etc.
When you create a button, you specify which Event it triggers when the
user clicks on the Button.
We like to visualise the user interface on a coarse-grained level as
"places" where a user can be. People naturally talk of being in a
certain place in a web app, and about how they can move from one place
to another. You can model these places and how a user gets from one
place to another with something like a state diagram
(
http://www.agilemodeling.com/artifacts/stateMachineDiagram.htm )
The terminology of Events and Actions are derived from state diagram
theory. Here is how we use in from Reahl's point of view:
http://www.reahl.org/docs/3.2/tutorial/connectingviews.d.html
So, if an Event is triggered by a user on a specific screen (aka View),
it will first execute the Action attached to it, and then take the user
to another, possibly different View as defined by transitions.
>
> f) It break the law of separation of concerns, doesn't it?
No. By declaring an Event on a domain object, you define a signal that
can be triggered by a user.
If you follow the state diagram approach, each state is a View, and
traditional controller concerns are captured by the state diagram
itself, especially the edges (transitions).
But, the concerns are specifically: what a View looks like vs how you
control transitioning a user between different Views in response to Events.
You do NOT put stuff in an Action that controls the user interface at all.
> g) How is used label?
Again, it is metadata about the Event. We happen to use it as the text
inside the Button to which that Event is attached. But where you declare
the label on the Event you are just saying that "humans may call this
Event X"
>
> I understand that events handlers are bound to models, is it the only
> way to go:
>
> h) what happens if instead of executing some processing on a model I
> want to reach rabbitmq or redis?
Then you write a model which acts as an interface in front of redis or
rabbitmg, with methods that proxy to these services.
> i) what happens if I want to ping redis, update one or several models?
> Where should the code go?
I think you should perhaps provide a concrete example here because the
answer (as it often is with design stuff) will depend. But generically:
then you build a model that reflects the face that you want to update
several other models, use a facade pattern or some such. With a more
concrete example I'd be able to give a better answer.
>
> Then the event is referenced in the template/rendering code as follow:
>
> |
>
> classAddAddressForm(Form):
> def__init__(self,view):
> super(AddAddressForm,self).__init__(view,'add_form')
>
> new_address=Address()
>
> grouped_inputs=self.add_child(FieldSet(view,legend_text='Add an
> address'))
>
> grouped_inputs.add_child(LabelledBlockInput(TextInput(self,
new_address.fields.name)))
>
> grouped_inputs.add_child(LabelledBlockInput(TextInput(self,new_address.fields.email_address)))
>
> self.define_event_handler(new_address.events.save)
> grouped_inputs.add_child(Button(self,*new_address.events.save*))
>
> |
>
> j) How do you declare a event handler that is not bound to a model (cf.
> previous question)?
Once again, you don't, but you can decide what you want to "model". It
need not be an address - it can be an XYZInterface, for example.
> k) What mechanism does reahl use to forward the button click event done
> browser side to Python side? In general how communication between
> frontend and backend happens?
It does a POST.
In general, if you click on a button, it POSTs to the Form, executed the
Action attached to that Event and then responds with a redirect (HTTP
302) to the next page (View) where you want the user to end up on.
If there are any exceptions (such as validation exceptions) as a result
of the POST, the database is rolled back, and the user is redirected to
the same View where the button was clicked - but now with validation
errors displayed.
The stuff we do with Ajax can be different, and depends on the context.
There may also be GETs in that case.
> l) It seems to me browser events are kind of "fire-and-forget" style. Is
> it possible to have RPC mechanism where clicking on button triggers a
> method call server side which answers or triggers the desired side
> effect frontend in the UI?
Yes. We have something called a RemoteMethod
(
http://www.reahl.org/docs/3.2/web/fw.d.html?highlight=define_transition#remotemethod
) which you can use to define something that can be triggered via an
URL. Exactly what it sends back is also configurable. In fact the basic
POST alluded to above is implemented using this mechanism.
>
> Other questions:
>
> m) Is it possible to implement a REST service using Reahl?
That is not our focus, but it is possible using a RemoteMethod.
> n) regarding widgets
> <
http://www.reahl.org/docs/3.2/tutorial/ownwidget.d.html?highlight=widget>,
> is it possible to bundle a widget with some routes?
No, that would not make sense. A View is a page / place on your app and
is uniquely identified by URL. Widgets are reusable chunks of UI that
you can compose particular Views with. If a Widget was linked to a URL,
you could not re-use it to compose different Views.
A UserInterface can also have an URL.
> o) again widgets, is it possible to point a widget to re-use a REST
> interface or events handler?
Yes, again using a RemoteMethod.
>
> p) I did read something about client side validation of forms but I
> can't find it.
Probably here:
http://www.reahl.org/docs/3.2/features/validation.d.html
You don't have to do anything special to make this happen. If you use
Fields, their ValidationConstraints will be checked client side and
server side automatically. We think that is quite cool - because you
just say logically how things should be validated, and then it happens
client side with no effort from your end.
>
> Last but not least, last question is it possible to push things to the
> frontend through websocket or long polling?
Not yet I'm sorry. There are still a few other use cases we'd like to
build good abstractions for before we deal with that sort of thing. But
I am sure we will make use of such mechanisms at some point.
I have to run now, will answer your other email a bit later tonight!
Regards
- Iwan
--
Reahl, the Python only web framework /
www.reahl.org