Does anybody know how to automatically update the options of a "child" select box depending on the choice of the "parent" select box in the admin page?
The problem: I have two select boxes. In the first one I choose e.g. a car brand. Once I choose the car brand I want the "child" select box options to update with the models of that brand.
I am using ForeignKey properly in my models and all the models are correct but if you can give me some guidance to solve this issue I would be grateful. Thanks!
Solved: I've used smart_selects. https://github.com/digi604/django-smart-selects
You can do this with JavaScript and Elementmanipulation:
save the car-models to JavaScript Vars: ie
<script type="text/javascript">
var porsche = {{ porsche|safe }};
var vw = {{ vw|safe }};
</script>
And in you JavaScript you can specify a new Change Method for your Parent select box:
$('#parent_select').change(function(){
changeCars();
});
The function could then manipulate the child select box:
var newCarList = [];
val =$('#parent_select').val();
if (val=='porsche'){
newCarList = porsche;
}
else if (val == 'vw'){
newCarList = vw;
}
else{
//some Error handling
}
select = document.getElementById('child_select');
while (select.firstChild) {
select.removeChild(select.firstChild);
// to remove all previously added childs (option fields)
}
for (var i = 0; i < newCarList.length; i ++){
var opt = document.createElement('option');
opt.value = newCarList[i];
opt.innerHTML = newCarList[i];
select.appendChild(opt);
//append all new Childs to the child_select
}
This possibility will work but is quite slow since Object manipulation is not the fastest way.
Another possibility would be to create different child selects and use show/hide to only display the correct one according to the value of the parent_select.
I have solved my problem. I used Django smart_selects. github.com/digi604/django-smart-selects
Related
I have been moving website made in Cakephp into Django. In one place I found get_declared_classes(). I thinks this function returns list of previously used classes before running current class.
First time when I encounter this, I just store list of classes manually in one file and I was using that and this solution worked only for a particular web page but Now I have multiple pages calling this class and everytime list of classnames are very different so I can not store class name list.
This code is actually connecting and fetching data from here and I want to replace this class in python(We are replacing whole website). The only problem I have is how to replace get_declared_classes.
class HrbcConnect{
private $scope = '';
private $token = null;
private $token_expire = 0;
private $request_opt = array();
public $id;
public $id_arr = array();
public $write_error;
public function read($resource,$condition='',$field=array(),$order=null){
$declared_classes = get_declared_classes();
foreach(App::objects('Model') as $v){
if(in_array($v,$declared_classes)){
$instance = new $v;
if(property_exists($instance,'hrbc_cols') && array_key_exists(ucfirst($resource),$instance->hrbc_cols)){
foreach($instance->hrbc_cols[ucfirst($resource)] as $vv){
if(is_array($vv)){
$field[] = $vv[0];
}else{
$field[] = $vv;
}
}
}elseif(property_exists($instance,'hrbc_cols_arr')){
foreach($instance->hrbc_cols_arr as $kk=>$vv){
if(array_key_exists(ucfirst($resource),$vv)){
foreach($vv[ucfirst($resource)] as $vvv){
if(is_array($vvv) && !in_array($vvv[0],$field)){
$field[] = $vvv[0];
}elseif(!is_array($vvv) && !in_array($vvv,$field)){
$field[] = $vvv;
}
}
}
}
}
}
}
}
}
When I print the $v in the above code to find what are classes being used, I found list of classes that defined in my models.
If question is not clear please let me know, I can provide more information.
Is there any other library that can replace this function in Python? Or Is there any other solution I can try ?
Is it possible to create information message with options like proceed or cancel in OpenERP ? If it is possible how to create one ?
You can extend a js web module to do that.
Create script.js under /module_name/static/src/js/ which contains:
openerp.module_name = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
/* For example */
instance.web.FormView.include({
});
};
You can create a wizard with cancel and proceed button within
Friends,
Need to remove this option from pop up manyone fields. (not in all fields.some fields need to remove this feature).i used widget="selection".then my domain filter not working.so please help me to find a solution.
There is a module for openerp 6.1 to remove the create and edit option(in the openerp apps site search for web remove) from the default selection of many2one field. You can use this as an example and create you own module. or you can modify the base codes goto your server, then navigate to openerp/addons/web/static/src/js/view_form.js and remove the quick create functionality defined from the line number 2860.
This is the Same answer that I have given in openerp help site.
I have faced the same problem, but I solved it easily.
You need to change your web add-ons.
Please follow the step:
Go to: web/static/src/js
open the file: view_form.js
Go to line number 2958 or you can find label: _t ("Create and
Edit..."),
comment it
Enjoy, you can now see in your many2one fields don't have 'Create and Edit'
Note : This will affect every many2one field.
In v7 you can use the answer as suggested in http://help.openerp.com/question/16498/how-to-disable-create-and-edit-from-from-a-menu/
<form string="My form" create="false">
I had this problem in v6.1 though, so I created a new option so that I could apply it to only some fields (not all fields as suggested by #Bipin)
<form string="My form" options='{"no_create": true}'>
and changed web/static/src/js/view_form.js
// Hack: check for new "no_create" option:
if (self.get_definition_options().no_create === undefined || !self.get_definition_options().no_create) {
// the rest of the code stays asis:
// quick create
var raw_result = _(data.result).map(function(x) {return x[1];});
if (search_val.length > 0 &&
!_.include(raw_result, search_val) &&
(!self.value || search_val !== self.value[1])) {
values.push({label: _.str.sprintf(_t('<em> Create "<strong>%s</strong>"</em>'),
$('<span />').text(search_val).html()), action: function() {
self._quick_create(search_val);
}});
}
// create...
values.push({label: _t("<em> Create and Edit...</em>"), action: function() {
self._change_int_value(null);
self._search_create_popup("form", undefined, {"default_name": search_val});
}});
} // here endith the hack
I want to make this into a module, as editing the source code isn't very maintainable.
Hi i got the site domain in the template name with the
{{request.META.HTTP_HOST}}
from which i got the value some thing like this
pydev.aviesta.com
and
pydev.aviesta.com.mx
i need to show different data for both domains but as this is the dev server i cant use the full doamin name for compare can i check only .mx or .com so there will be no problem when going to live site
You may need Custom filter for this.
#register.filter(name='split')
def split(value, arg):
return value.split('.')[-1]
Use it as {{request.META.HTTP_HOST|split}}
i got the solution with js
<script>
var str = location.host;
if( str.search(".mx") > 0 ){
var dom = 'mx';
}else{
var dom = 'com';
} </script>
I've got geodjango running using openlayers and OpenStreetMaps with the admin app.
Now I want to write some views to display the data. Basically, I just want to add a list of points (seen in the admin) to the map.
Geodjango appears to use a special openlayers.js file to do it's magic in the admin. Is there a good way to interface with this?
How can I write a view/template to display the geodjango data on a open street map window, as is seen in the admin?
At the moment, I'm digging into the openlayers.js file and api looking for an 'easy' solution. (I don't have js experience so this is taking some time.)
The current way I can see to do this is add the following as a template, and use django to add the code needed to display the points. (Based on the example here)
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Draw Feature Example</title>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
<script type="text/javascript">
var map;
function init(){
map = new OpenLayers.Map('map');
var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
map.addLayer(layer);
/*
* Layer style
*/
// we want opaque external graphics and non-opaque internal graphics
var layer_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
layer_style.fillOpacity = 0.2;
layer_style.graphicOpacity = 1;
/*
* Blue style
*/
var style_blue = OpenLayers.Util.extend({}, layer_style);
style_blue.strokeColor = "blue";
style_blue.fillColor = "blue";
style_blue.graphicName = "star";
style_blue.pointRadius = 10;
style_blue.strokeWidth = 3;
style_blue.rotation = 45;
style_blue.strokeLinecap = "butt";
var vectorLayer = new OpenLayers.Layer.Vector("Simple Geometry", {style: layer_style});
// create a point feature
var point = new OpenLayers.Geometry.Point(-111.04, 45.68);
var pointFeature = new OpenLayers.Feature.Vector(point,null,style_blue);
// Add additional points/features here via django
map.addLayer(vectorLayer);
map.setCenter(new OpenLayers.LonLat(point.x, point.y), 5);
vectorLayer.addFeatures([pointFeature]);
}
</script>
</head>
<body onload="init()">
<div id="map" class="smallmap"></div>
</body>
</html>
Is this how it's done, or is there a better way?
Another solution is to create a form that utilizes the GeoDjango Admin widget.
To do this, I:
Setup a GeneratePolygonAdminClass:
class GeneratePolygonAdmin(admin.GeoModelAdmin):
list_filter=('polygon',)
list_display=('object', 'polygon')
Where the form is built:
geoAdmin=GeneratePolygonAdmin(ModelWithPolygonField, admin.site)
PolygonFormField=GeneratePolygon._meta.get_field('Polygon')
PolygonWidget=geoAdmin.get_map_widget(PolygonFormField)
Dict['Polygon']=forms.CharField(widget=PolygonWidget()) #In this case, I am creating a Dict to use for a dynamic form
Populating the widget of the form:
def SetupPolygonWidget(form, LayerName, MapFileName, DefaultPolygon=''):
form.setData({'Polygon':DefaultPolygon})
form.fields['Polygon'].widget.params['wms_layer']=LayerName
form.fields['Polygon'].widget.params['wms_url']='/cgi-bin/mapserv?MAP=' + MapFileName
form.fields['Polygon'].widget.params['default_lon']=-80.9
form.fields['Polygon'].widget.params['default_lat']=33.7
form.fields['Polygon'].widget.params['default_zoom']=11
form.fields['Polygon'].widget.params['wms_name']=YOURWMSLayerName
form.fields['Polygon'].widget.params['map_width']=800
form.fields['Polygon'].widget.params['map_height']=600
form.fields['Polygon'].widget.params['map_srid']=YOUR_SRID
form.fields['Polygon'].widget.params['modifiable']=True
form.fields['Polygon'].widget.params['map_options']={}
form.fields['Polygon'].widget.params['map_options']['buffer'] = 0
return form
Based on the code at:
http://code.djangoproject.com/browser/django/branches/gis/django/contrib/gis/admin/options.py?rev=7980
It looks like you can use the extra_js option to include OpenStreetMap (I have not tested this).
This is quite old, and I wouldn't go around creating a template hack as I originally was thinking. Now I would use leaflet.js with an ajax request to a django view that returns geojson to a leaflet geojson layer.
This makes the django side super easy.
Sample Django View:
# -*- coding: utf-8 -*-
'''
'''
import json
from django.http import HttpResponse, HttpResponseBadRequest
from django.contrib.gis.geos import Polygon
from models import ResultLayer, MyModel
def get_layer_polygons(request, layer_id):
"""
Return the polygons for the given bbox (bounding box)
"""
layer = ResultLayer.objects.get(id=layer_id)
bbox_raw = request.GET.get("bbox", None)
# Make sure the incoming bounding box is correctly formed!
bbox = None
if bbox_raw and bbox_raw.count(",") == 3:
bbox = [float(v) for v in bbox_raw.split(",")]
if not bbox:
msg = "Improperly formed or not given 'bbox' querystring option, should be in the format '?bbox=minlon,minlat,maxlon,maxlat'"
return HttpResponseBadRequest(msg)
bbox_poly = Polygon.from_bbox(bbox)
bbox_poly.srid = 900913 # google
bbox_poly.transform(layer.srid) # transform to the layer's srid for querying
bin_size = int(bin_size)
# build vector polygons from bin
results = MyModel.objects.filter(layer=layer, poly__intersects=bbox_poly).transform(900913, field_name="poly")
geojson_data = []
for r in results:
# loading json in order to dump json list later
gjson = r.poly.geojson
py_gjson = json.loads(gjson)
geojson_data.append(py_gjson)
return HttpResponse(json.dumps(geojson_data), mimetype='application/json')
I think your solution is workable and probably the easiest approach. Just templatize the javascript and use Django to inject your data points as the template is rendered.
If you wanted to get fancier, you could have a Django view that served up the data points as JSON (application/json) and then use AJAX to call back and retrieve the data based on events that are happening in the browser. If you want your application to be highly interactive above and beyond what OpenLayers provides, this might be worth the added complexity, but of course it all depends on the needs of your application.
You could consider using FloppyForms. In the end, I usually end up customizing the solution to my own needs, but it's a nice way to get started.
Checkout this tutorial from the geodjango-basic-apps project:
http://code.google.com/p/geodjango-basic-apps/wiki/FOSS4GWorkshop
maybe you don't have to hack up your own javascript just yet