Your code can be simplified as follows:
This is incorrect:
form.vars.user.writable = False
I assume you mean:
db.services.user.writable = False
It is not a good idea to define a form in a if block, i.e. in a
different scope than the the form.accepts. Try this instead:
@auth.requires_login()
def services():
record = db.services(user=auth.user.id) # returns None if record
not found
db.services.user.writable = False
db.services.user.default = auth.user.id
form = SQLFORM(db.services, record, deletable=False) # update or
create depending on record
if form.accepts(request.vars, session):
response.flash = 'form accepted'
elif form.errors:
response.flash = 'form has errors'
return dict(form=form)
On Aug 22, 3:48 pm, Niphlod <[email protected]> wrote:
> usually I'll do something like that:
>
> 1. @auth.requires_login()
> 2. def services():
> 3. record = db(db.services.user==auth.user.id).select().first()
> 4. if record:
> 5. form = SQLFORM(db.services, record, deletable=False)
> 6. form.vars.user.writable = False
> 7. else:
> 8. form = SQLFORM(db.services)
> 9. form.vars.user.default = auth.user.id
> 10. form.vars.user.writable = False
> 11. if form.accepts(request.vars, session):
> 12. response.flash = 'form accepted'
> 13. elif form.errors:
> 14. response.flash = 'form has errors'
> 15. return dict(form=form)
>
> changes made to your implementation:
> a) request.args are needed to catch something "after" something/
> default/services ... that line is copy/pasted from the book but in
> your context it doesn't mean anything...actually the URL with that is
> needed to be like something/default/services/xxx where xxx is an
> identifier of the record to edit. Since you want only one record per
> user, request.args use is meaningless.
>
> so, "if len(request.args)" is missing totally.
>
> b) if there's only one record per user, you can select directly the
> row with .first() , no need to retain the set (multiple rows object)
> if there aren't going to be multiple records per user.
> .first() return a row or None if non-existent, hence the "if record:"
> on line 4.
>
> c) if record exists, form will be "editable" of the row "record" (with
> records[1] you were doing quite a mess....actually selecting the 2nd
> row of your set, python enumeration starts from [0], not from
> [1]!!) .
> on line 6. and 10. "form.vars.user.writable = False" give yourself
> some protection .... actually if you don't do this you'll end up
> giving away the chance to your users to change the "user" field,
> "assigning" his "services" row to another user.... definitely not the
> way to go. I'll be happy to set also form.vars.user.readable = False
> to hide the field at all, but that's your choice.
>
> Feel free to ask more if you're concerned by something or if you
> didn't understand all.
>
> Niphlod