@@ -8,14 +8,14 services: | |||||
8 | image: madrigal |
|
8 | image: madrigal | |
9 | working_dir: /madrigal/source/madpy/djangoMad |
|
9 | working_dir: /madrigal/source/madpy/djangoMad | |
10 | command: gunicorn djangoMad.wsgi --bind 0.0.0.0:8000 |
|
10 | command: gunicorn djangoMad.wsgi --bind 0.0.0.0:8000 | |
11 |
# command: python manage.py runserver 0.0.0.0:8 |
|
11 | # command: python manage.py runserver 0.0.0.0:8888 | |
12 | env_file: .env |
|
12 | env_file: .env | |
13 | # ports: |
|
13 | # ports: | |
14 |
# - 8 |
|
14 | # - 8888:8888 | |
15 | volumes: |
|
15 | volumes: | |
16 | - '${EXP_DIR}:/madrigal/experiments' |
|
16 | - '${EXP_DIR}:/madrigal/experiments' | |
17 | - '/usr/local/madrigal/metadata:/madrigal/metadata' |
|
17 | # - '/usr/local/madrigal/metadata:/madrigal/metadata' | |
18 |
- '/ |
|
18 | - '/home/jespinoza/workspace/madrigal/source/madpy/djangoMad:/madrigal/source/madpy/djangoMad' | |
19 |
|
19 | |||
20 | nginx: |
|
20 | nginx: | |
21 | container_name: 'madrigal-nginx' |
|
21 | container_name: 'madrigal-nginx' |
@@ -6,6 +6,7 upstream djangomad { | |||||
6 |
|
6 | |||
7 | server { |
|
7 | server { | |
8 | listen 8080; |
|
8 | listen 8080; | |
|
9 | client_max_body_size 50M; | |||
9 |
|
10 | |||
10 | location /madrigal { |
|
11 | location /madrigal { | |
11 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
|
12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
@@ -23,7 +23,7 def login_view(request): | |||||
23 | if user.is_active: |
|
23 | if user.is_active: | |
24 | login(request, user) |
|
24 | login(request, user) | |
25 |
|
25 | |||
26 |
return redirect(' |
|
26 | return redirect(request.GET.get('next')) | |
27 | else: |
|
27 | else: | |
28 | return render(request, "login/login.html" ) |
|
28 | return render(request, "login/login.html" ) | |
29 | else: |
|
29 | else: | |
@@ -35,4 +35,4 def login_view(request): | |||||
35 | def logout_view(request): |
|
35 | def logout_view(request): | |
36 |
|
36 | |||
37 | logout(request) |
|
37 | logout(request) | |
38 |
return redirect(' |
|
38 | return redirect('index') No newline at end of file |
@@ -20,42 +20,24 import madweb.forms | |||||
20 |
|
20 | |||
21 | import datetime, time |
|
21 | import datetime, time | |
22 |
|
22 | |||
23 | def getSelection(keyword, args, kwargs): |
|
|||
24 | """getSelection returns '0' if keyword not a key in either args[0] or kwargs, |
|
|||
25 | otherwise the value |
|
|||
26 |
|
||||
27 | args, kwargs - arguments as passed into SingleExpDefaultForm __init__ |
|
|||
28 | """ |
|
|||
29 | if len(args) == 0 and len(list(kwargs.keys())) == 0: |
|
|||
30 | return('0') # default case when no data passed in |
|
|||
31 | elif len(args) > 0: |
|
|||
32 | # args[0] is data dict argument to bind data |
|
|||
33 | if keyword in args[0]: |
|
|||
34 | return(args[0][keyword]) |
|
|||
35 | else: |
|
|||
36 | return('0') |
|
|||
37 | elif keyword in kwargs: |
|
|||
38 | return(kwargs[keyword]) |
|
|||
39 | elif 'data' in kwargs: |
|
|||
40 | if keyword in kwargs['data']: |
|
|||
41 | return(kwargs['data'][keyword]) |
|
|||
42 | else: |
|
|||
43 | return('0') |
|
|||
44 | else: |
|
|||
45 | return('0') |
|
|||
46 |
|
23 | |||
47 | def getExperimentList(args, kwargs, madWeb, header='Select experiment: '): |
|
24 | def getExperimentList(instrumentId=None): | |
48 |
|
25 | |||
49 | instrumentsId= int(getSelection('instruments', args, kwargs)) |
|
26 | madDB = madrigal.metadata.MadrigalDB() | |
|
27 | madWeb = madrigal.ui.web.MadrigalWeb(madDB) | |||
|
28 | ||||
|
29 | if instrumentId: | |||
|
30 | kinstList = [int(instrumentId)] | |||
|
31 | else: | |||
|
32 | kinstList = [0] | |||
50 |
|
33 | |||
51 | kinstList = [int(instrumentsId)] |
|
|||
52 | startDate = datetime.datetime(1950,1,1) |
|
34 | startDate = datetime.datetime(1950,1,1) | |
53 | startDT = datetime.datetime(startDate.year, startDate.month, startDate.day, 0, 0, 0) |
|
35 | startDT = datetime.datetime(startDate.year, startDate.month, startDate.day, 0, 0, 0) | |
54 | now = datetime.datetime.now() |
|
36 | now = datetime.datetime.now() | |
55 | endDate = datetime.datetime(now.year, 12, 31, 23, 59, 59) |
|
37 | endDate = datetime.datetime(now.year, 12, 31, 23, 59, 59) | |
56 | endDT = datetime.datetime(endDate.year, endDate.month, endDate.day, 23, 59, 59) |
|
38 | endDT = datetime.datetime(endDate.year, endDate.month, endDate.day, 23, 59, 59) | |
57 | experiments = madWeb.getExperimentList(kinstList,startDT, endDT, True) |
|
39 | experiments = madWeb.getExperimentList(kinstList,startDT, endDT, True) | |
58 |
expListin = [('0', |
|
40 | expListin = [('0', 'Select experiment: '),] | |
59 | for exp in experiments: |
|
41 | for exp in experiments: | |
60 | expListin.append((exp[0], exp[2])) |
|
42 | expListin.append((exp[0], exp[2])) | |
61 |
|
43 | |||
@@ -68,31 +50,49 def getExperimentList(args, kwargs, madWeb, header='Select experiment: '): | |||||
68 |
|
50 | |||
69 | return(expList) |
|
51 | return(expList) | |
70 |
|
52 | |||
|
53 | def getInstrumentList(): | |||
|
54 | ||||
|
55 | madDB = madrigal.metadata.MadrigalDB() | |||
|
56 | madInstData = madrigal.metadata.MadrigalInstrumentData(madDB) | |||
|
57 | instruments = madInstData.getInstruments(0, True) | |||
|
58 | instList = [('0', "Select Instrument"), ] | |||
|
59 | for kinst, instDesc, siteID in instruments: | |||
|
60 | instList.append((str(kinst), instDesc)) | |||
|
61 | ||||
|
62 | return(instList) | |||
|
63 | ||||
71 | class UpdataForm(forms.Form): |
|
64 | class UpdataForm(forms.Form): | |
72 | def __init__(self, *args, **kwargs): |
|
|||
73 | super(UpdataForm, self).__init__(*args, **kwargs) |
|
|||
74 | madDB = madrigal.metadata.MadrigalDB() |
|
|||
75 | madInstData = madrigal.metadata.MadrigalInstrumentData(madDB) |
|
|||
76 | instruments = madInstData.getInstruments(0, True) |
|
|||
77 | instList = [('0', "Select Instrument"), ] |
|
|||
78 | for kinst, instDesc, siteID in instruments: |
|
|||
79 | instList.append((str(kinst), instDesc)) |
|
|||
80 |
|
65 | |||
81 | instrumentSelection = getSelection('instruments', args, kwargs) |
|
66 | CHOICES=[('new','New Instrument/Experiment'), | |
82 | self.fields['instruments'] = django.forms.ChoiceField(widget = django.forms.Select(attrs={"onChange":'populateExp(this)'}), |
|
67 | ('existing','Existing')] | |
83 | choices=instList, |
|
68 | choose = forms.ChoiceField( | |
84 | initial=instrumentSelection, |
|
69 | choices=CHOICES, | |
85 | label='Instrument:') |
|
70 | widget=forms.RadioSelect(attrs={'class': 'custom-radio', 'onClick': 'updateRadio(this);'}), | |
86 |
|
71 | initial='existing') | ||
87 | madWebObj = madrigal.ui.web.MadrigalWeb(madDB) |
|
72 | inst = forms.IntegerField(min_value=1, label='Instrument ID:', disabled=True, required=False) | |
88 | experimentSelection = getSelection('experiments', args, kwargs) |
|
73 | exp = forms.CharField(max_length=40, label='Experiment Title:', disabled=True, required=False) | |
89 | self.fields['experiments'] = django.forms.ChoiceField(choices=getExperimentList(args, kwargs, madWebObj), |
|
74 | instruments = forms.ChoiceField( | |
90 | initial=experimentSelection, |
|
75 | widget = django.forms.Select(attrs={"onChange":'populateExp(this);'}), | |
91 | required=False, label='Experiment:') |
|
76 | choices=getInstrumentList(), | |
92 |
|
77 | required=False, | ||
93 | description = forms.CharField(widget=forms.Textarea(attrs={'cols': 40,'rows': 3, 'style': 'resize:none'}), label='Description') |
|
78 | label='Instruments:') | |
94 | type = forms.ChoiceField(choices=[('0', 'Public'),('1', 'Private')], initial=0,widget=forms.RadioSelect(attrs={'class': 'custom-radio'})) |
|
79 | ||
95 | file = forms.FileField(label='Select Files', widget=forms.ClearableFileInput(attrs={'multiple': True})) |
|
80 | experiments = forms.ChoiceField( | |
|
81 | choices=[], | |||
|
82 | required=False, | |||
|
83 | label='Experiments:') | |||
|
84 | permission = forms.ChoiceField( | |||
|
85 | choices=[('0', 'Public'),('1', 'Private')], | |||
|
86 | initial=0, | |||
|
87 | widget=forms.RadioSelect(attrs={'class': 'custom-radio'})) | |||
|
88 | description = forms.CharField( | |||
|
89 | widget=forms.Textarea(attrs={'cols': 40,'rows': 3, 'style': 'resize:none'}), | |||
|
90 | required=False, | |||
|
91 | label='Description') | |||
|
92 | optchar = forms.CharField(max_length=1, label='Optional Char:', required=False) | |||
|
93 | file = forms.FileField( | |||
|
94 | label='Select Files', | |||
|
95 | widget=forms.ClearableFileInput(attrs={'multiple': True})) | |||
96 |
|
96 | |||
97 | class ExpForm(forms.Form): |
|
97 | class ExpForm(forms.Form): | |
98 | """SingleExpInstForm is a Form class for the instrument select field in the Single Experiment interface. |
|
98 | """SingleExpInstForm is a Form class for the instrument select field in the Single Experiment interface. | |
@@ -100,9 +100,7 class ExpForm(forms.Form): | |||||
100 | """ |
|
100 | """ | |
101 | def __init__(self, *args, **kwargs): |
|
101 | def __init__(self, *args, **kwargs): | |
102 | super(ExpForm, self).__init__(*args, **kwargs) |
|
102 | super(ExpForm, self).__init__(*args, **kwargs) | |
103 | madDB = madrigal.metadata.MadrigalDB() |
|
103 | self.fields['experiments'] = forms.ChoiceField( | |
104 | madWebObj = madrigal.ui.web.MadrigalWeb(madDB) |
|
104 | choices=getExperimentList(args[0]['instrument']), | |
105 | experimentSelection = getSelection('experiments', args, kwargs) |
|
105 | # initial=kwargs['exp'], | |
106 | self.fields['experiments'] = django.forms.ChoiceField(choices=getExperimentList(args, kwargs, madWebObj), |
|
106 | required=False, label='Experiments') | |
107 | initial=experimentSelection, |
|
|||
108 | required=False, label='Experiment') |
|
@@ -1,6 +1,4 | |||||
1 | <div class="row"> |
|
1 | ||
2 | {{ form.experiments.label }} |
|
|||
3 | </div> |
|
|||
4 | <!-- Instrument select is its own row in selections column --> |
|
2 | <!-- Instrument select is its own row in selections column --> | |
5 | <div class="row"> |
|
3 | <div class="row"> | |
6 | <div class="col-md-12"> |
|
4 | <div class="col-md-12"> |
@@ -6,14 +6,31 | |||||
6 | function populateExp(select) { |
|
6 | function populateExp(select) { | |
7 |
|
7 | |||
8 | var kinst = select.options[select.selectedIndex].value; |
|
8 | var kinst = select.options[select.selectedIndex].value; | |
9 |
var url = "{% url 'updata:get_experiments' %}" + '?instrument |
|
9 | var url = "{% url 'updata:get_experiments' %}" + '?instrument=' + kinst; | |
10 | // first delete all forms that are now out of date |
|
10 | // first delete all forms that are now out of date | |
11 | divIndex = $(".single_form").index($("#experiments")) |
|
11 | //divIndex = $(".single_form").index($("#id_experiments")) | |
12 | $(".single_form").slice(divIndex).empty() |
|
12 | //$(".single_form").slice(divIndex).empty() | |
13 | // second populate the categories html |
|
13 | // second populate the categories html | |
14 |
|
|
14 | //$(".single_form").slice(divIndex, divIndex + 1).load(url); | |
|
15 | $("#id_experiments").load(url); | |||
15 | } |
|
16 | } | |
16 |
|
17 | |||
|
18 | function updateRadio(myRadio) { | |||
|
19 | if (myRadio.value == 'new') { | |||
|
20 | $( "#id_exp" ).prop( "disabled", false ); | |||
|
21 | $( "#id_inst" ).prop( "disabled", false ); | |||
|
22 | $( "#id_experiments" ).prop( "disabled", true ); | |||
|
23 | $( "#id_instruments" ).prop( "disabled", true ); | |||
|
24 | } else { | |||
|
25 | $( "#id_exp" ).prop( "disabled", true ); | |||
|
26 | $( "#id_inst" ).prop( "disabled", true ); | |||
|
27 | $( "#id_experiments" ).prop( "disabled", false ); | |||
|
28 | $( "#id_instruments" ).prop( "disabled", false ); | |||
|
29 | } | |||
|
30 | ||||
|
31 | } | |||
|
32 | ||||
|
33 | ||||
17 | </script> |
|
34 | </script> | |
18 |
|
35 | |||
19 | <style> |
|
36 | <style> | |
@@ -22,6 +39,10 | |||||
22 | margin: 0; |
|
39 | margin: 0; | |
23 | padding: 0; |
|
40 | padding: 0; | |
24 | } |
|
41 | } | |
|
42 | ||||
|
43 | .errorlist { | |||
|
44 | color: red; | |||
|
45 | } | |||
25 | </style> |
|
46 | </style> | |
26 | {% endblock %} |
|
47 | {% endblock %} | |
27 |
|
48 | |||
@@ -32,70 +53,7 | |||||
32 |
|
53 | |||
33 | {% csrf_token %} |
|
54 | {% csrf_token %} | |
34 |
|
55 | |||
35 | {% block description %} |
|
56 | {{ form.as_p }} | |
36 | <!-- subdivide selection column for instruments to be possibly filled in by ajax - single_form 0 --> |
|
|||
37 | <div class="col-md-12 single_form" id="description"> |
|
|||
38 | <div class="row"> |
|
|||
39 | {{ form.description.label }} |
|
|||
40 | </div> |
|
|||
41 | <!-- Instrument select is its own row in selections column --> |
|
|||
42 | <div class="row"> |
|
|||
43 | <div class="col-md-12"> |
|
|||
44 | {{ form.description }} |
|
|||
45 | </div> <!-- end span --> |
|
|||
46 | </div> <!-- end row --> |
|
|||
47 | </div> <!-- end subdivide --> |
|
|||
48 |
|
||||
49 | {% endblock %} |
|
|||
50 |
|
||||
51 | {% block file %} |
|
|||
52 | <div class="col-md-12 single_form" style="margin-top: 15px;" id="description"> |
|
|||
53 | <div class="row"> |
|
|||
54 | {{ form.file.label }} |
|
|||
55 | </div> |
|
|||
56 | <!-- Instrument select is its own row in selections column --> |
|
|||
57 | <div class="row"> |
|
|||
58 | <div class="col-md-12"> |
|
|||
59 | {{ form.file }} |
|
|||
60 | </div> <!-- end span --> |
|
|||
61 | </div> <!-- end row --> |
|
|||
62 | </div> <!-- end subdivide --> |
|
|||
63 |
|
||||
64 | {% endblock %} |
|
|||
65 |
|
||||
66 | {% block type %} |
|
|||
67 | <div class="col-md-12 single_form" style="margin-top: 15px;" id="description"> |
|
|||
68 | <!-- Instrument select is its own row in selections column --> |
|
|||
69 | <div class="row"> |
|
|||
70 | <div class="col-md-12"> |
|
|||
71 | {{ form.type }} |
|
|||
72 | </div> <!-- end span --> |
|
|||
73 | </div> <!-- end row --> |
|
|||
74 | </div> <!-- end subdivide --> |
|
|||
75 |
|
||||
76 | {% endblock %} |
|
|||
77 |
|
||||
78 | {% block instruments %} |
|
|||
79 | <!-- subdivide selection column for instruments to be possibly filled in by ajax - single_form 0 --> |
|
|||
80 | <div class="col-md-12 single_form" style="margin-top: 15px;" id="instruments"> |
|
|||
81 |
|
||||
82 | {% if form.instruments %} |
|
|||
83 | {% include "madweb/instruments.html" %} |
|
|||
84 | {% endif %} |
|
|||
85 |
|
||||
86 | </div> <!-- end subdivide --> |
|
|||
87 | {% endblock %} |
|
|||
88 |
|
||||
89 | {% block experiments %} |
|
|||
90 | <!-- subdivide selection column for experiments to be possibly filled in by ajax - single_form 0 --> |
|
|||
91 | <div class="col-md-12 single_form" style="margin-top: 15px;" id="experiments"> |
|
|||
92 |
|
||||
93 | {% if form.experiments %} |
|
|||
94 | {% include "updata/experiments.html" %} |
|
|||
95 | {% endif %} |
|
|||
96 |
|
||||
97 | </div> <!-- end subdivide --> |
|
|||
98 | {% endblock %} |
|
|||
99 | <button style="margin-top: 15px;" type="submit">Load</button> |
|
57 | <button style="margin-top: 15px;" type="submit">Load</button> | |
100 |
|
58 | |||
101 | </form> |
|
59 | </form> |
@@ -1,7 +1,7 | |||||
1 |
|
1 | |||
2 | from django.contrib.auth.decorators import login_required |
|
2 | from django.contrib.auth.decorators import login_required | |
3 | from django.shortcuts import render |
|
3 | from django.shortcuts import render | |
4 | from .forms import UpdataForm, ExpForm |
|
4 | from apps.updata.forms import UpdataForm, ExpForm | |
5 | from django.core.files.storage import FileSystemStorage |
|
5 | from django.core.files.storage import FileSystemStorage | |
6 | from django.contrib import messages |
|
6 | from django.contrib import messages | |
7 |
|
7 | |||
@@ -22,45 +22,77 def index(request): | |||||
22 | madDB = madrigal.metadata.MadrigalDB() |
|
22 | madDB = madrigal.metadata.MadrigalDB() | |
23 | madWebObj = madrigal.ui.web.MadrigalWeb(madDB) |
|
23 | madWebObj = madrigal.ui.web.MadrigalWeb(madDB) | |
24 | siteName, siteList = madWebObj.getSiteInfo() |
|
24 | siteName, siteList = madWebObj.getSiteInfo() | |
25 |
|
25 | err = False | ||
26 | if request.method == 'POST': |
|
26 | if request.method == 'POST': | |
27 | form = UpdataForm(request.POST, request.FILES) |
|
27 | form = UpdataForm(request.POST, request.FILES) | |
28 | files = request.FILES.getlist('file') |
|
28 | files = request.FILES.getlist('file') | |
|
29 | files.sort() | |||
|
30 | filenames = [] | |||
|
31 | ||||
|
32 | choose = request.POST.get('choose') | |||
|
33 | if choose == 'new': | |||
|
34 | instCode = int(request.POST.get('inst')) | |||
|
35 | expTitle = request.POST.get('exp') | |||
|
36 | else: | |||
|
37 | instCode = int(request.POST.get('instruments')) | |||
|
38 | expId = request.POST.get('experiments') | |||
|
39 | madExp = madrigal.metadata.MadrigalExperiment() | |||
|
40 | expTitle = madExp.getExpNameByExpId(expId) | |||
29 |
|
41 | |||
30 | if form.is_valid(): |
|
42 | description = request.POST.get('description') | |
31 | try: |
|
43 | perm = int(request.POST.get('permission')) | |
32 | description = form.cleaned_data['description'] |
|
44 | optchar = request.POST.get('optchar').strip() | |
33 | instCode = int(form.cleaned_data['instruments']) |
|
45 | first = True | |
34 | expId = form.cleaned_data['experiments'] |
|
46 | for f in files: | |
35 | perm = int(form.cleaned_data['type']) |
|
47 | fs = FileSystemStorage(location='/tmp') | |
36 |
|
48 | fs.save(f.name, f) | ||
37 | #saving file |
|
49 | filename = os.path.join('/tmp', f.name) | |
38 | for f in files: |
|
50 | ext = filename.split('.')[-1] | |
39 | fs = FileSystemStorage(location='/tmp') |
|
51 | if ext not in ('hdf5', 'h5'): | |
40 | fs.save(f.name, f) |
|
52 | convert = True | |
41 | madExp = madrigal.metadata.MadrigalExperiment() |
|
53 | else: | |
42 | filepath = os.path.join('/tmp', f.name) |
|
54 | convert = False | |
43 | expTitle = madExp.getExpNameByExpId(expId) |
|
55 | ||
44 |
|
|
56 | if first: | |
45 | dbAdminObj.createMadrigalExperiment(filepath,expTitle, perm, description, instCode) |
|
57 | first = False | |
46 |
|
|
58 | try: | |
|
59 | expDir = dbAdminObj.createMadrigalExperiment(filename, expTitle, perm, description, | |||
|
60 | instCode, optChar=optchar, updateToMad3=convert) | |||
|
61 | except Exception as e: | |||
|
62 | err = True | |||
|
63 | messages.error(request, | |||
|
64 | 'An error occur creating the experiment {}: {}'.format(expTitle, e) | |||
|
65 | ) | |||
|
66 | break | |||
|
67 | else: | |||
|
68 | try: | |||
|
69 | dbAdminObj.addMadrigalFile(expDir, filename, perm, description, updateToMad3=convert) | |||
|
70 | except Exception as e: | |||
|
71 | err = True | |||
|
72 | messages.error(request, | |||
|
73 | 'An error occur adding file {}: {}'.format(filename.split('/')[-1], e) | |||
|
74 | ) | |||
|
75 | ||||
|
76 | filenames.append(filename.split('/')[-1]) | |||
|
77 | os.remove(filename) | |||
|
78 | ||||
|
79 | if not err: | |||
|
80 | messages.success(request, | |||
|
81 | 'Experiment {} created succesfully with files: {}'.format(expTitle, filenames) | |||
|
82 | ) | |||
|
83 | ||||
|
84 | madInstParams = madrigal.metadata.MadrigalInstrumentParameters() | |||
|
85 | madInstKindats = madrigal.metadata.MadrigalInstrumentKindats() | |||
|
86 | ||||
|
87 | print('*** Updating local metadata ***') | |||
|
88 | dbAdminObj.__updateLocalMetadata__() | |||
|
89 | print('*** Rebuilding instParmTab.txt ***') | |||
|
90 | madInstParams.rebuildInstParmTable() | |||
|
91 | print('*** Rebuilding instKindatTab.txt ***') | |||
|
92 | madInstKindats.rebuildInstKindatTable() | |||
|
93 | ||||
|
94 | form = UpdataForm() | |||
47 |
|
95 | |||
48 | madInstParams = madrigal.metadata.MadrigalInstrumentParameters() |
|
|||
49 | madInstKindats = madrigal.metadata.MadrigalInstrumentKindats() |
|
|||
50 |
|
||||
51 | print('*** Updating local metadata ***') |
|
|||
52 | dbAdminObj.__updateLocalMetadata__() |
|
|||
53 | print('*** Rebuilding instParmTab.txt ***') |
|
|||
54 | madInstParams.rebuildInstParmTable() |
|
|||
55 | print('*** Rebuilding instKindatTab.txt ***') |
|
|||
56 | madInstKindats.rebuildInstKindatTable() |
|
|||
57 | messages.success( |
|
|||
58 | request, 'Experimento(s) creado(s) exitosamente') |
|
|||
59 | form = UpdataForm() |
|
|||
60 |
|
||||
61 | except Exception as e: |
|
|||
62 | messages.error( |
|
|||
63 | request, str(e)) |
|
|||
64 | else: |
|
96 | else: | |
65 | form = UpdataForm() |
|
97 | form = UpdataForm() | |
66 |
|
98 |
General Comments 0
You need to be logged in to leave comments.
Login now