aaah you are creating your view in the model, have you not heard of MVC and separation of concerns?
That would work, but it is violating the MVC principle. Also, it looks like you are only storing the 'city' and not the country or state. What happens if in two countries they have the same city? (I can think of one off the top of my head - Moscow, Fl, USA, and Moscow, Russia). You won't know which country the person is from... I can also think of several cities in different states. "Bowling Green" is a common city name. It's a city in Florida, Indiana, Kentucky, Maryland, Missouri, Ohio, South Carolina, and Virgina (among others). My way would do it (http://www.web2pyslices.com/slice/show/1724/cascading-dropdowns-simplified) but I don't think it's ever been added to an add account mechanism before. On Monday, November 11, 2013 11:47:15 AM UTC-7, Leonel Câmara wrote: > > You are in luck, I had to do this for one of my projects. Here's a widget > I made for a project where I had the same problem but I had 3 levels, > Country->state->city > > For countries that don't have states you can use administrative regions, > but it's also trivial to adapt this to only 2 levels. > > *MODELS* > > db.define_table('country', > Field('name', length=128, requires=IS_NOT_EMPTY(), notnull=True, > unique=True), > Field('acronym', length=2, requires=IS_NOT_EMPTY()), > format='%(name)s') > db.define_table('state', > Field('name', length=128, requires=IS_NOT_EMPTY(), notnull=True), > Field('acronym', 'string', requires=IS_NOT_EMPTY()), > Field('country','reference country', requires=IS_IN_DB(db, db.country.id, > '%(name)s'), represent=lambda x, row: db.country[x].name), > format='%(name)s') > db.define_table('city', > Field('name', length=128, requires=IS_NOT_EMPTY(), notnull=True), > Field('state', 'reference state', requires=IS_IN_DB(db, db.state.id, > '%(name)s'), represent=lambda x, row: db.state[x].name), > format='%(name)s') > auth.settings.extra_fields['auth_user']= [ > Field('city','reference city', label=T('City'), requires=IS_IN_DB(db, > db.city.id, '%(name)s'))] > > class LOCATION_SELECTS(DIV): > """ A helper that essentially creates a div with the 3 selects used to > choose a location """ > > def __init__(self, *args, **attributes): > if '_id' not in attributes: > import random > attributes['_id'] = 'ls' + str(random.random())[2:] > > def mk_sel_select(entities, selected, name): > s = SELECT(_name=name) > s.append(OPTION(T('Pick a %s' % name), _value=0)) > for entity in entities: > if entity.id == selected: > s.append(OPTION(entity.name, _value=entity.id, > _selected='selected')) > else: > s.append(OPTION(entity.name, _value=entity.id)) > return s > > DIV.__init__(self, *args, **attributes) > countries = db(db.country.id > 0).select(orderby=db.country.name) > > if 'initial_city' in attributes: > sel_city = attributes['initial_city'] > rec_city = db.city[sel_city] > sel_state = rec_city.state > sel_country = rec_city.state.country > states = db(db.state.country == > sel_country).select(orderby=db.state.name) > cities = db(db.city.state == > sel_state).select(orderby=db.city.name) > > self.components.append(mk_sel_select(countries, sel_country, > 'country')) > self.components.append(mk_sel_select(states, sel_state, 'state')) > self.components.append(mk_sel_select(cities, sel_city, 'city')) > else: > self.components.append(SELECT(OPTION(T('Pick a country'), > _value=0), *[OPTION(country.name,_value=country.id) for country in > countries], _name='country')) > self.components.append(SELECT(OPTION(T('Pick a region'), > _value=0), _name='state', _disabled='true')) > self.components.append(SELECT(OPTION(T('Pick a city'), _value=0), > _name='city', _disabled='true')) > > def xml(self): > return (DIV.xml(self) + > SCRIPT("""$(document).ready( function() { > var country_sel = $('#%(sid)s select[name="country"]'); > var state_sel = $('#%(sid)s select[name="state"]'); > var city_sel = $('#%(sid)s select[name="city"]'); var > state_cache = new Object(); var city_cache = new > Object(); > var state_func = function(data) { > state_sel.children('option:gt(0)').remove(); > $.each(data.states, function(key, val) { > state_sel.append('<option value="' + > data.states[key].id + '">' + data.states[key].name + '</option>'); > }); > state_sel.removeAttr('disabled'); > } > var city_func = function(data) { > city_sel.children('option:gt(0)').remove(); > $.each(data.cities, function(key, val) { > city_sel.append('<option value="' + data.cities[key].id > + '">' + data.cities[key].name + '</option>'); }); > city_sel.removeAttr('disabled'); > } > country_sel.change(function () { > var val = country_sel.val(); if (val === > '0') { > state_sel.children('option:gt(0)').remove() > state_sel.attr('disabled', ''); > city_sel.children('option:gt(0)').remove(); > city_sel.attr('disabled', ''); return; > } > city_sel.children('option:gt(0)').remove(); > city_sel.attr('disabled', ''); > if (val in state_cache) { > state_func(state_cache[val]); } else { > $.getJSON('%(getstates)s' + '/' + encodeURIComponent(val), > function(data) { state_cache[val] = data; > state_func(data); > }); } }); > state_sel.change(function () { > var val = state_sel.val(); if (val === '0') { > city_sel.children('option:gt(0)').remove(); > city_sel.attr('disabled', ''); > return; } if > (val in city_cache) { > city_func(city_cache[val]); } else { > $.getJSON('%(getcities)s' + '/' + encodeURIComponent(val), > function(data) { city_cache[val] = > data; city_func(data); > }); } }); > }); """ % {'sid':self['_id'], > 'getstates':URL('default', 'get_states.json'), 'getcities':URL('default', > 'get_cities.json')} ).xml()) > > def city_widget(field, value): > """ A widget for city fields that makes you put the country and state too > """ > try: > value = int(value) > if value <= 0: > raise ValueError() > widget = LOCATION_SELECTS(initial_city=value) > except (ValueError, TypeError) as e: > widget = LOCATION_SELECTS() > > widget.components[-1]['requires'] = field.requires > return widget > db.auth_user.city.widget = city_widget > > > *CONTROLLERS (default.py)* > > def get_states(): > """ Get the states for a given country id, these might be districts > or whatever makes sense for the country in question. """ > session.forget() > result = db(db.state.country == request.args(0)).select(db.state.id, > db.state.name, orderby=db.state.name).as_list() > return {'states': result} > > def get_cities(): > """ Get the cities for a given state id. """ > session.forget() > result = db(db.city.state == request.args(0)).select(db.city.id, > db.city.name, orderby=db.city.name).as_list() > return {'cities': result} > > > > Make sure you allow generic.json for the 2 controllers. And it is done. > > -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/groups/opt_out.

