Rendering spatial data of GeoQuerySet in a custom view on GeoDjango - django

I have just started my first project on GeoDjango.
As a matter of fact, with GeoDjango powered Admin application we all have a great possibility to view/edit spatial data, associated with the current object.
The problem is that after the objects having been populated I need to render several objects' associated geometry at once on a single map. I might implement it as a model action, redirecting to a custom view. I just don't know, how to include the OpenLayers widget in the view and how to render there my compound geometry from my GeoQuerySet.
I would be very thankful for any hint from an experienced GeoDjango programmer.

Two halves of this question:
How do I generate Geographic data that OpenLayers can read via Django?
How do I consume this data with OpenLayers?
Generating Geographic Data
There are several different ways to generate geographic data in Django. Built in, you can use the .kml() or .json() methods on a queryset; doing so causes each returned instance to have a .json or .kml property which has the KML or JSON of the Geometry generated as a string.
You can then use this output in templates that use the {{feature.kml}} or {{feature.json}}. (The latter is somewhat difficult, because you would have to manually do the JSON encoding before it hit the template, a bit of an odd situation.)
Another option is to use a library to help you: specifically, vectorformats. (Google "featureserver vectorformats" for information, since I can only include one hyperlink.) Installed via PyPI/easy_install vectorformats, you can use the Django format:
>>> from vectorformats.Formats import Django, GeoJSON
>>> qs = Model.objects.filter(city="Cambridge")
>>> djf = Django.Django(geodjango="geometry", properties=['city', 'state'])
>>> geoj = GeoJSON.GeoJSON()
>>> s = geoj.encode(djf.decode(qs))
>>> print s
This string can be returned via an HTTPResponse to return a GeoJSON object. So, your view would wrap these 4 lines in a bit that generated a queryset (qs, here), and then returned an HttpResponse with the string.
Consuming Data
OpenLayers has 'format' objects which can read data: There are formats for GeoJSON and KML, as well as others.
You can load the data using standard XMLHttpRequest mechanisms then parse them with a format:
var f = new OpenLayers.Format.GeoJSON();
var features = f.read(req.responseText);
layer.addFeatures(features);
Alternatively, you can use the built in Protocol support to load remote data:
map = new OpenLayers.Map('map');
var wms = new OpenLayers.Layer.WMS(
"OpenLayers WMS", "http://labs.metacarta.com/wms/vmap0",
{layers: 'basic'}
);
var layer = new OpenLayers.Layer.Vector("GML", {
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: "/django/view/json/",
format: new OpenLayers.Format.GeoJSON()
})
});
map.addLayers([wms, layer]);
map.zoomToExtent(new OpenLayers.Bounds(
-3.92, 44.34, 4.87, 49.55
));
You can see in this example, that the 'url' points to your Django view; all the loading of data and parsing it according to the provided format is included. (You can see a similar example in the OpenLayers example for fixed behavior/http protocol.)
Putting it Together
Create a Django view, using vectorformats to return your data as GeoJSON
Create a separate view, which returns an HTML page like the OpenLayers example linked, with the modifications shown in the code sample.
That view serves the HTML page that loads your GeoJSON data and parses it.

Related

How to make filtering non model data in flask-admin

I have to make dashboard like view in flask-admin that will use data retrieved from external API. I have already written a functions that get date ranges and return data from that range. I should use BaseView probably but I don't know how to actually write it to make filters work. This is example function that i have to use: charts = generate_data_for_dashboard('164', '6423FACA-FC71-489D-BF32-3A671AB747E3', '2018-03-01', '2018-09-01'). Those params should be chosen from 3 different dropdowns. So far I know only how to render views with pre coded data like this :
class DashboardView(BaseView):
kwargs = {}
#expose('/', methods=('GET',))
def statistics_charts(self):
user = current_user
company = g.company
offices = Office.query.filter_by(company_id=company.id)
self.kwargs['user'] = user
self.kwargs['company'] = company
charts = generate_data_for_dashboard('164', '6423FACA-FC71-489D-BF32-3A671AB747E3', '2018-03-01', '2018-09-01')
self.kwargs['chart1'] = charts[0]
self.kwargs['chart2'] = charts[1]
return self.render('stats/dashboard.html', **self.kwargs)
But I need some kind of form to filter it. In addition date filter dropdown should have dynamic options : current_week, last_week, current_month, last_month, last_year. Don't know where to start.
You should use WTForms to build a form. You then have to decide if you want the data to be fetched on Submit or without a reload of the page. In the former case, you can just return the fetched information on the response page in your statistics_charts view. But if you want the data to update without a reload, you'll need to use JavaScript to track the form field changes, send the AJAX request to the API, and then interpret the resulting JSON and update your dashboard graphs and tables as needed.
I have not used it, but this tutorial says you can use Dash for substantial parts of this task, while mostly writing in Python. So that could be something to check out. There is also flask_jsondash which might work for you.

