new base for viewer
Closed this issue · 8 comments
viewer application should be simplified and then divided into abstract classes and the child case. Creating abstract class and child class helps us to write code in DRY style of coding for further development.
For this reason, the viewer
app will be replace by viewer_standalone
for safety and code repository. In the next step, viewer_standalone
will be split in two apps that contain the abstract classes and the child (usage) classes separately.
Models
Search - OK, remove str
Remove Dataset
Remove VisualizationParameter
Remove Visualization
Forms
SearchForm
Meta.fields = ['polygon', 'date0', 'date1', 'source']
should not be hardcoded.
It should be dynamically set in a method of SearchForm. For example:
# in base_viewer
class SearchForm(forms.ModelForm):
search_model = Search
search_fields = ['polygon', 'date0', 'date1', 'source']
def __init__(self, *args, **kwargs):
self.Meta.model = self.search_model
self.Meta.fields = self.search_fields
super().__init__(self, *args, **kwargs)
class Meta:
model = None
fields = None
...
# in adas_viewer
class AdasSearchForm(SearchForm):
search_model = AdasSearch
search_fields = ['polygon', 'date0', 'date1', 'source', 'parameter']
Views
Keep IndexView
remove IndexView. set_params
Keep set_form_defaults, post, get
Split render into:
filter_datasets()
# base viewer
class IndexView(View):
def get...
def post...
...
def filter_datasets(self, form):
# filter by date
# filter by source
# filter by geometry
# adas_viewer
class AdasView(IndexView):
def filter_datasets(self, form):
super().filter_datasets(self, form)
# filter by parameter name
Remove pagination of output
Remove params
Remove visualisation
def render(self, request)
datasets = self.filter(self.form)
datasets = self.paginate(datasets)
context = self.set_context()
render(context)
Template
Start from scratch:
https://django-leaflet.readthedocs.io/en/latest/widget.html
Bare minimum template should show a form (with a map) and a list of found files.
is my draft of templates for possible usage in the future as snippet codes.
- Let's move some functionality to ModelForms:
default values can be set a ModelForm method set_defaults()
Input and output is form
filtering of datasets can be done a ModelForm filter()
Input and output is dataset
class SearchForm1:
def set_defaults(self, form):
form['time_coverage_start'] = 10
return form
def filter(self, form, datasets):
return datasets.objects.filter(time_coverage_start=form['time_coverage_start'])
class SearchForm2:
def set_defaults(self, form):
return form
def filter(self, form, datasets):
return datasets.objects.filter(geometry__intersects=form['geometry'])
class BaseView:
class_form = [SearchForm1, SearchForm2]
def set_defaults(self):
self.forms = [form.set_defaults() for form in self.class_form]
def filter(self, form):
ds = Dataset.objects.all()
for form in self.class_form:
ds = form.filter(ds)
return ds
- Let's make get() and post() methods flat (read Zen of Python)
def get(self):
self.set_defaults()
self.validate()
self.filter()
self.set_context()
render()
def post(self, request):
self.set_defaults()
forms = [form(request) for form in self.class_form]
self.validate()
self.filter()
self.set_context()
render()
class AdasView(BaseView):
class_form = [SearchForm1, SearchForm2, SearchForm3]
Add self.initial to forms:
class BaseForm(forms.ModelForm):
initial = dict()
def __init__(self, *args, **kwargs):
uper().__init__(initial=self.initial, *args, **kwargs)
class TimeAndSourceForm(BaseForm):
initial = dict(
time_coverage_end = timezone.now(),
time_coverage_start = timezone.datetime(2000, 1, 1),
)
class Meta:
model = CatalogDataset
fields = ['time_coverage_start', 'time_coverage_end', 'source']
def filter(self, ds):
t0 = self.cleaned_data['time_coverage_start']
t1 = self.cleaned_data['time_coverage_end'] + \
timezone.timedelta(hours=24)
ds = ds.filter(Q(time_coverage_end__lt=t1) &
Q(time_coverage_start__gt=t0))
src = [self.cleaned_data['source']]
ds = ds.filter(source__in=src)
return ds
class SpatialSearchForm(BaseForm):
...
form = TimeAndSourceForm()
form = TimeAndSourceForm(post.REQUEST)
Add parameter to create_forms()
And return forms instead of setting self.forms
def create_forms(self, request_post=None):
''' Set default values for the form by instantiating them '''
if request_post is None:
request_post = dict()
forms = [i(request_post) for i in self.form_class]
return forms
def get(self, request, *args, **kwargs):
''' Render page if no data is given '''
forms = self.create_forms()
forms = self.validate_forms(forms)
self.filtering_the_datasets(request, forms)
self.set_context(forms)
return render(request, self.main_template, self.context)
def post(self, request, *args, **kwargs):
''' all sections needed for POST requests'''
forms = self.create_forms(request.POST)
forms = self.validate_forms(forms)
# modify attributes based on the forms cleaned data
self.filtering_the_datasets(request, forms)
# return self.final_rendering(request)
self.set_context(forms)
return render(request, self.main_template, self.context)
Change logics of the filtering function
def get():
ds = self.get_all_datasets()
def post():
ds = self.get_filtered_datasets(forms)
def get_all_datasets(self):
return CatalogDataset.objects.all()
def get_filtered_datasets(self, forms):
ds = self.get_all_datasets()
for form in forms:
ds = form.filter(ds)
return ds