def conformanceMain(self,request): ''' Displays the main conformance view ''' s=self.s e=s.experiment urls={'self':reverse('pimmsqn.apps.qn.views.conformanceMain', args=(self.centreid,s.id,)), 'mods':reverse('pimmsqn.apps.qn.views.assign', args=(self.centreid,'modelmod','simulation',s.id,)), 'sim':reverse('pimmsqn.apps.qn.views.simulationEdit', args=(self.centreid,s.id,)) } #con=Conformance.objects.filter(simulation=s) if request.method=='POST': cformset=MyConformanceFormSet(s,request.POST) if cformset.is_valid(): cformset.save() return HttpResponseRedirect(urls['self']) else: cformset.specialise() elif request.method=='GET': cformset=MyConformanceFormSet(s) cformset.specialise() return render_to_response('conformance.html',{'s':s, 'e':e, 'cform':cformset, 'urls':urls, 'tabs':tabs(request, self.centreid, 'Conformance')})
def list(self,request): ''' Return a listing of simulations for a given centre ''' c=Centre.objects.get(pk=self.centreid) #little class to monkey patch up the stuff needed for the template class etmp: def __init__(self, abbrev, values, id, group): self.abbrev = abbrev self.values = values self.id = id self.url = reverse('pimmsqn.apps.qn.views.viewExperiment', args=(c.id, id,)) self.new = reverse('pimmsqn.apps.qn.views.simulationAdd', args=(c.id, id,)) self.group = group csims = Simulation.objects.filter(centre=c).filter(isDeleted=False) cpurl = reverse('pimmsqn.apps.qn.views.simulationCopy', args=(c.id, )) eset=Experiment.objects.all().filter(isDeleted=False) exp=[] for e in eset: sims = e.simulation_set.filter(centre=c.id).filter(isDeleted=False) group = e.abbrev.split()[1] for s in sims: s.url = reverse('pimmsqn.apps.qn.views.simulationEdit', args=(c.id,s.id,)) exp.append(etmp(e.abbrev, sims, e.id, group)) return render_to_response('simulationList.html', {'c':c,'experiments':exp,'csims':csims,'cpurl':cpurl, 'tabs':tabs(request,c.id,'Experiments'), 'notAjax':not request.is_ajax()})
def centre(request,centre_id): ''' Handle the top page on a centre by centre basis ''' c=Centre.objects.get(id=centre_id) #models=[] models=[Component.objects.get(id=m.id) for m in c.component_set.filter( scienceType='model').filter( isDeleted=False)] #monkey patch the urls to edit these ... for m in models: m.url=reverse('pimmsqn.apps.qn.views.componentEdit',args=(c.id,m.id)) m.cpURL=reverse('pimmsqn.apps.qn.views.componentCopy',args=(c.id,m.id)) platforms=[Platform.objects.get(id=p['id']) for p in c.platform_set.values().filter(isDeleted=False)] for p in platforms: p.url=reverse('pimmsqn.apps.qn.views.platformEdit',args=(c.id,p.id)) sims=Simulation.objects.filter(centre=c.id).filter(isDeleted=False).order_by('abbrev') for s in sims: s.url=reverse('pimmsqn.apps.qn.views.simulationEdit',args=(c.id,s.id)) grids=Grid.objects.filter(centre=c.id).filter(istopGrid=True).filter(isDeleted=False) for g in grids: g.url=reverse('pimmsqn.apps.qn.views.gridEdit',args=(c.id,g.id)) g.cpURL=reverse('pimmsqn.apps.qn.views.gridCopy',args=(c.id,g.id)) newmodURL=reverse('pimmsqn.apps.qn.views.componentAdd',args=(c.id,)) newplatURL=reverse('pimmsqn.apps.qn.views.platformEdit',args=(c.id,)) viewsimURL=reverse('pimmsqn.apps.qn.views.simulationList',args=(c.id,)) newgridURL=reverse('pimmsqn.apps.qn.views.gridAdd',args=(c.id,)) refs=Reference.objects.filter(centre=c) files=DataContainer.objects.filter(centre=c) parties=ResponsibleParty.objects.filter(centre=c) #get simulation info for sim table tablesims = getsims(c) logging.info('Viewing %s'%c.id) return render_to_response('centre/centre.html', {'centre':c, 'models':models, 'platforms':platforms, 'grids':grids, 'refs':refs, 'files':files, 'parties':parties, 'newmod':newmodURL, 'newplat':newplatURL, 'newgrid':newgridURL, 'sims':sublist(sims,3), 'viewsimurl':viewsimURL, 'tabs':tabs(request,c.id, 'Summary'), 'notAjax':not request.is_ajax(), 'tablesims':tablesims})
def edit(self,request,returnType): ''' We normally see this method called as a GET when it's hyperlinked from a list or assign page, so we want to go back there in those cases. If it's a POST, then we handle it, and go back to the correct place, unless there is a problem. ''' # The basic sequence when we receive an edit form as a post, is that # if it's valid, return to where we came from. If it's not, we should show # a form, complete with errors, with a submission URL which gets the user # back to the right place. A GET should set that process up. if self.target: okURL=reverse('pimmsqn.apps.qn.views.%s'%returnType, args=(self.cid,self.resource['type'],self.target['type'],self.target['instance'].id,)) else: okURL=reverse('pimmsqn.apps.qn.views.%s'%returnType, args=(self.cid,self.resource['type'],)) # Note that if the resource instance id is zero, this is a new one. instance=None if self.resource['id']<>'0': instance=self.resource['class'].objects.get(id=self.resource['id']) # Now construct a useful submission URL args=[self.cid,self.resource['type'],self.resource['id']] if self.target:args+=[self.target['type'],self.target['instance'].id] if returnType: args.append(returnType) if request.method=='POST': logging.debug('Handling post with %s, %s '%(self.resource,request.POST)) if instance: if instance.centre!=self.centre: logging.info('Attempt to edit resource not owned') return HttpResponseForbidden(render_to_string('error.html', {'message':"Attempt to edit a resource you don't own", 'url':okURL})) form=self._constructForm('POST',request.POST,instance=instance) form.hostCentre=self.centre if form.is_valid(): if returnType=='ajax': return HttpResponse('not implemented') f=form.save() args[2]=f.id editURL=reverse('pimmsqn.apps.qn.views.edit',args=args) logging.debug('Successful edit post, redirecting to %s'%editURL) return HttpResponseRedirect(editURL)#(okURL) else: print 'ERRORS [%s]'%form.errors elif request.method=='GET': form=self._constructForm('GET',instance=instance) constraints=self.constraints() if constraints:form.specialise(constraints) editURL=reverse('pimmsqn.apps.qn.views.edit',args=args) return render_to_response(self.editHTML,{'form':form,'editURL':editURL,'okURL':okURL, 'tabs':tabs(request,self.cid,'Edit %s'%instance), 'snippet_template':'%s_snippet.html'%self.resource['type'], 'resource':self.resource})
def ensemble(request,cen_id,sim_id): ''' Manage ensembles for a given simulation ''' s=Simulation.objects.get(id=sim_id) e=Ensemble.objects.get(simulation=s) e.updateMembers() # in case members were deleted via their code mods or ics. members=e.ensemblemember_set.all()[1:] EnsembleMemberFormset=modelformset_factory(EnsembleMember, form=EnsembleMemberForm, formset=BaseEnsembleMemberFormSet, extra=0,exclude=('ensemble', 'memberNumber')) urls={'self':reverse('pimmsqn.apps.qn.views.ensemble', args=(cen_id,sim_id,)), 'sim':reverse('pimmsqn.apps.qn.views.simulationEdit', args=(cen_id,sim_id,)), 'mods':reverse('pimmsqn.apps.qn.views.list', args=(cen_id,'modelmod','ensemble',s.id,)), 'ics':reverse('pimmsqn.apps.qn.views.list', args=(cen_id,'inputmod','ensemble',s.id,)), } if request.method=='GET': eform=EnsembleForm(instance=e,prefix='set') eformset=EnsembleMemberFormset(queryset=members,prefix='members') elif request.method=='POST': if e.etype is not None: eformset=EnsembleMemberFormset(request.POST,queryset=members,prefix='members') else: eformset=None eform=EnsembleForm(request.POST,instance=e,prefix='set') ok=True if eform.is_valid(): eform.save() else: ok=False if eformset is not None: if eformset.is_valid(): eformset.save() else: ok=False logging.debug('POST to ensemble is ok - %s'%ok) if ok: return HttpResponseRedirect(urls['self']) for f in eformset.forms: f.specialise(s.experiment.requirementSet) eform.rset=(s.experiment.requirementSet is not None) return render_to_response('ensemble.html', {'s':s,'e':e,'urls':urls,'eform':eform,'eformset':eformset, 'tabs':tabs(request,cen_id,'Ensemble')})
def manageRefs(self,request): ''' Handle references for a specific component ''' refs=Reference.objects.filter(component__id=self.component.id) allrefs=Reference.objects.all() available=[] c=self.component for r in allrefs: if r not in refs:available.append(r) rform=ReferenceForm() refu=reverse('pimmsqn.apps.qn.views.addReference',args=(self.centre_id,c.id,)) baseURLa=reverse('pimmsqn.apps.qn.views.assignReference',args=(1,1,))[0:-4] baseURLr=reverse('pimmsqn.apps.qn.views.remReference',args=(1,1,))[0:-4] return render_to_response('componentRefs.html', {'refs':refs,'available':available,'rform':rform,'c':c, 'refu':refu,'baseURLa':baseURLa,'baseURLr':baseURLr, 'tabs':tabs(request,self.centre_id,'References for %s'%c), 'notAjax':not request.is_ajax()})
def inputs(self,request): ''' Handle the construction of input requirements into a component ''' okURL=reverse('pimmsqn.apps.qn.views.componentInp',args=(self.centre_id,self.pkid,)) urls={'ok':okURL,'self':self.url} if request.method=='POST': Inpform=MyComponentInputFormSet(self.component,self.component.isRealm, request.POST) if Inpform.is_valid(): Inpform.save() return HttpResponseRedirect(okURL) else: Inpform.specialise() elif request.method=='GET': Inpform=MyComponentInputFormSet(self.component,self.component.isRealm) Inpform.specialise() return render_to_response('inputs.html',{'c':self.component,'urls':urls, 'form':Inpform, 'tabs':tabs(request,self.centre_id,'Inputs for %s'%self.component)})
def coupling(self,request,ctype=None): ''' Handle the construction of component couplings ''' # we do the couplings for the parent model of a component model=self.component.model okURL=reverse('pimmsqn.apps.qn.views.componentCup',args=(self.centre_id,self.pkid,)) urls={'self':reverse('pimmsqn.apps.qn.views.componentCup', args=(self.centre_id,self.pkid,)) } cg=CouplingGroup.objects.filter(component=model).get(simulation=None) if request.method=='POST': Intform=MyCouplingFormSet(cg,request.POST) if Intform.is_valid(): Intform.save() return HttpResponseRedirect(okURL) else: Intform.specialise() elif request.method=='GET': Intform=MyCouplingFormSet(cg) Intform.specialise() return render_to_response('coupling.html',{'c':model,'urls':urls, 'Intform':Intform,'tabs':tabs(request,self.centre_id,'Coupling for %s'%model)})
def __handle(self,simulation=None): model=self.component.model assert model != None,'Component %s has no model'%self.component queryset=model.couplings(simulation) self.urls['model']=reverse('pimmsqn.apps.qn.views.componentEdit', args=(self.centre_id,model.id,)) logging.debug('Handling %s coupling request for %s (simulation %s)'%(self.method,model,simulation)) if self.method=='POST': Intform=MyCouplingFormSet(model,simulation,queryset,self.request.POST) if Intform.is_valid(): Intform.save() return HttpResponseRedirect(self.urls['ok']) else: Intform.specialise() elif self.method=='GET': Intform=MyCouplingFormSet(model,simulation,queryset) Intform.specialise() labelstr='Coupling for %s'%model if simulation: labelstr+=' (in %s)'%simulation return render_to_response('coupling.html',{'c':model,'s':simulation,'urls':self.urls, 'Intform':Intform, 'tabs':tabs(self.request,self.centre_id,labelstr)})
def platformEdit(request,centre_id,platform_id=None): ''' Handle platform editing ''' c=Centre.objects.get(id=centre_id) urls={} # start by getting a form ... if platform_id is None: urls['edit']=reverse('pimmsqn.apps.qn.views.platformEdit',args=(centre_id,)) if request.method=='GET': pform=MyPlatformForm(c) elif request.method=='POST': pform=MyPlatformForm(c,request.POST) p=None puri=atomuri() else: urls['edit']=reverse('pimmsqn.apps.qn.views.platformEdit',args=(centre_id,platform_id,)) p=Platform.objects.get(id=platform_id) puri=p.uri if request.method=='GET': pform=MyPlatformForm(c,instance=p) elif request.method=='POST': pform=MyPlatformForm(c,request.POST,instance=p) urls=commonURLs(p,urls) # now we've got a form, handle it if request.method=='POST': if pform.is_valid(): p=pform.save(commit=False) p.centre=c p.uri=puri p.save() return HttpResponseRedirect( reverse('pimmsqn.apps.qn.views.centre',args=(centre_id,))) return render_to_response('platform.html', {'pform':pform,'urls':urls,'p':p,'c':c, 'tabs':tabs(request,centre_id,'Platform')})
def intro(request,cen_id): return render_to_response('intro.html',{'tabs':tabs(request,cen_id,'Intro')})
def assign(self,request): ''' This method binds to the target resource, a number of the resources managed by this one. eg If this class is instantiated with resourceType = file, and this method is called with an instance (target) of some class, then this method will bind the chosen files to that target, and then return to that target view via targetURL. We provide targetType and targetID to allow the construction of return URLs when we go to the editor ...''' title='Assign %s(s) to %s %s'%(self.resource['type'],self.target['type'],self.target['instance']) objects=self.objects() data=[(r.id,str(r)) for r in objects] # two possible forms could be used, multiple choice, or single choice. class AssignForm(forms.Form): ''' Used for producing a form for selection of multiple choices ''' choose=forms.MultipleChoiceField(choices=data, widget=forms.CheckboxSelectMultiple(), required=False) class AssignOneForm(forms.Form): ''' Used for selecting just one option from a list ''' choose=forms.ChoiceField(choices=data) showChoices=len(data) # We have two sorts of django attributes to deal with here, # foreign keys, and manytomany fields. target=self.target['instance'] manager=target.__getattribute__(self.resource['attname']) # is it a manytomanyfield? many2many="<class 'django.db.models.fields.related.ManyRelatedManager'>" manyClass=str(type(manager)) JustOne=(manyClass!=many2many) #need to get at the initial values and choose an appropriate form if JustOne: if manager is None: initial=[] else: initial=manager.id ActualForm=AssignOneForm else: initial=[i.id for i in manager.get_query_set()] ActualForm=AssignForm if request.method=='POST': rform=ActualForm(request.POST) if rform.is_valid(): #now parse these up and assign to the resource if not JustOne:manager.clear() new=rform.cleaned_data['choose'] if JustOne: target.__setattr__(self.resource['attname'],objects.get(id=new)) else: for n in new: r=objects.get(id=n) manager.add(r) target.save() return HttpResponseRedirect(self.target['url']) elif request.method=='GET': #need to ensure that if there are none already chosen, we don't bind the form ... if initial==[]: rform=ActualForm() else:rform=ActualForm({'choose':initial}) url='' #editURL and form used to add a new instance. editURL=reverse('pimmsqn.apps.qn.views.edit', args=(self.cid,self.resource['type'],0,self.target['type'],self.target['instance'].id,'assign')) listURL=reverse('pimmsqn.apps.qn.views.list', args=(self.cid,self.resource['type'],self.target['type'],self.target['instance'].id)) return render_to_response(self.selectHTML, {'showChoices':showChoices, 'rform':rform, 'title':title, 'form':self._constructForm('GET'), 'editURL':editURL,'listURL':listURL, 'editTemplate':'%s_snippet.html'%self.resource['type'], 'tabs':tabs(request,self.cid,'Assign %s'%self.resource['type']), 'chooseURL':url})
def list(self,request): ''' Show a list of the basic entities, either all of them, or those associated with a specific instance of a specific class ''' objects=self.objects() #construct a set of options for filtering to a specific class (if appropriate) ftype=self.resource['filter'] if ftype: url=reverse('pimmsqn.apps.qn.views.filterlist',args=(self.cid,self.resource['type'],)) ops=ftype.objects.all() try: # if we can filter on centres, we do ... ops.filter(centre__id=self.cid) except AttributeError: pass filterops={'m':'Filter by %s'%ftype._meta.module_name, 'ops':ops, 'url':url, 'klass':ftype._meta.module_name} else: filterops=None # construct a CMIP5 export button if self.resource['type']=='file': exportFiles=reverse('pimmsqn.apps.qn.views.exportFiles',args=(self.cid,)) else: exportFiles=None if self.target: # in the case of a list, the target is used to go back ... # get a URL for a blank form formURL=reverse('pimmsqn.apps.qn.views.edit', args=(self.cid,self.resource['type'],0, self.target['type'],self.target['instance'].id,'list',)) for o in objects: # monkey patch an edit URL into the object allowing for the target, # saying come back here (to the list). Unfortunately doing that # means we lose the incoming reference. args=(self.cid,self.resource['type'],o.id, self.target['type'],self.target['instance'].id,'list',) o.editURL=reverse('pimmsqn.apps.qn.views.edit',args=args) o.delURL=reverse('pimmsqn.apps.qn.views.delete',args=args) #o.delURL=reverse('pimmsqn.apps.qn.views.delete', # args=(self.cid,self.resource['type'],o.id,self.currentURL) # Need to be able to make sure this isn't an html get from an <a> otherwise # do it as form with a method of delete. else: # get a URL for a blank form formURL=reverse('pimmsqn.apps.qn.views.edit', args=(self.cid,self.resource['type'],0,'list',)) for o in objects: # monkey patch an edit URL into the object, saying come back here (list) args=(self.cid,self.resource['type'],o.id,'list',) o.editURL=reverse('pimmsqn.apps.qn.views.edit',args=args) if o.centre==self.centre: o.delURL=reverse('pimmsqn.apps.qn.views.delete',args=args) else: o.delURL=None # we pass a form and formURL for a new instance to be created. # we're doing all this because we think we have too many entities to use a formset return render_to_response(self.listHTML,{ 'objects':sublist(objects,3), 'tabs':tabs(request,self.cid,self.resource['tab']), 'form':self._constructForm('GET'), 'editURL':formURL, 'instance':self.resource, 'snippet_template':'%s_snippet.html'%self.resource['type'], 'target':self.target, 'exportFiles':exportFiles, 'filter':filterops })
def edit(self,request): ''' Provides a form to edit a component, and handle the posting of a form containing edits for a component, or a delete''' c=self.component logging.debug('Starting editing component %s'%c.id) if request.method=='POST': if 'deleteMe' in request.POST: if c.controlled: logging.debug('Invalid delete POST to controlled component') return HttpResponse('Invalid Request') else: if len(c.components.all())<>0: return HttpResponse('You need to delete child components first') parent=Component.objects.filter(components=c)[0] url=reverse('pimmsqn.apps.qn.views.componentEdit',args=(self.centre_id,parent.id,)) c.delete() return HttpResponseRedirect(url) # find my own urls ... urls={} urls['form']=self.url urls['refs']=reverse('pimmsqn.apps.qn.views.assign',args=(self.centre_id,'reference', 'component',c.id,)) urls['subcomp']=reverse('pimmsqn.apps.qn.views.componentSub',args=(self.centre_id,c.id,)) urls['coupling']=reverse('pimmsqn.apps.qn.views.componentCup',args=(self.centre_id,c.id)) urls['inputs']=reverse('pimmsqn.apps.qn.views.componentInp',args=(self.centre_id,c.id)) urls['text']=reverse('pimmsqn.apps.qn.views.componentTxt',args=(self.centre_id,c.id)) urls=commonURLs(c.model,urls) baseURL=reverse('pimmsqn.apps.qn.views.componentAdd',args=(self.centre_id,)) template='+EDID+' baseURL=baseURL.replace('add/','%s/edit'%template) # this is the automatic machinery ... refs=Reference.objects.filter(component__id=c.id) inps=ComponentInput.objects.filter(owner__id=c.id) postOK=True if request.method=="POST": pform=ParamGroupForm(c,request.POST,prefix='props') pform.newatt=1 cform=ComponentForm(request.POST,prefix='gen',instance=c) if cform.is_valid(): c=cform.save() c=RemoteUser(request,c) logging.debug('Saving component %s details (e.g. uri %s)'%(c.id,c.uri)) else: logging.debug('Unable to save characteristics for component %s'%c.id) postOK=False logging.debug(cform.errors) ok=pform.save() if postOK: postOK=ok # if not postok, ok value doesn't matter # We separate the response handling so we can do some navigation in the # meanwhile ... navtree=yuiTree2(c.id,baseURL,template=template) # Handle a request to copy responsible details downwards to subcomponents if request.method=='POST': if 'filterdown' in request.POST: c.filterdown() if 'filterdowngrid' in request.POST: c.filterdowngrid() #OK, we have three cases to handle: #FIXME; we'll need to put this in the right places with instances: if request.method=='POST': if postOK: #redirect, so repainting the page doesn't resubmit logging.debug('Finished handling post to %s'%c.id) return HttpResponseRedirect(urls['form']) else: pass # don't reset the forms so the user gets an error response. else: #get some forms cform=ComponentForm(instance=c, prefix='gen') pform=ParamGroupForm(c,prefix='props') pform.newatt=1 if c.isModel: # We'd better decide what we want to say about couplings. Same # code in simulation! cset=c.couplings(None) else: cset=None # Need to check that the current top level model name is in agreement # with the official DRS names and sound a warning if not (as opposed # to raising a form error and halting further progress) if c.isModel: modname = c.abbrev if modname not in modelnames: warning = \ """ Warning: The model name used does not match an official cmip5 model name. Although this does not stop you from proceeding it will mean that you will not be able to export your metadata to CMIP5. If you believe your model name is correct, please get in touch as we update our list of accepted names only periodically """ else: warning=False else: warning=False # Text for notification panel to alert user of new questions and the # background behind this if c.isModel: helppaneltitle = "New Questions added" helppaneltext = \ """ These additional questions have been established by the Lead Authors of IPCC AR5 Chap 9 on "Model evaluation" and in consultation with the community to inform the model development process of CMIP5. These will help document: <br/> 1) the model development path, <br/> 2) the tuning process, and <br/> 3) the conservation of integral properties. <br/> It is expected that answers provided before July 15th 2012 will be reflected in the second order draft of the AR5 report. """ else: helppaneltitle = '' helppaneltext = '' logging.debug('Finished handling %s to component %s'%(request.method,c.id)) return render_to_response('componentMain.html', {'c':c,'refs':refs,'inps':inps, 'cform':cform,'pform':pform, 'navtree':navtree.html, 'urls':urls, 'isRealm':c.isRealm, 'isModel':c.isModel, 'isParamGroup':c.isParamGroup, 'cset':cset, 'warning':warning, 'helppaneltitle': helppaneltitle, 'helppaneltext': helppaneltext, 'tabs':tabs(request, self.centre_id, 'Model', self.component.model.id), 'notAjax':not request.is_ajax()})
def __handle(self,request,s,e,url,label): ''' This method handles the form itself for both the add and edit methods ''' logging.debug('entering simulation handle routine') if s.ensembleMembers > 1: eset = s.ensemble_set.all() assert(len(eset)==1, 'There can only be one ensemble set for %s' % s) members = eset[0].ensemblemember_set.all() ensemble = {'set':eset[0], 'members':members} else: ensemble = None urls = {'url':url} if label == 'Update': urls['ic']=reverse('pimmsqn.apps.qn.views.assign', args=(self.centreid,'initialcondition','simulation',s.id,)) urls['bc']=reverse('pimmsqn.apps.qn.views.simulationCup', args=(self.centreid,s.id,)) urls['con']=reverse('pimmsqn.apps.qn.views.conformanceMain', args=(self.centreid,s.id,)) urls['ens']=reverse('pimmsqn.apps.qn.views.ensemble', args=(self.centreid,s.id,)) urls['mod']=reverse('pimmsqn.apps.qn.views.assign', args=(self.centreid,'modelmod','simulation',s.id,)) urls=commonURLs(s,urls) # dont think we should be able to get to input mods from here ... #urls['ics']=reverse('pimmsqn.apps.qn.views.assign', # args=(self.centreid,'inputmod','simulation',s.id,)) # A the moment we're only assuming one related simulation so we don't # have to deal with a formset rsims = s.related_from.all() if len(rsims): r = rsims[0] else: r = None if request.method == 'POST': # do the simualation first ... simform = SimulationForm(request.POST, instance=s, prefix='sim') simform.specialise(self.centre) if simform.is_valid(): simok = True if label == 'Add': oldmodel = None olddrs = None oldstartyear = None else: oldmodel = s.numericalModel olddrs = s.drsMember oldstartyear = s.duration.startDate.year news = simform.save() logging.debug('model before %s, after %s' % (oldmodel, news.numericalModel)) if news.numericalModel != oldmodel: news.resetConformances() news.resetCoupling() news.updateDRS() logging.debug('drs before %s, after %s' % (olddrs, news.drsMember)) # making sure the original sim has a drsoutput if s.drsOutput.all().count() == 0: s.updateDRS() #update the drsouput if drsmember changes or new sim created if news.drsMember != olddrs: news.updateDRS() #update the start year if necessary if news.duration.startDate.year != oldstartyear: news.updateDRS() elif not simform.is_valid(): simok = False logging.info('SIMFORM not valid [%s]' % simform.errors) relform = SimRelationshipForm(s, request.POST, instance=r, prefix='rel') if relform.is_valid(): if simok: r=relform.save() return HttpResponseRedirect(news.edit_url()) else: # if there is no sto, then we should delete this relationship instance and move on. pass #generate a drs string instance in DRS Output class else: relform=SimRelationshipForm(s,instance=r,prefix='rel') simform=SimulationForm(instance=s,prefix='sim') simform.specialise(self.centre) # work out what we want to say about couplings cset=[] if label !='Add': cset=s.numericalModel.couplings(s) for i in cset: i.valid=len(i.internalclosure_set.all())+len(i.externalclosure_set.all()) > 0 # need at least one closure # now work out what we want to say about conformances. cs=Conformance.objects.filter(simulation=s) return render_to_response('simulation.html', {'s':s,'simform':simform,'urls':urls,'label':label,'exp':e, 'cset':cset,'coset':cs,'ensemble':ensemble,'rform':relform, 'tabs':tabs(request,self.centreid,'Simulation',s.id or 0)})
def viewExperiment(request,cen_id,experiment_id): e=Experiment.objects.get(id=experiment_id) r=e.requirements.all() return render_to_response('experiment.html',{'e':e,'reqs':r,'tabs':tabs(request,cen_id,'Experiment')})
def edit(self,request): ''' Provides a form to edit a grid, and handle the posting of a form containing edits for a grid, or a delete''' c=self.grid logging.debug('Starting editing grid %s'%c.id) #TODO; figure out if we want to keep the idea of a 'controlled' grid component, i.e. do we want the #ability to add extra grid components (doubtful) - I've removed the delete capability for now: # find my own urls ... urls={} urls['form']=self.url urls['refs']=reverse('pimmsqn.apps.qn.views.assign',args=(self.centre_id,'reference', 'grid',c.id,)) #urls=commonURLs(c.grid,urls) baseURL=reverse('pimmsqn.apps.qn.views.gridAdd',args=(self.centre_id,)) template='+EDID+' baseURL=baseURL.replace('add/','%s/edit'%template) refs=Reference.objects.filter(grid__id=c.id) postOK=True if request.method=="POST": pform=ParamGroupForm(c,request.POST,prefix='props') pform.newatt=1 cform=GridForm(request.POST,prefix='gen',instance=c) if cform.is_valid(): c=cform.save() c=RemoteUser(request,c) logging.debug('Saving grid %s details (e.g. uri %s)'%(c.id,c.uri)) else: logging.debug('Unable to save characteristics for grid %s'%c.id) postOK=False logging.debug(cform.errors) ok=pform.save() if postOK: postOK=ok # if not postok, ok value doesn't matter # We separate the response handling so we can do some navigation in the # meanwhile ... navtree=gridyuiTree2(c.id,baseURL,template=template) #FIXME; we'll need to put this in the right places with instances: if request.method=='POST': if postOK: #redirect, so repainting the page doesn't resubmit logging.debug('Finished handling post to %s'%c.id) return HttpResponseRedirect(urls['form']) else: pass # don't reset the forms so the user gets an error response. else: #get some forms cform=GridForm(instance=c,prefix='gen') pform=ParamGroupForm(c,prefix='props') pform.newatt=1 logging.debug('Finished handling %s to grid %s'%(request.method,c.id)) return render_to_response('gridMain.html', {'c':c,'cform':cform,'pform':pform, 'navtree':navtree.html,'refs':refs, 'urls':urls, 'tabs':tabs(request,self.centre_id,'Grid',self.grid.topGrid.id), 'notAjax':not request.is_ajax()})
def help(request,cen_id): urls={'vnhist':reverse('pimmsqn.apps.qn.views.vnhist',args=(cen_id,)), 'trans':reverse('pimmsqn.apps.qn.views.trans',args=(cen_id,)),} return render_to_response('help.html',{'urls':urls,'tabs':tabs(request,cen_id,'Help')})
def about(request,cen_id): return render_to_response('about.html',{'tabs':tabs(request,cen_id,'About')})