store a list in request.session in one view and retrieve it in another view django

I have a huge list that will be generated dynamically from a csv file in a django view, but i had a requirement to use that list in the next view, so i thought to give a try on django sessions
def import_products(request):
if request.method == 'POST':
if request.FILES:
csv_file_data = ...........
total_records = [row for row in csv_file_data]
request.session['list_data'] = total_records
# total_records is `list of lists` of length more than 150
# do some processing with the list and render the page
return render_to_response('product/import_products.html')
def do_something_with_csv_data_from_above_view(request):
data = request.session['list_data']
# do some operations with list and render the page
return render_to_response('website/product/success.html',
So as mentioned in the above, i need to use the total_records huge list in the do_something_with_csv_data_from_above_view view and delete the session by storing it in another variable
So actually how to implement/use exactly the sessions concept(i have read the django docs but could n't able to get the exact concept)
In my case,
When a user tries to upload the csv file each time, i am reading the data and storing
the data as list to session
==> Is this the right way to do so ? also i want to store the session variable in
database concept
Because the list was huge, i need to delete it for sure in the next view when i
copied it in to another variable
Am i missing anything, can anyone please implement exact code for my above scenario ?
You have two options:
Client side RESTful - This is a RESTful solution but may require a bit more work. You can retrieve the data in the first request to the client and after selecting you can send the selected rows back to the server for processing, CSV etc.
Caching: In the first request you can cache your data on the server using a django file system or memcached. In the second request use the cache key (which would be the user session key + some timestamp + whatever else) to fetch the data and store in the db.
If it's a lot of data option 2 may be better.

How to quickly create custom content elements in TYPO3 6.x

In TYPO3 6.x, what is an easy way to quickly create custom content elements?
A typical example (Maybe for a collection of testimonials):
In the backend (with adequate labels):
An image
An input field
A textarea
When rendering:
Image resized to xy
input wrapped in h2
textarea passed through parseFunc and wrapped in more markup
Ideally, these would be available in the page module as cType, but at least in the list module.
And use fluid templates.
My questions:
From another CMS I am used to content item templates being applied to the BE and the FE at the same time (you write the template for what it should do, and then there's a backend item just for that type of content element) - but that's not how fluid works - or can it be done?
Is there an extension that would handle such custom content elements (other than Templavoila)?
Or do I have to create a custom extbase/fluid extension for each such field type?
And, by the way: is there a recommendable tutorial for the new extbase kickstarter? I got scared away by all that domain modelling stuff.
That scaring domain modeling stuff is probably best option for you :)
Create an extension with FE plugin which holds and displays data as you want, so you can place it as a "Insert plugin". It's possible to add this plugin as a custom CType and I will find a sample for you, but little bit later.
Note, you don't need to create additional models as you can store required data ie. in FlexForm.
From FE plugin to CType
Let's consider that you have an extension with key hello which contains News controller with list and single actions in it.
In your ext_tables.php you have registered a FE plugin:
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin($_EXTKEY, 'News', 'Scared Hello News');
When it's working fine you can add it to the list of content types (available in TCA) just by adding fifth param to the configurePlugin method in your ext_localconf.php:
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'TYPO3.' . $_EXTKEY,
'News',
array('News' => 'list, show'),
array('News' => ''),
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT // <- this one
);
Next part (basing on this site) is adding your plugin to the New Content Element Wizard as noticed in TYPO3 Wiki since TYPO3 ver. 6.0.0 changed a little, so easiest way is adding something like this into your ext_tables.php:
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig('<INCLUDE_TYPOSCRIPT: source="FILE:EXT:hello/Configuration/TypoScript/pageTsConfig.ts">');
and in /typo3conf/ext/hello/Configuration/TypoScript/pageTsConfig.ts file write add this:
mod.wizards.newContentElement.wizardItems.plugins.elements.tx_hello_news {
icon = gfx/c_wiz/regular_text.gif
title = Scared Hello News
description = Displays Scared News
tt_content_defValues.CType = hello_news
}
# Below the same for TemplaVoila
templavoila.wizards.newContentElement.wizardItems.plugins.elements.tx_hello_news {
icon = gfx/c_wiz/regular_text.gif
title = Scared Hello News
description = Displays Scared News
tt_content_defValues.CType = hello_news
}
Note that proper key tx_hello_news should be combination of lowercased tx_, $_EXTKEY and plugin name - used in registerPlugin method.
You can stop here if you are bored ;)
Bring tt_content's fields back into your CType
Above steps will cause that no typical fields will be available in the TCA for your element, so you need to copy something or create own. To see how it works just see some sample, in the backend in left menu choose ADMIN TOOLS > Configuration > TCA > tt_content > types
There you'll find all types in the system, choose the most required and copy its [showitem] node into your own. Again in ext_tables.php add this PHP array:
$TCA['tt_content']['types']['hello_news']['showitem'] = $TCA['tt_content']['types']['textpic']['showitem'];
Again: hello_news is combination of lowercased $_EXTKEY and FE plugin name...
Of course if it's required you can compose quite own set of fields, one by one by custom string:
$TCA['tt_content']['types']['hello_news']['showitem'] = '--palette--;LLL:EXT:cms/locallang_ttc.xml:palette.general;general, --palette--;LLL:EXT:cms/locallang_ttc.xml:palette.header;header';
Access the fields in Extbase Controller:
Fortunately is easiest part as you can just access it as an Array:
$currentTtContent = $this->configurationManager->getContentObject()->data;
$header = $currentTtContent['header'];
debug($currentTtContent);
debug($header);
I think http://typo3.org/extensions/repository/view/dce will do exactly what I was looking for

