Re: SQLFORM create / edit / delete help (I feel like I've hit a wall)

97 views
Skip to first unread message

Anthony

unread,
Apr 16, 2013, 11:12:05 AM4/16/13
to
This is a lot to process -- next time maybe try to pare things down to the essentials (more likely someone will take the time to review it).

First, do you want the user_id field to be restricted to the id of the current logged in user? If so, then don't put the value in a hidden field on the client -- that can be hacked unless you validate on the server. Instead, just set a default value in the model and don't make the field writable:

Field('user_id', 'reference auth_user', default=auth.user_id, readable=False, writable=False)

Also, note that if it is a reference to another table, it should be a reference field, not an integer field.

Regarding the complete address field, you can instead handle that on the server side with either a computed field (which gets stored in the database) or a virtual field (which is generated after pulling data from the database). For a computed field (which is essentially what you are now doing on the client):

Field('complete_address', 'string',
      compute=lambda r: '%(address)s %(city)s %(location_state)s %(zipcode)s' % r)

A few other tips:

Instead of session.auth.user.id, you can just do auth.user.id. Also, although it doesn't matter here, auth.user_id is often preferable because when there is no logged in user, it simply returns None, whereas auth.user.id will generate an error in that case (because auth.user will be None and therefore have no "id" attribute).

Finally, in Python, to increment a counter, you can do count1 += 1 instead of count1 = count1 + 1.

Anthony


On Tuesday, April 16, 2013 6:40:04 AM UTC-4, Trevor Overman wrote:

I've google'd all over the place, but I can't seem to find a solid answer to the problems that I'm having.

I'm trying to create a "Saved Locations" area on my website where a user can submit, and then edit or delete a location.

Model

#user-profile-locations
db
.define_table('user_locations',
   
Field('user_id', 'integer', requires=IS_NOT_EMPTY()),
   
Field('address', 'string', requires=IS_NOT_EMPTY()),
   
Field('city', 'string', requires=IS_NOT_EMPTY()),
   
Field('location_state', 'string', requires=IS_NOT_EMPTY()),
   
Field('zipcode', 'string', requires=IS_NOT_EMPTY()),
   
Field('phone_number', 'string', requires=IS_NOT_EMPTY()),
   
Field('complete_address', 'string', requires=IS_NOT_EMPTY()),
   
Field('special_instructions', 'string'),
   
Field('description', 'string', requires=IS_NOT_EMPTY()))



Controller

 form_newlocation = SQLFORM(db.user_locations)

**I know this is completely wrong, I'm looking on some advice on where to go from here.

View

<h1><a id="locations-expand">Saved Locations<b class="caret" id="user-caret" style=""></b><i class="icon-map-marker" style="margin-top:22px;margin-left:20px;"></i></a></h1><hr>

<table style="margin-left:15px;" id = "locations-form">
{{count1 = 0}}
{{count2 = 0}}
{{count3 = -1}}

{{for address in address_array:}}
   
    {{count1 = count1 + 1}}
    {{for description in description_array:}}
       
        {{count2 = count2 + 1}}
        {{count3 = count3 + 1}}
        {{if count1 == count2:}}
                       
       
<tr>

           
<td style="width:340px"><h4><a href="mylocations">{{=address}}</a></h4></td>
           
<td style="width:200px"><p class="lead" style="font-size:12pt;">{{=description}}</p></td>
           
           
<td><a id ="edit-{{=count2}}"><i class="icon-edit" title="Edit" style="margin-top:5px"></i></a></td>
           
<td><a id="delete-{{=count2}}"><i class="icon-remove" title="Delete" style="margin-top:5px"></i></a></td>
           
       
</tr>
       
<tr>
           
           
<td>
           
               
<div id="edit-form-{{=count2}}" style="display:none;">
                                                                                       
               
<form enctype="multipart/form-data" action="" method="post">
               
<table>
                   
<tr id="address__row">
                       
<td><input type="text" class="string" name="address" value="{{=locations_array[0][count3]}}" placeholder="Address" id="address" /></td>
                       
<td></td>
                   
</tr>
                   
<tr id="city__row">
                       
<td><input type="text" class="string" name="city" value="{{=locations_array[1][count3]}}" placeholder="City" id="city" /></td>
                       
<td></td>
                   
</tr>
                   
<tr id="location_state__row">
                       
<td><input type="text" class="string" name="location_state" value="{{=locations_array[2][count3]}}" placeholder="State" id="location_state" /></td>
                       
<td></td>
                   
</tr>
                   
<tr id="zipcode__row">
                       
<td><input type="text" class="string" name="zipcode" value="{{=locations_array[3][count3]}}" placeholder="Zipcode" id="zipcode" /></td>
                       
<td></td>
                   
</tr>
                   
<tr id="phone_number__row">
                       
<td><input type="text" class="string" name="phone_number" value="{{=locations_array[4][count3]}}" placeholder="Phone Number" id="phone_number" /></td>
                       
<td></td>
                   
</tr>
                   
<tr id="special_instructions__row">
                       
<td><textarea type="text" class="string" name="special_instructions" placeholder="Special Instructions" id="special_instructions" >{{=locations_array[5][count3]}}</textarea></td>
                       
<td></td>
                   
</tr>
                   
<tr id="description__row">
                       
<td><textarea type="text" class="string" name="description" placeholder="Description" id="description" >{{=locations_array[6][count3]}}</textarea></td>
                       
<td></td>
                   
</tr>
                   
                   
<tr id="submit_record__row">
                       
<td><input value="Edit Location" type="submit" id="submit"></td>
                       
<td></td>
                   
</tr>
               
</table>

                   
<input value="user_locations-edit-{{=count2}}" type="hidden" name="_formname" />
                   
<input value="" type="hidden" id="complete_address" name="complete_address" />
                   
<input value="{{=session.auth.user.id}}" type="hidden" name="user_id" />
                   
<input value="{{=locations_array[8][count3]}}" type="hidden" name="id" />

               
</form>
                                 
               
</div>
           
           
</td>
           
       
</tr>
       
<tr>
       
           
<td>
               
               
<div id="delete-form-{{=count2}}" style="display:none;">
                           
               
<form enctype="multipart/form-data" action="" method="post">
               
<table>
                   
<tr id="description__row">
                       
<td><span class="muted">Are you sure you want to delete this location?<input type="checkbox" class="" name="checkbox" value="" placeholder="" id="checkbox" /></span></td>
                       
<td></td>
                   
</tr>
                   
                   
<tr id="submit_record__row">
                       
<td><input value="Delete" type="submit" id="submit"></td>
                       
<td></td>
                   
</tr>
               
</table>

                   
<input value="user_locations-delete-{{=count2}}" type="hidden" name="_formname" />
                   
<input value="{{=session.auth.user.id}}" type="hidden" name="user_id" />
                   
<input value="{{=locations_array[8][count3]}}" type="hidden" name="location_id" />

               
</form>            
           
</div>
               
           
</td>
       
       
</tr>
       
       
<tr>
       
<script>
           

           
            $
("#edit-form-{{=count2}}").show("slow");
            $
("#edit-form-{{=count2}}").hide();
            $
("#edit-{{=count2}}").click(function () {
            $
("#edit-form-{{=count2}}").slideToggle();
            $
("#delete-form-{{=count2}}").hide();});
       
            $
("#delete-form-{{=count2}}").show("slow");
            $
("#delete-form-{{=count2}}").hide();
            $
("#delete-{{=count2}}").click(function () {
            $
("#delete-form-{{=count2}}").slideToggle();
            $
("#edit-form-{{=count2}}").hide();});
       
           
</script>
       
       
</tr>
       
        {{pass}}

    {{pass}}
    {{count2 = 0}}
    {{count3 = -1}}

   
{{pass}}
   
   
</table>
   
<div id="newlocation" style="margin-left:25px;margin-top:10px;"><a>+New Location</a></div>
   
<div id="newlocation-form" style="display:none;margin-left:35px">
     
        {{=form_newlocation}}  
       
   
</div>

<br>
<script>  
                               
       
        $
("#submit").click(function () {
           
           
var address = $('#address').val();
           
var city = $('#city').val();
               
var state = $('#location_state').val();
               
var zipcode = $('#zipcode').val()  ;
               
var complete_address = address + " " + city + " " +  state + " " + zipcode;
               
               $
('#complete_address').val(complete_address);    

               
       
});
       
       
        $
("#newlocation-form").show("slow");
        $
("#newlocation-form").hide();
        $
("#newlocation").click(function () {
        $
("#newlocation-form").slideToggle();});
       
        $
("#locations-form").show("slow");
        $
("#locations-expand").click(function () {
        $
("#locations-form").slideToggle();});
       
</script>

**this view is currently in a very hacktastic form..

anyway, I'm trying to have the "user_id" and "complete_address" fields hidden, while making the complete_address a concatenation of the address, city, state, and zip fields  when the submit button is clicked. Then, I'm wanting to build the delete and edit functions. I've attached some some current pictures to give you a better idea.



Any sort of help with any of this would be greatly appreciated!

-Trevor

Jim S

unread,
Apr 16, 2013, 9:27:55 AM4/16/13
to web...@googlegroups.com
I may be oversimplifying or misunderstanding the issue, but if you just want simple CRUD, have you considered using SQLFORM.grid?

-Jim

Trevor Overman

unread,
Apr 16, 2013, 4:38:30 PM4/16/13
to


On Tuesday, April 16, 2013 7:47:25 AM UTC-4, Anthony wrote:
This is a lot to process -- next time maybe try to pare things down to the essentials (more likely someone will take the time to review it).

I agree, thanks for helping out though! I really appreciate it.

First, do you want the user_id field to be restricted to the id of the current logged in user? If so, then don't put the value in a hidden field on the client -- that can be hacked unless you validate on the server. Instead, just set a default value in the model and don't make the field writable:

Field('user_id', 'reference auth_user', default=auth.user_id, readable=False, writable=False)

Also, note that if it is a reference to another table, it should be a reference field, not an integer field.

Yes this is exactly what I was wanting. I did realize the security issue but couldn't figure out how to do it server side.
 
Regarding the complete address field, you can instead handle that on the server side with either a computed field (which gets stored in the database) or a virtual field (which is generated after pulling data from the database). For a computed field (which is essentially what you are now doing on the client):

Field('complete_address', 'string',
      compute=lambda r: '%(address)s %(city)s %(location_state)s %(zipcode)s' % r)


Thank you for this as well; exactly what I needed.
 
A few other tips:

Instead of session.auth.user.id, you can just do auth.user.id. Also, although it doesn't matter here, auth.user_id is often preferable because when there is no logged in user, it simply returns None, whereas auth.user.id will generate an error in that case (because auth.user will be None and therefore have no "id" attribute).

Finally, in Python, to increment a counter, you can do count1 += 1 instead of count1 = count1 + 1.

Anthony



I think I've gotten the model down now correctly. Would you have any advice with the controller and views ? I know the way I'm doing it now with a nested for loop and counter probably isn't the best way. Maybe there is a much better way to do this instead of defining the edit and delete form in the view?

Anyway, If I understand correctly, to create an edit form you simply pass a record to the sqlform "SQLFORM(db, record)"

Sorry if these sound like relatively simple "book oriented" questions. I just feel as though I've read the same sentences over and over and there might be something I'm missing.

Once again, thanks for your help.

-Trevor

Trevor Overman

unread,
Apr 16, 2013, 4:09:01 PM4/16/13
to
I looked at SQLFORM.grid, but to me it seemed limited to styling options. I may be completely wrong and just not know how to do it correctly.

黄祥

unread,
Apr 17, 2013, 7:21:11 AM4/17/13
to web...@googlegroups.com

Field('complete_address', 'string',
      compute=lambda r: '%(address)s %(city)s %(location_state)s %(zipcode)s' % r)


for complete_address, in terms of performance or efficiency, what is the difference between store it in table field or just format it in view side?

best regards

Anthony

unread,
Apr 17, 2013, 8:53:53 AM4/17/13
to web...@googlegroups.com
I think I've gotten the model down now correctly. Would you have any advice with the controller and views ? I know the way I'm doing it now with a nested for loop and counter probably isn't the best way. Maybe there is a much better way to do this instead of defining the edit and delete form in the view?

Not sure -- haven't studied the view code in detail to figure what you're trying to do, and you haven't shown the full controller code. In general, if you just want to be able to show a list of all records in a given table and allow creating and updating of records, either Crud or SQLFORM.grid are the way to go.
 

Anyway, If I understand correctly, to create an edit form you simply pass a record to the sqlform "SQLFORM(db, record)"

Yes.

Anthony

Anthony

unread,
Apr 17, 2013, 8:56:49 AM4/17/13
to web...@googlegroups.com
On Tuesday, April 16, 2013 4:07:53 PM UTC-4, Trevor Overman wrote:
I looked at SQLFORM.grid, but to me it seemed limited to styling options. I may be completely wrong and just not know how to do it correctly.

If you can't achieve what you want with the standard arguments to the grid method, you can manipulate the structure of the produced grid via the server-side DOM, and you can style it via custom CSS.

Anthony

Jim Steil

unread,
Apr 17, 2013, 9:19:25 AM4/17/13
to web...@googlegroups.com

You can use custom forms with .grid also. No limitations there.

Jim

--
 
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/FZ3BwheICUo/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
Reply all
Reply to author
Forward
0 new messages