Huge remote source to jquery autocomplete without using database

I am working on a web app, in Django, which lets user tell their favourite movies. For the input I want to provide users a textbox with autocomplete enabled.
The list of all movies ever made is very big (18 MB) thus autocomplete has to be enabled using remote source.
To add to this, I have the constraint that I can not use a database. (Because my app is hosted on heroku and to store such data in database would cost a lot)
Right now, I have the list of all movies stored in a .py file, and I import it into my views.py. The view which handles the ajax request from autocomplete iterates over each movie in this list to filter based on the query term and returns the filtered list.
-movies.py
all_movies = [list of all movies' titles] # > 1M string elements
-views.py (handle_autocomplete() gets called whenever user changes the input in the textbox on web app)
import movies
def handle_autocomplete(request):
data = request.GET['term']
my_list = [title for title in movies.all_movies if data in title]
return HttpResponse(simplejson.dumps(my_list))
What are the disadvantages of this approach and how can I improve upon it?
Are there any libraries/ django apps which handle remote-source autocomplete ?

Google Maps location based on address in django

I am developing a web application in django and i want to build a feature where in a person can input a location name in a text box and the corresponding location is shown at the center of a google map on the next page..
Please let me know the detailed way in which this can be done in Django
Thank you in advance!
I don't know whether this helps you enough, but basically this is one way of doing it:
Write the form, the view and the template for the location input;
Read up on how to set up a Google Maps instance with Javascript;
When a user submits the form, your view calls the Google Maps geocoding web service, using urllib2 (the URL is for instance: http://maps.googleapis.com/maps/api/geocode/json?address=<address retrieved from form>&sensor=true
Process the resulting JSON, extracting latitude and longitude;
Return the lat and lng variables (+ others you might need) to your template;
In your template, where you define your map in javascript, use the lat and lng template variables to set up the map, e.g. (as per the example in the Google Maps JavaScript API docs):
var myLatlng = new google.maps.LatLng({% latitude%}, {% longitude %});
var myOptions = {
zoom: 8,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
As one commenter noted, your question is very broad - this answer therefore won't go in too many details. If you get the above process working, start expanding on it (you could easily ajaxify this for example, or you could use the GM webservice to return meaningful error messages to the user, ...)