Compare commits
67 commits
Author | SHA1 | Date | |
---|---|---|---|
44bab85ba7 | |||
|
3b30b9666a | ||
|
30f0743c41 | ||
|
db54e3c3d7 | ||
|
d7199827da | ||
|
0574694d38 | ||
|
f88a037edc | ||
|
bfe6fe610a | ||
|
19b115434f | ||
|
674ab5d288 | ||
|
2c870df36c | ||
|
929d279b24 | ||
|
127a9ab8ec | ||
|
b7dfb676ec | ||
|
079762250b | ||
|
c7b525875d | ||
|
4734789a25 | ||
|
3a5cbc6325 | ||
|
a80158da66 | ||
|
5326ea7ab0 | ||
|
854ce75993 | ||
|
02aaccffed | ||
|
5e50d3320e | ||
|
0140a65602 | ||
|
8f2f8b86e2 | ||
|
e798679c6c | ||
f85846cd48 | |||
|
0123fd2eef | ||
|
3eb5ba12d9 | ||
|
bc4061f12a | ||
|
4cc03b6372 | ||
|
00c03e7bec | ||
|
600ae8e5de | ||
|
13b7918de1 | ||
|
a91d2b16b6 | ||
|
5b64c4ee15 | ||
|
5446daa87f | ||
48a2585829 | |||
2c4fb66176 | |||
|
f960c4e779 | ||
|
3b9498d13d | ||
|
7fd30a5dcd | ||
|
c5bfc46e33 | ||
b7f8e237fa | |||
c84ae636c5 | |||
8e409d1a38 | |||
808f1d94bb | |||
9dc9daa1e0 | |||
e8f8ee8ad3 | |||
d436650d2c | |||
e9ec1909b4 | |||
0136386ad0 | |||
cc66cfd4d8 | |||
dffd00d8cb | |||
7efa5b3741 | |||
|
f2d27bd791 | ||
|
202b6c0092 | ||
907ae0c256 | |||
|
2c83c3e322 | ||
|
f272481bf6 | ||
|
5b7e4eed3e | ||
|
da8fba3497 | ||
|
2dda215ffe | ||
|
401b554a1c | ||
|
27ecafa887 | ||
|
a0c3dd57dd | ||
|
41a2129e9a |
19 changed files with 650 additions and 114 deletions
35
Changelog.md
35
Changelog.md
|
@ -1,5 +1,40 @@
|
|||
# CHANGELOG.md
|
||||
|
||||
## 2.1 (2022-09-29)
|
||||
- issue#11013: non-public entries appearing as public
|
||||
|
||||
## 2.0 (2022-09-19) Dockerify https://redmine.ungleich.ch/issues/10884
|
||||
|
||||
Steps:
|
||||
- Create .env.prod and .env.prod.db files
|
||||
|
||||
#### .env.prod
|
||||
```
|
||||
DEBUG=0
|
||||
SECRET_KEY=secret_key_here
|
||||
DJANGO_SETTINGS_MODULE=gmba_django.settings.production
|
||||
ALLOWED_HOSTS=localhost,127.0.0.1,[::1]
|
||||
POSTGRES_USER=user
|
||||
POSTGRES_PASSWORD=password
|
||||
POSTGRES_DB=app
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_PORT=5432
|
||||
```
|
||||
|
||||
Building containers
|
||||
- docker-compose -f docker-compose.prod.yml down -v --remove-orphans
|
||||
- docker-compose -f docker-compose.prod.yml up -d --build
|
||||
|
||||
Copy db and adust
|
||||
- docker cp gd.sql gmba_django_db_1:/gd.sql
|
||||
- docker-compose exec db psql --username=psql_username_name --dbname=psql_db_name < /gd.sql
|
||||
|
||||
Migrate / check
|
||||
- docker-compose exec web python manage.py migrate --noinput
|
||||
|
||||
Static resources
|
||||
- docker-compose -f docker-compose.prod.yml exec web python manage.py collectstatic --no-input --clear
|
||||
|
||||
## 1.12 (2022-01-19)
|
||||
|
||||
Bugfixes:
|
||||
|
|
85
Dockerfile.prod
Normal file
85
Dockerfile.prod
Normal file
|
@ -0,0 +1,85 @@
|
|||
###########
|
||||
# BUILDER #
|
||||
###########
|
||||
|
||||
# pull official base image
|
||||
FROM python:3.9.6-alpine as builder
|
||||
|
||||
# set work directory
|
||||
WORKDIR /usr/src/gmba_django
|
||||
|
||||
# set environment variables
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
# install psycopg2 dependencies
|
||||
RUN apk update \
|
||||
&& apk add postgresql-dev gcc python3-dev musl-dev
|
||||
|
||||
# lint
|
||||
RUN pip install --upgrade pip
|
||||
RUN pip install flake8==3.9.2
|
||||
COPY . .
|
||||
#RUN flake8 --ignore=E501,F401 .
|
||||
|
||||
# install dependencies
|
||||
COPY ./requirements.txt .
|
||||
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/gmba_django/wheels -r requirements.txt
|
||||
|
||||
|
||||
#########
|
||||
# FINAL #
|
||||
#########
|
||||
|
||||
# pull official base image
|
||||
FROM python:3.9.6-alpine
|
||||
|
||||
# create directory for the app user
|
||||
RUN mkdir -p /home/app
|
||||
|
||||
# create the app user
|
||||
RUN addgroup -S app && adduser -S app -G app
|
||||
|
||||
# create the appropriate directories
|
||||
ENV HOME=/home/app
|
||||
ENV APP_HOME=/home/app/gmba_django
|
||||
RUN mkdir $APP_HOME
|
||||
RUN mkdir $APP_HOME/static
|
||||
RUN mkdir $APP_HOME/media
|
||||
|
||||
#ADD gmba_django /data/app
|
||||
|
||||
#WORKDIR /data/app/gmba_django
|
||||
|
||||
# install dependencies
|
||||
RUN apk update && apk add libpq
|
||||
COPY --from=builder /usr/src/gmba_django/wheels /wheels
|
||||
COPY --from=builder /usr/src/gmba_django/requirements.txt .
|
||||
RUN pip install --no-cache /wheels/*
|
||||
|
||||
# copy entrypoint.prod.sh
|
||||
COPY ./entrypoint.prod.sh /entrypoint.prod.sh
|
||||
COPY ./init.sh /init.sh
|
||||
RUN sed -i 's/\r$//g' /entrypoint.prod.sh
|
||||
RUN chmod +x /entrypoint.prod.sh
|
||||
|
||||
# copy project
|
||||
#COPY . $APP_HOME
|
||||
|
||||
ADD . /home/app/gmba_django
|
||||
WORKDIR /home/app/gmba_django
|
||||
|
||||
# chown all the files to the app user
|
||||
RUN chown -R app:app $APP_HOME
|
||||
|
||||
# change to the app user
|
||||
USER app
|
||||
|
||||
#RUN python manage.py collectstatic --noinput
|
||||
|
||||
# run entrypoint.prod.sh
|
||||
ENTRYPOINT ["/entrypoint.prod.sh"]
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["gunicorn", "--bind", "[::]:8000", "--chdir", "/home/app/gmba_django", "--workers", "3", "gmba_django.wsgi:application"]
|
206
app/admin.py
206
app/admin.py
|
@ -1,8 +1,53 @@
|
|||
from re import A
|
||||
from unicodedata import name
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from .models import *
|
||||
from django.forms import TextInput
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse
|
||||
import csv
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import AutocompleteSelect
|
||||
from django.contrib import messages # import messages
|
||||
|
||||
|
||||
class autocomplete_fields_form(forms.ModelForm):
|
||||
"""This form overrides autocomplete
|
||||
organization field for Person class
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(autocomplete_fields_form, self).__init__(*args, **kwargs)
|
||||
|
||||
# self.fields['organization'].label = 'My new label'
|
||||
|
||||
class Meta:
|
||||
model = Person
|
||||
fields = '__all__'
|
||||
widgets = {
|
||||
'organization': forms.Select(attrs={'style': 'width:750px'})
|
||||
}
|
||||
|
||||
|
||||
def download_csv(modeladmin, request, queryset):
|
||||
name = queryset[0].__class__.__name__
|
||||
response = HttpResponse()
|
||||
response['Content-Disposition'] = "attachment; filename="+name+"_table.csv"
|
||||
first_row = []
|
||||
for i in queryset[0]._meta.__dict__.get("fields"):
|
||||
temp = str(i).split('.')
|
||||
first_row.append(temp[-1])
|
||||
|
||||
writer = csv.writer(response)
|
||||
writer.writerow(first_row)
|
||||
for dic in queryset.values():
|
||||
temp_list = (list(dic.values()))
|
||||
writer.writerow(temp_list)
|
||||
return response
|
||||
|
||||
|
||||
download_csv.short_description = 'export (.csv)'
|
||||
|
||||
|
||||
class PeopleResourceInline(admin.TabularInline):
|
||||
|
@ -23,12 +68,13 @@ class PersonAdmin(admin.ModelAdmin):
|
|||
PeopleRangeInline
|
||||
]
|
||||
readonly_fields = ['id']
|
||||
search_fields = ['title', 'first_name', 'last_name', 'organisation', 'position', 'country__short_name', 'contact_email']
|
||||
search_fields = ['title', 'first_name', 'last_name', 'organisation',
|
||||
'position', 'country__short_name', 'contact_email']
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': (
|
||||
('id', 'profile_on_web', 'news_letter'),
|
||||
('mr_mrs', 'title','full_name', 'position'),
|
||||
('mr_mrs', 'title', 'full_name', 'position'),
|
||||
('first_name', 'last_name', 'search_name', 'status'),
|
||||
('contact_email', 'email_2', 'skype', 'professional_phone'),
|
||||
'organization',
|
||||
|
@ -40,7 +86,7 @@ class PersonAdmin(admin.ModelAdmin):
|
|||
('Research Scale', {
|
||||
'classes': ('collapse',),
|
||||
'fields': (('field_site', 'transect', 'mountain_top', 'mountain_range', 'landscape', 'regional', 'national',),
|
||||
'_global'),
|
||||
'_global'),
|
||||
}),
|
||||
('Methods and tools', {
|
||||
'classes': ('collapse',),
|
||||
|
@ -64,10 +110,95 @@ class PersonAdmin(admin.ModelAdmin):
|
|||
}),
|
||||
)
|
||||
list_display = ['id', 'full_name', 'organization']
|
||||
autocomplete_fields = ['organization']
|
||||
|
||||
#autocomplete_fields = ['organization']
|
||||
form = autocomplete_fields_form # adjust width of autocomplete_fields organization
|
||||
|
||||
list_per_page = settings.ADMIN_LIST_PER_PAGE
|
||||
ordering = ['full_name']
|
||||
# list_display_links = ['id']
|
||||
actions = [download_csv]
|
||||
|
||||
def get_field_queryset(self, db, db_field, request):
|
||||
queryset = super().get_field_queryset(db, db_field, request)
|
||||
if db_field.name == 'organization':
|
||||
queryset = queryset.order_by(
|
||||
'country', 'organisation_english', 'organisation_2', 'organisation_3', 'acronym')
|
||||
return queryset
|
||||
|
||||
def get_actions(self, request):
|
||||
actions = super().get_actions(request)
|
||||
if 'delete_selected' in actions:
|
||||
del actions['delete_selected']
|
||||
return actions
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
self.delete_person(request, obj)
|
||||
return super(PersonAdmin, self).delete_model(request, obj)
|
||||
|
||||
def delete_person(self, request, obj):
|
||||
taxa_people = TaxaPeople.objects.filter(person=obj.id)
|
||||
for i in taxa_people:
|
||||
i.delete()
|
||||
ranges_people = RangesPeople.objects.filter(person=obj.id)
|
||||
for i in ranges_people:
|
||||
i.delete()
|
||||
resources_people = ResourcesPeople.objects.filter(person=obj.id)
|
||||
for i in resources_people:
|
||||
i.delete()
|
||||
scales_people = ScalesPeople.objects.filter(person=obj.id)
|
||||
for i in scales_people:
|
||||
i.delete()
|
||||
people_function = PeopleFunction.objects.filter(person=obj.id)
|
||||
for i in people_function:
|
||||
i.delete()
|
||||
people_range = PeopleRange.objects.filter(person=obj.id)
|
||||
for i in people_range:
|
||||
i.delete()
|
||||
people_resources = PeopleResource.objects.filter(person=obj.id)
|
||||
for i in people_resources:
|
||||
i.delete()
|
||||
fields_people = FieldsPeople.objects.filter(person=obj.id)
|
||||
for i in fields_people:
|
||||
i.delete()
|
||||
methods_people = MethodsPeople.objects.filter(person=obj.id)
|
||||
for i in methods_people:
|
||||
i.delete()
|
||||
|
||||
def delete_persons(self, request, obj):
|
||||
for o in obj.all():
|
||||
taxa_people = TaxaPeople.objects.filter(person=o.id)
|
||||
for i in taxa_people:
|
||||
i.delete()
|
||||
ranges_people = RangesPeople.objects.filter(person=o.id)
|
||||
for i in ranges_people:
|
||||
i.delete()
|
||||
resources_people = ResourcesPeople.objects.filter(person=o.id)
|
||||
for i in resources_people:
|
||||
i.delete()
|
||||
scales_people = ScalesPeople.objects.filter(person=o.id)
|
||||
for i in scales_people:
|
||||
i.delete()
|
||||
people_function = PeopleFunction.objects.filter(person=o.id)
|
||||
for i in people_function:
|
||||
i.delete()
|
||||
people_range = PeopleRange.objects.filter(person=o.id)
|
||||
for i in people_range:
|
||||
i.delete()
|
||||
people_resources = PeopleResource.objects.filter(person=o.id)
|
||||
for i in people_resources:
|
||||
i.delete()
|
||||
fields_people = FieldsPeople.objects.filter(person=o.id)
|
||||
for i in fields_people:
|
||||
i.delete()
|
||||
methods_people = MethodsPeople.objects.filter(person=o.id)
|
||||
for i in methods_people:
|
||||
i.delete()
|
||||
o.delete()
|
||||
messages.success(request, "Successfully deleted")
|
||||
|
||||
delete_persons.short_description = 'Delete Person & Related Fields'
|
||||
|
||||
actions = [download_csv, delete_persons]
|
||||
|
||||
|
||||
class ResourceKeywordInline(admin.TabularInline):
|
||||
|
@ -131,6 +262,52 @@ class ResourceAdmin(admin.ModelAdmin):
|
|||
)
|
||||
list_per_page = settings.ADMIN_LIST_PER_PAGE
|
||||
|
||||
def get_actions(self, request):
|
||||
actions = super().get_actions(request)
|
||||
if 'delete_selected' in actions:
|
||||
del actions['delete_selected']
|
||||
return actions
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
self.delete_resource(request, obj)
|
||||
return super(ResourceAdmin, self).delete_model(request, obj)
|
||||
|
||||
def delete_resource(self, request, obj):
|
||||
resource_keyword = ResourceKeyword.objects.filter(resource=obj.id)
|
||||
for i in resource_keyword:
|
||||
i.delete()
|
||||
resource_range = ResourceRange.objects.filter(resource_title=obj.id)
|
||||
for i in resource_range:
|
||||
i.delete()
|
||||
resource_people = ResourcesPeople.objects.filter(resource=obj.id)
|
||||
for i in resource_people:
|
||||
i.delete()
|
||||
resource_people_resource = PeopleResource.objects.filter(
|
||||
resource=obj.id)
|
||||
for i in resource_people_resource:
|
||||
i.delete()
|
||||
|
||||
def delete_resources(self, request, obj):
|
||||
for o in obj.all():
|
||||
resource_keyword = ResourceKeyword.objects.filter(resource=o.id)
|
||||
for i in resource_keyword:
|
||||
i.delete()
|
||||
resource_range = ResourceRange.objects.filter(resource_title=o.id)
|
||||
for i in resource_range:
|
||||
i.delete()
|
||||
resource_people = ResourcesPeople.objects.filter(resource=o.id)
|
||||
for i in resource_people:
|
||||
i.delete()
|
||||
resource_people_resource = PeopleResource.objects.filter(
|
||||
resource=o.id)
|
||||
for i in resource_people_resource:
|
||||
i.delete()
|
||||
o.delete()
|
||||
messages.success(request, "Successfully deleted")
|
||||
delete_resources.short_description = 'Delete Resource & Related Fields'
|
||||
|
||||
actions = [download_csv, delete_resources]
|
||||
|
||||
|
||||
class RangeNameTranslationInline(admin.TabularInline):
|
||||
autocomplete_fields = ['language_translation']
|
||||
|
@ -185,6 +362,8 @@ class RangeAdmin(admin.ModelAdmin):
|
|||
ordering = ['range_name']
|
||||
list_per_page = settings.ADMIN_LIST_PER_PAGE
|
||||
|
||||
actions = [download_csv]
|
||||
|
||||
|
||||
class PeopleOrganizationInline(admin.TabularInline):
|
||||
model = Person
|
||||
|
@ -197,15 +376,17 @@ class OrganizationAdmin(admin.ModelAdmin):
|
|||
PeopleOrganizationInline,
|
||||
]
|
||||
readonly_fields = ('org_num1',)
|
||||
search_fields = ['organisation_search', 'org_alpha_search', 'organisation_2', 'organisation_3', 'subject']
|
||||
list_display = ['org_num1', 'organisation_english', 'organisation_2', 'country']
|
||||
search_fields = ['organisation_search', 'org_alpha_search',
|
||||
'organisation_2', 'organisation_3', 'subject', 'organisation_english']
|
||||
list_display = ['org_num1', 'organisation_english',
|
||||
'organisation_2', 'country']
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': (
|
||||
'org_num1',
|
||||
('acronym', 'category', 'subject'),
|
||||
'country',
|
||||
('organisation_english','tel', 'email', 'url',),
|
||||
('organisation_english', 'tel', 'email', 'url',),
|
||||
('organisation_2', 'organisation_3'),
|
||||
'organisation_original',
|
||||
)
|
||||
|
@ -220,11 +401,12 @@ class OrganizationAdmin(admin.ModelAdmin):
|
|||
('Other details', {
|
||||
'classes': ('collapse',),
|
||||
'fields': (
|
||||
'tags',
|
||||
),
|
||||
'tags',
|
||||
),
|
||||
})
|
||||
)
|
||||
ordering = ['organisation_english']
|
||||
actions = [download_csv]
|
||||
|
||||
def org_url(self, instance):
|
||||
return format_html('<a href="{0}" target="_blank">{1}</a>',
|
||||
|
@ -317,7 +499,8 @@ class SpeciesAdmin(admin.ModelAdmin):
|
|||
|
||||
class TaxonRangeAdmin(admin.ModelAdmin):
|
||||
model = TaxonRange
|
||||
search_fields = ['range__range_name', 'taxon', 'subrange_or_region', 'distribution', 'source', 'remarks']
|
||||
search_fields = ['range__range_name', 'taxon',
|
||||
'subrange_or_region', 'distribution', 'source', 'remarks']
|
||||
list_display = ['range_name', 'taxon']
|
||||
|
||||
def range_name(self, obj):
|
||||
|
@ -391,6 +574,7 @@ admin.site.register(Keyword, KeywordAdmin)
|
|||
# admin.site.register(Scale)
|
||||
# admin.site.register(Taxon)
|
||||
# admin.site.register(Field, FieldAdmin)
|
||||
admin.site.disable_action('delete_selected')
|
||||
|
||||
|
||||
# LU models
|
||||
|
|
102
app/convert.py
102
app/convert.py
|
@ -39,7 +39,7 @@ def add_linked(person, obj, data):
|
|||
tgt.name = n
|
||||
tgt.save()
|
||||
field.append(tgt)
|
||||
return field
|
||||
return field
|
||||
|
||||
|
||||
# Fetch an object by source_id (numeric identifier used in source DB)
|
||||
|
@ -71,7 +71,8 @@ def reindex_data():
|
|||
|
||||
|
||||
# Data update routine
|
||||
def refresh_data(filename, fmt=None):
|
||||
def refresh_data(filename, fmt=None, update_existing=False):
|
||||
print("refresh_data")
|
||||
count = 0
|
||||
rowcount = 0
|
||||
if not isfile(filename):
|
||||
|
@ -101,42 +102,72 @@ def refresh_data(filename, fmt=None):
|
|||
return None
|
||||
|
||||
if fmt['dataformat'] is DataFormat.PERSON_DETAIL:
|
||||
print(row)
|
||||
person, source_id = get_by_id(row['ID'], Person)
|
||||
if not person:
|
||||
person = Person.objects.filter(first_name=row['First name'], last_name=row['Last name']).first()
|
||||
if person:
|
||||
print("Fetched from DB")
|
||||
else:
|
||||
print("Does not exist in DB")
|
||||
if not person:
|
||||
person = Person(first_name=row['First name'], last_name=row['Last name'], source_id=row['ID'])
|
||||
person.source_id = source_id
|
||||
person.title = row['Title']
|
||||
print(row)
|
||||
person.organisation = row['Organisation English']
|
||||
print("Country = %s" % row['country'] if 'country' in row else '')
|
||||
if 'country' not in row or row['country'] is None or row['country'].strip() == '':
|
||||
row['country'] = 0
|
||||
c = Country.objects.get(id=row['country'])
|
||||
person.country = c
|
||||
person.position = row['Position']
|
||||
person.biography = row['Biography']
|
||||
person.contact_email = row['e-mail 1']
|
||||
person.personal_url = fix_url(row['URL'])
|
||||
person.save()
|
||||
print("Created")
|
||||
|
||||
# Update data fields
|
||||
person.source_id = source_id
|
||||
person.title = row['Title']
|
||||
person.organisation = row['Organisation English']
|
||||
print("Country = %s" % row['country'])
|
||||
if row['country'] is None or row['country'].strip() == '':
|
||||
row['country'] = 0
|
||||
c = Country.objects.get(id=row['country'])
|
||||
person.country = c
|
||||
person.position = row['Position']
|
||||
person.biography = row['Biography']
|
||||
person.contact_email = row['e-mail 1']
|
||||
person.personal_url = fix_url(row['URL'])
|
||||
|
||||
if update_existing:
|
||||
person.source_id = source_id
|
||||
person.title = row['Title']
|
||||
print(row)
|
||||
person.organisation = row['Organisation English']
|
||||
print("Country = %s" % row['country'] if 'country' in row else '')
|
||||
if 'country' not in row or row['country'] is None or row['country'].strip() == '':
|
||||
row['country'] = 0
|
||||
c = Country.objects.get(id=row['country'])
|
||||
person.country = c
|
||||
person.position = row['Position']
|
||||
person.biography = row['Biography']
|
||||
person.contact_email = row['e-mail 1']
|
||||
person.personal_url = fix_url(row['URL'])
|
||||
person.save()
|
||||
with transaction.atomic():
|
||||
research_methods = add_linked(person, Method, row['Methods'])
|
||||
methods_people = [MethodsPeople.objects.get_or_create(method_id=m.id, person_id=person.id) for m in research_methods]
|
||||
methods_people = [MethodsPeople.objects.get_or_create(method_id=m.id, person_id=person.id)[0] for m in research_methods]
|
||||
person.methodspeople_set.set(methods_people)
|
||||
research_scales = add_linked(person, Scale, row['Scale'])
|
||||
scales_people = [ScalesPeople.objects.get_or_create(scale_id=s.id, person_id=person.id) for s in research_scales]
|
||||
scales_people = [ScalesPeople.objects.get_or_create(scale_id=s.id, person_id=person.id)[0] for s in research_scales]
|
||||
person.scalespeople_set.set(scales_people)
|
||||
research_taxa = add_linked(person, Taxon, row['Taxa'])
|
||||
taxa_people = [TaxaPeople.objects.get_or_create(taxon_id=t.id, person_id=person.id) for t in research_taxa]
|
||||
taxa_people = [TaxaPeople.objects.get_or_create(taxon_id=t.id, person_id=person.id)[0] for t in research_taxa]
|
||||
person.taxapeople_set.set(taxa_people)
|
||||
research_fields = add_linked(person, Field, row['Field of expertise'])
|
||||
fields_people = [FieldsPeople.objects.get_or_create(field_id=f.id, person_id=person.id) for f in research_fields]
|
||||
fields_people = [FieldsPeople.objects.get_or_create(field_id=f.id, person_id=person.id)[0] for f in research_fields]
|
||||
person.fieldspeople_set.set(fields_people)
|
||||
# research_ranges = add_linked(person, MountainRange, row['MountainRange'])
|
||||
# ranges_people = [RangesPeople.objects.get_or_create(range_id=r.id, person_id=person.id)[0] for r in research_ranges]
|
||||
# person.rangespeople_set.set(ranges_people)
|
||||
person.index()
|
||||
person.save()
|
||||
count = count + 1
|
||||
|
||||
elif fmt['dataformat'] is DataFormat.RESOURCE_DETAIL:
|
||||
res, source_id = get_by_id(row['ID'], Resource)
|
||||
if not res: res = Resource(source_id=source_id)
|
||||
if not res:
|
||||
res = Resource(source_id=source_id)
|
||||
res.title = row['Title']
|
||||
res.citation = row['Citation']
|
||||
res.url = fix_url(row['URL'].strip('#')) # remove weird #formatting#
|
||||
|
@ -155,9 +186,11 @@ def refresh_data(filename, fmt=None):
|
|||
|
||||
elif fmt['dataformat'] is DataFormat.PERSON_RESOURCE:
|
||||
rzs, source_id = get_by_id(row['Resource'], Resource, first=False)
|
||||
if not rzs or not rzs.first(): continue
|
||||
if not rzs or not rzs.first():
|
||||
continue
|
||||
ppl, source_id = get_by_id(row['Person'], Person, first=False)
|
||||
if not ppl or not ppl.first(): continue
|
||||
if not ppl or not ppl.first():
|
||||
continue
|
||||
for person in ppl:
|
||||
person.resources = []
|
||||
for r in rzs:
|
||||
|
@ -167,15 +200,30 @@ def refresh_data(filename, fmt=None):
|
|||
|
||||
elif fmt['dataformat'] is DataFormat.PERSON_RANGE:
|
||||
rzs, source_id = get_by_id(row['MountainRange'], MountainRange, first=False)
|
||||
print(" range=%s, source_id=%s" % (rzs, source_id))
|
||||
if not rzs or not rzs.first():
|
||||
print(" --- No rzs, continue")
|
||||
continue
|
||||
ppl, source_id = get_by_id(row['Person'], Person, first=False)
|
||||
if not ppl or not ppl.first(): continue
|
||||
for person in ppl:
|
||||
person.ranges = []
|
||||
for r in rzs:
|
||||
person.ranges.append(r)
|
||||
print(" +++ ppl=%s, source_id=%s" % (ppl, source_id))
|
||||
if not ppl or not ppl.first():
|
||||
print(" --- No ppl, continue")
|
||||
continue
|
||||
with transaction.atomic():
|
||||
person = ppl.first()
|
||||
research_ranges = add_linked(person, MountainRange, row['MountainRange'])
|
||||
ranges_people = [PeopleRange.objects.get_or_create(range_id=r.id, person_id=person.id)[0] for r in research_ranges]
|
||||
person.peoplerange_set.set(ranges_people)
|
||||
# for person in ppl:
|
||||
# research_ranges = add_linked(person, MountainRange, row['MountainRange'])
|
||||
# ranges_people = [RangesPeople.objects.get_or_create(range_id=r.id, person_id=person.id)[0] for r in research_ranges]
|
||||
# person.rangespeople_set.set(ranges_people)
|
||||
# ranges_people = RangesPeople
|
||||
# for r in rzs:
|
||||
# ranges_people.append(r)
|
||||
# person.rangespeople_set.set(ranges_people)
|
||||
person.save()
|
||||
#print(" *** Saved %s => %s (%s)" % (person, ranges_people, len(ranges_people)))
|
||||
count = count + 1
|
||||
|
||||
elif fmt['extension'] == 'geojson':
|
||||
|
|
|
@ -356,7 +356,7 @@ class Command(BaseCommand):
|
|||
for k, v in self.csv_files_models_dict.items():
|
||||
if v.strip().lower() == model_name.strip().lower():
|
||||
csv_file_name = k
|
||||
if k == '':
|
||||
if csv_file_name == '':
|
||||
raise Exception('Could not find a csv file name for model %s' % model_name)
|
||||
if csv_folder_path.endswith('/'):
|
||||
file_path = '%s%s' % (csv_folder_path, csv_file_name)
|
||||
|
|
179
app/models.py
179
app/models.py
|
@ -31,7 +31,8 @@ class Field(models.Model):
|
|||
|
||||
class FieldsPeople(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey('Person', models.DO_NOTHING, blank=True, null=True)
|
||||
person = models.ForeignKey(
|
||||
'Person', models.DO_NOTHING, blank=True, null=True)
|
||||
field = models.ForeignKey(Field, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
|
@ -53,8 +54,10 @@ class Method(models.Model):
|
|||
|
||||
class MethodsPeople(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey('Person', models.DO_NOTHING, blank=True, null=True)
|
||||
method = models.ForeignKey(Method, models.DO_NOTHING, blank=True, null=True)
|
||||
person = models.ForeignKey(
|
||||
'Person', models.DO_NOTHING, blank=True, null=True)
|
||||
method = models.ForeignKey(
|
||||
Method, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'methods_people'
|
||||
|
@ -92,10 +95,14 @@ class MountainRange(models.Model):
|
|||
#range_name_map = models.CharField(blank=True, null=True, unique=True, max_length=128)
|
||||
range_name = models.CharField(blank=True, null=True, max_length=128)
|
||||
range_name_ascii = models.CharField(blank=True, null=True, max_length=128)
|
||||
range_name_language = models.ForeignKey(Language, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
mother_range = models.ForeignKey("self", models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
feature = models.ForeignKey(RangeType, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
map_unit = models.TextField(blank=True, null=True, choices=MAP_UNIT_CHOICES)
|
||||
range_name_language = models.ForeignKey(
|
||||
Language, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
mother_range = models.ForeignKey(
|
||||
"self", models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
feature = models.ForeignKey(
|
||||
RangeType, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
map_unit = models.TextField(
|
||||
blank=True, null=True, choices=MAP_UNIT_CHOICES)
|
||||
level = models.TextField(blank=True, null=True)
|
||||
level_text = models.TextField(blank=True, null=True)
|
||||
level_1 = models.TextField(blank=True, null=True)
|
||||
|
@ -113,14 +120,16 @@ class MountainRange(models.Model):
|
|||
comments = models.TextField(blank=True, null=True)
|
||||
checked = models.BooleanField(default=False)
|
||||
source = models.TextField(blank=True, null=True)
|
||||
range_alternate_id = models.CharField(blank=True, null=True, max_length=128)
|
||||
range_alternate_id = models.CharField(
|
||||
blank=True, null=True, max_length=128)
|
||||
geologic_region = models.TextField(blank=True, null=True)
|
||||
gmba_v2_id = models.PositiveIntegerField(blank=True, null=True)
|
||||
gmba_v2_id_str = models.TextField(blank=True, null=True)
|
||||
wiki_data_id = models.CharField(blank=True, null=True, max_length=25)
|
||||
wiki_data_url = models.URLField(blank=True, null=True)
|
||||
select_300 = models.BooleanField(default=False)
|
||||
gmba_narrow = models.BooleanField(default=False, verbose_name="GMBA Standard")
|
||||
gmba_narrow = models.BooleanField(
|
||||
default=False, verbose_name="GMBA Standard")
|
||||
name_fr = models.CharField(blank=True, null=True, max_length=128)
|
||||
name_de = models.CharField(blank=True, null=True, max_length=128)
|
||||
name_es = models.CharField(blank=True, null=True, max_length=128)
|
||||
|
@ -201,7 +210,8 @@ class Resource(models.Model):
|
|||
PEGASuS_Check_map_with_author = models.BooleanField(default=False)
|
||||
PEGASuS_polygon_ID = models.CharField(max_length=32, blank=True, null=True)
|
||||
PEGASuS_Polygon_comments = models.TextField(blank=True, null=True)
|
||||
PEGASuS_Assessment_ID = models.CharField(max_length=32, blank=True, null=True)
|
||||
PEGASuS_Assessment_ID = models.CharField(
|
||||
max_length=32, blank=True, null=True)
|
||||
gloria = models.BooleanField(default=False)
|
||||
gnomo = models.BooleanField(default=False)
|
||||
lter = models.BooleanField(default=False)
|
||||
|
@ -352,15 +362,20 @@ class GMBA_function(models.Model):
|
|||
class Organisation(models.Model):
|
||||
CATEGORY_CHOICES = (
|
||||
('Independent', 'Independent'),
|
||||
('Public administration > Research Institution', 'Public administration > Research Institution'),
|
||||
('Public administration > Research Institution',
|
||||
'Public administration > Research Institution'),
|
||||
('Academia > University > Institute', 'Academia > University > Institute'),
|
||||
('Academia > University', 'Academia > University'),
|
||||
('Public administration > Other Agency', 'Public administration > Other Agency'),
|
||||
('Public administration > Other Agency',
|
||||
'Public administration > Other Agency'),
|
||||
('Private > NGO (not for profit)', 'Private > NGO (not for profit)'),
|
||||
('Academia > Academy of Sciences', 'Academia > Academy of Sciences'),
|
||||
('Academia > Academy of Sciences > Institute', 'Academia > Academy of Sciences > Institute'),
|
||||
('Public administration > Government', 'Public administration > Government'),
|
||||
('Intergovernmental Agency > Research Institution', 'Intergovernmental Agency > Research Institution'),
|
||||
('Academia > Academy of Sciences > Institute',
|
||||
'Academia > Academy of Sciences > Institute'),
|
||||
('Public administration > Government',
|
||||
'Public administration > Government'),
|
||||
('Intergovernmental Agency > Research Institution',
|
||||
'Intergovernmental Agency > Research Institution'),
|
||||
('Intergovernmental Agency', 'Intergovernmental Agency '),
|
||||
('Private > Research Institution', 'Private > Research Institution'),
|
||||
('Collection > Museum', 'Collection > Museum'),
|
||||
|
@ -384,7 +399,8 @@ class Organisation(models.Model):
|
|||
('Culture / arts', 'Culture / arts'),
|
||||
('Geography', 'Geography'),
|
||||
('Zoology', 'Zoology'),
|
||||
('Development / poverty / human rights', 'Development / poverty / human rights'),
|
||||
('Development / poverty / human rights',
|
||||
'Development / poverty / human rights'),
|
||||
('Social Sciences', 'Social Sciences'),
|
||||
('Earth Sciences', 'Earth Sciences'),
|
||||
('Health', 'Health'),
|
||||
|
@ -399,9 +415,12 @@ class Organisation(models.Model):
|
|||
org_num1 = models.AutoField(primary_key=True, verbose_name='ID')
|
||||
organisation_search = models.TextField(blank=True, null=True)
|
||||
org_alpha_search = models.TextField(blank=True, null=True)
|
||||
organisation_english = models.CharField(max_length=256, blank=True, null=True, verbose_name='Organisation')
|
||||
organisation_2 = models.CharField(max_length=256, blank=True, null=True, verbose_name='Department 1')
|
||||
organisation_3 = models.CharField(max_length=256, blank=True, null=True, verbose_name='Department 2')
|
||||
organisation_english = models.CharField(
|
||||
max_length=256, blank=True, null=True, verbose_name='Organisation')
|
||||
organisation_2 = models.CharField(
|
||||
max_length=256, blank=True, null=True, verbose_name='Department 1')
|
||||
organisation_3 = models.CharField(
|
||||
max_length=256, blank=True, null=True, verbose_name='Department 2')
|
||||
organisation_original = models.TextField(blank=True, null=True)
|
||||
acronym = models.CharField(max_length=128, blank=True, null=True)
|
||||
street = models.CharField(max_length=256, blank=True, null=True)
|
||||
|
@ -414,27 +433,33 @@ class Organisation(models.Model):
|
|||
url = models.URLField(blank=True, null=True)
|
||||
tel = models.CharField(max_length=128, blank=True, null=True)
|
||||
email = models.EmailField(blank=True, null=True)
|
||||
country = models.ForeignKey(Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
country = models.ForeignKey(
|
||||
Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
tags = models.TextField(blank=True, null=True)
|
||||
description = models.TextField(blank=True, null=True)
|
||||
northing = models.TextField(blank=True, null=True)
|
||||
easting = models.TextField(blank=True, null=True)
|
||||
category = models.TextField(blank=True, null=True, choices=CATEGORY_CHOICES)
|
||||
subject = models.CharField(max_length=128, blank=True, null=True, choices=SUBJECT_CHOICES)
|
||||
category = models.TextField(
|
||||
blank=True, null=True, choices=CATEGORY_CHOICES)
|
||||
subject = models.CharField(
|
||||
max_length=128, blank=True, null=True, choices=SUBJECT_CHOICES)
|
||||
|
||||
def __str__(self):
|
||||
if self.organisation_english:
|
||||
if self.organisation_2:
|
||||
name = f"{self.organisation_english} ({self.organisation_2})"
|
||||
name = f"{self.country} < {self.organisation_english} < {self.organisation_2} < {self.organisation_3} < {self.acronym}"
|
||||
|
||||
else:
|
||||
name = f"{self.organisation_english}"
|
||||
name = f"{self.country} < {self.organisation_english} < {self.organisation_2} < {self.organisation_3} < {self.acronym}"
|
||||
|
||||
else:
|
||||
name = '---'
|
||||
name = ' ---'
|
||||
|
||||
return name
|
||||
|
||||
|
||||
|
||||
class RangeOnlineInfo(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
# This is supposed to be linked to MountainRange via range_name_map, but the range_name_map
|
||||
|
@ -451,8 +476,10 @@ class RangeOnlineInfo(models.Model):
|
|||
|
||||
class RangeNameTranslation(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
range_name = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
language_translation = models.ForeignKey(Language, models.DO_NOTHING, blank=True, null=True)
|
||||
range_name = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
language_translation = models.ForeignKey(
|
||||
Language, models.DO_NOTHING, blank=True, null=True)
|
||||
range_name_translation = models.TextField(blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -505,8 +532,10 @@ class Keyword(models.Model):
|
|||
|
||||
class ResourceKeyword(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
resource = models.ForeignKey(Resource, models.DO_NOTHING, blank=True, null=True)
|
||||
keyword = models.ForeignKey(Keyword, models.DO_NOTHING, blank=True, null=True, to_field='keyword_id')
|
||||
resource = models.ForeignKey(
|
||||
Resource, models.DO_NOTHING, blank=True, null=True)
|
||||
keyword = models.ForeignKey(
|
||||
Keyword, models.DO_NOTHING, blank=True, null=True, to_field='keyword_id')
|
||||
|
||||
def __str__(self):
|
||||
return '%s - %s' % (self.resource.title, self.keyword.keyword)
|
||||
|
@ -529,8 +558,10 @@ class NamesImport(models.Model):
|
|||
|
||||
class ResourceRange(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
resource_title = models.ForeignKey(Resource, models.DO_NOTHING, blank=True, null=True)
|
||||
range_name = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
resource_title = models.ForeignKey(
|
||||
Resource, models.DO_NOTHING, blank=True, null=True)
|
||||
range_name = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return '%s, %s' % (self.resource_title.title, self.range_name.name)
|
||||
|
@ -538,7 +569,8 @@ class ResourceRange(models.Model):
|
|||
|
||||
class LanguageLink(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
language_number_code = models.ForeignKey(Language, models.DO_NOTHING, blank=True, null=True)
|
||||
language_number_code = models.ForeignKey(
|
||||
Language, models.DO_NOTHING, blank=True, null=True)
|
||||
language_letter_code = models.TextField(blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -560,8 +592,10 @@ class Peak(models.Model):
|
|||
|
||||
class Search(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
range_name = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
repository = models.ForeignKey(Repository, models.DO_NOTHING, blank=True, null=True)
|
||||
range_name = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
repository = models.ForeignKey(
|
||||
Repository, models.DO_NOTHING, blank=True, null=True)
|
||||
search_string = models.TextField(blank=True, null=True)
|
||||
search_date = models.TextField(blank=True, null=True)
|
||||
result = models.TextField(blank=True, null=True)
|
||||
|
@ -584,12 +618,12 @@ class Person(models.Model):
|
|||
('''Involved scientist
|
||||
Steering committee''', '''Involved scientist
|
||||
Steering committee'''),
|
||||
('Network', 'Network'),
|
||||
('Network', 'Network'),
|
||||
('Newsletter only', 'Newsletter only'),
|
||||
('''Steering committee
|
||||
Involved scientist''', '''Steering committee
|
||||
Involved scientist''')
|
||||
)
|
||||
)
|
||||
id = models.AutoField(primary_key=True)
|
||||
source_id = models.IntegerField(blank=True, null=True)
|
||||
title = models.CharField(blank=True, null=True, max_length=255)
|
||||
|
@ -600,7 +634,9 @@ Involved scientist''')
|
|||
contact_email = models.EmailField(blank=True, null=True) # email_1
|
||||
personal_url = models.URLField(blank=True, null=True) # url ?
|
||||
biography = models.TextField(blank=True, null=True)
|
||||
field_indexer = models.TextField(db_column='_indexer', blank=True, null=True) # Field renamed because it started with '_'.
|
||||
# Field renamed because it started with '_'.
|
||||
field_indexer = models.TextField(
|
||||
db_column='_indexer', blank=True, null=True)
|
||||
|
||||
mr_mrs = models.TextField(blank=True, null=True, choices=MR_MRS_CHOICES)
|
||||
full_name = models.CharField(blank=True, null=True, max_length=100)
|
||||
|
@ -611,12 +647,16 @@ Involved scientist''')
|
|||
mobile_number = models.CharField(blank=True, null=True, max_length=50)
|
||||
url = models.URLField(blank=True, null=True)
|
||||
field_of_expertise = models.TextField(blank=True, null=True)
|
||||
status = models.ForeignKey(PeopleStatus, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
status = models.ForeignKey(
|
||||
PeopleStatus, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
entry_date = models.TextField(blank=True, null=True)
|
||||
gmba_function = models.TextField(blank=True, null=True, choices=GMBA_FUNCTION_CHOICES)
|
||||
gmba_function = models.TextField(
|
||||
blank=True, null=True, choices=GMBA_FUNCTION_CHOICES)
|
||||
news_letter = models.BooleanField(default=False)
|
||||
country = models.ForeignKey(Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
organization = models.ForeignKey(Organisation, models.DO_NOTHING, blank=True, null=True)
|
||||
country = models.ForeignKey(
|
||||
Country, models.DO_NOTHING, blank=True, null=True, to_field='id')
|
||||
organization = models.ForeignKey(
|
||||
Organisation, models.DO_NOTHING, blank=True, null=True)
|
||||
birds = models.BooleanField(default=False)
|
||||
mammals = models.BooleanField(default=False)
|
||||
reptiles = models.BooleanField(default=False)
|
||||
|
@ -641,7 +681,8 @@ Involved scientist''')
|
|||
assessment = models.BooleanField(default=False)
|
||||
meta_analysis = models.BooleanField(default=False)
|
||||
synthesis = models.BooleanField(default=False)
|
||||
qualitative_ssm = models.BooleanField(default=False) #"Qualitative social science methods (interviews, surveys)"
|
||||
# "Qualitative social science methods (interviews, surveys)"
|
||||
qualitative_ssm = models.BooleanField(default=False)
|
||||
genetic_analyses = models.BooleanField(default=False)
|
||||
field_site = models.BooleanField(default=False)
|
||||
transect = models.BooleanField(default=False)
|
||||
|
@ -666,10 +707,18 @@ Involved scientist''')
|
|||
return False
|
||||
|
||||
def index(self):
|
||||
self.field_indexer = " ".join([
|
||||
self.first_name, self.last_name, self.organisation, self.position, self.biography
|
||||
])
|
||||
return True
|
||||
if self:
|
||||
self.field_indexer = " ".join([
|
||||
self.first_name if self and self.first_name else "",
|
||||
self.last_name if self and self.last_name else "",
|
||||
self.organisation if self and self.organisation else "",
|
||||
self.position if self and self.position else "",
|
||||
self.biography if self and self.biography else ""
|
||||
] if self else "")
|
||||
# self.save()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def fullname(self):
|
||||
return " ".join([self.title if self.title else '',
|
||||
|
@ -691,11 +740,16 @@ Involved scientist''')
|
|||
'biography': self.biography or '',
|
||||
}
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.index()
|
||||
super(Person, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class TaxaPeople(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
|
||||
taxon = models.ForeignKey('Taxon', models.DO_NOTHING, blank=True, null=True)
|
||||
taxon = models.ForeignKey(
|
||||
'Taxon', models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'taxa_people'
|
||||
|
@ -707,7 +761,8 @@ class TaxaPeople(models.Model):
|
|||
class RangesPeople(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
|
||||
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
range = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'ranges_people'
|
||||
|
@ -719,7 +774,8 @@ class RangesPeople(models.Model):
|
|||
class ResourcesPeople(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
|
||||
resource = models.ForeignKey(Resource, models.CASCADE, blank=True, null=True)
|
||||
resource = models.ForeignKey(
|
||||
Resource, models.CASCADE, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'resources_people'
|
||||
|
@ -730,7 +786,8 @@ class ResourcesPeople(models.Model):
|
|||
|
||||
class ScalesPeople(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(Person, models.DO_NOTHING, blank=True, null=True)
|
||||
person = models.ForeignKey(
|
||||
Person, models.DO_NOTHING, blank=True, null=True)
|
||||
scale = models.ForeignKey(Scale, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
|
@ -754,7 +811,8 @@ class Species(models.Model):
|
|||
class PeopleFunction(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
|
||||
function = models.ForeignKey(GMBA_function, models.DO_NOTHING, blank=True, null=True)
|
||||
function = models.ForeignKey(
|
||||
GMBA_function, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.person.full_name
|
||||
|
@ -762,8 +820,10 @@ class PeopleFunction(models.Model):
|
|||
|
||||
class SpeciesRange(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
scientific_name = models.ForeignKey(Species, models.DO_NOTHING, blank=True, null=True)
|
||||
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
scientific_name = models.ForeignKey(
|
||||
Species, models.DO_NOTHING, blank=True, null=True)
|
||||
range = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
endemic = models.TextField(blank=True, null=True)
|
||||
source_url = models.TextField(blank=True, null=True)
|
||||
|
||||
|
@ -774,7 +834,8 @@ class SpeciesRange(models.Model):
|
|||
class PeopleRange(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
|
||||
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
range = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.id)
|
||||
|
@ -782,7 +843,8 @@ class PeopleRange(models.Model):
|
|||
|
||||
class TaxonRange(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
range = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
taxon = models.TextField(blank=True, null=True)
|
||||
subrange_or_region = models.TextField(blank=True, null=True)
|
||||
taxon_status = models.TextField(blank=True, null=True)
|
||||
|
@ -813,7 +875,8 @@ class PeopleResource(models.Model):
|
|||
)
|
||||
id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(Person, models.CASCADE, blank=True, null=True)
|
||||
resource = models.ForeignKey(Resource, models.DO_NOTHING, blank=True, null=True)
|
||||
resource = models.ForeignKey(
|
||||
Resource, models.DO_NOTHING, blank=True, null=True)
|
||||
role = models.TextField(blank=True, null=True, choices=ROLES_CHOICES)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -822,8 +885,10 @@ class PeopleResource(models.Model):
|
|||
|
||||
class RangeCountry(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
range = models.ForeignKey(MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
country = models.ForeignKey(Country, models.DO_NOTHING, blank=True, null=True)
|
||||
range = models.ForeignKey(
|
||||
MountainRange, models.DO_NOTHING, blank=True, null=True)
|
||||
country = models.ForeignKey(
|
||||
Country, models.DO_NOTHING, blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return '%s --- %s' % (self.range.range_name if self.range else 'None', self.country.short_name if self.country else 'None')
|
||||
|
|
|
@ -248,7 +248,7 @@
|
|||
</div><!-- /person-tags -->
|
||||
|
||||
<a name="contact"></a><h3>Contact</h3>
|
||||
<form action="https://formspree.io/gmba@ips.unibe.ch"
|
||||
<form onsubmit="{ FormSubmitted }" action="https://formspree.io/f/xvolqjpe"
|
||||
target="_blank" method="POST" class="contact-form">
|
||||
<input type="hidden" name="subject" value="Contact request from GMBA Connect">
|
||||
<input type="hidden" name="person" value={ person.data.fullname }>
|
||||
|
@ -256,7 +256,7 @@
|
|||
<input type="text" name="name" placeholder="Your name" required>
|
||||
<input type="email" name="_replyto" placeholder="E-mail address" required>
|
||||
<p>
|
||||
<input type="submit" value="Send" class="c-button u-small c-button--brand">
|
||||
<input type="submit" value="Send" class="c-button u-small c-button--brand">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
|
@ -287,6 +287,12 @@
|
|||
const FILTER_BLANK = {
|
||||
'country': [], 'range': [], 'field': [], 'taxon': []
|
||||
}
|
||||
|
||||
FormSubmitted(){
|
||||
console.log("i got executed")
|
||||
var self = this
|
||||
self.closedetails()
|
||||
}
|
||||
this.filters_shown = FILTER_BLANK
|
||||
|
||||
search(e, nextpage) {
|
||||
|
@ -481,6 +487,9 @@
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</gmba-search>
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<meta name="referrer" content="origin">
|
||||
|
||||
|
||||
|
||||
<link href="{% static 'app/admin/bootstrap/bootstrap3/swatch/default/bootstrap.min.css' %}?v=3.3.5" rel="stylesheet">
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="referrer" content="origin">
|
||||
|
||||
|
||||
<!--[if lte IE 8]><script src="/static/assets/js/ie/html5shiv.js"></script><![endif]-->
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="/static/assets/css/ie8.css" /><![endif]-->
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="referrer" content="origin">
|
||||
|
||||
|
||||
<!--[if lte IE 8]><script src="{% static 'app/assets/js/ie/html5shiv.js' %}"></script><![endif]-->
|
||||
<!--[if lte IE 8]><link rel="stylesheet" href="{% static 'app/assets/ss/ie8.css' %}" /><![endif]-->
|
||||
|
|
20
app/views.py
20
app/views.py
|
@ -176,11 +176,17 @@ def get_paginated(query_set, page, per_page):
|
|||
for p in paginator.object_list:
|
||||
filters['country'].append(p.country.short_name)
|
||||
for r in p.peoplerange_set.all():
|
||||
filters['range'].append(r.range.range_name)
|
||||
if r.range and r.range.range_name:
|
||||
filters['range'].append(r.range.range_name)
|
||||
else:
|
||||
print("r.range.range_name is None %s %s" % (r.range_id, r.person_id))
|
||||
for r in p.fieldspeople_set.all():
|
||||
filters['field'].append(r.field.name)
|
||||
for r in p.taxapeople_set.all():
|
||||
filters['taxon'].append(r.taxon.name)
|
||||
if r and r.taxon and r.taxon.name:
|
||||
filters['taxon'].append(r.taxon.name)
|
||||
else:
|
||||
print("r.taxon.name is None %s %s" % (r.range_id, r.taxon))
|
||||
filters = {
|
||||
'country': sorted(set(filters['country'])),
|
||||
'range': sorted(set(filters['range'])),
|
||||
|
@ -207,10 +213,10 @@ class SearchView(View):
|
|||
per_page = int(self.request.GET.get('per_page', 10))
|
||||
q = self.request.GET.get('q', '').strip()
|
||||
if not q or len(q) < 3:
|
||||
query_set = Person.objects.all()
|
||||
query_set = Person.objects.filter(profile_on_web=True).all()
|
||||
else:
|
||||
query = reduce(operator.or_, (Q(field_indexer__icontains=item) for item in q.split(" ")))
|
||||
query_set = Person.objects.filter(query)
|
||||
query_set = Person.objects.filter(query).filter(profile_on_web=True)
|
||||
|
||||
q_country = self.request.GET.get('country', '')
|
||||
q_range = self.request.GET.get('range', '')
|
||||
|
@ -219,7 +225,7 @@ class SearchView(View):
|
|||
if len(q_country) > 2:
|
||||
query_set = query_set.filter(country__short_name__icontains=q_country.strip().lower())
|
||||
if len(q_range) > 2:
|
||||
ranges_people = PeopleRange.objects.filter(range__name__icontains=q_range.strip().lower())
|
||||
ranges_people = PeopleRange.objects.filter(range__range_name__icontains=q_range.strip().lower())
|
||||
r_people_ids = [rp.person_id for rp in ranges_people]
|
||||
query_set = query_set.filter(id__in=r_people_ids)
|
||||
if len(q_field) > 2:
|
||||
|
@ -239,8 +245,8 @@ class PeopleDetailView(View):
|
|||
person = get_object_or_404(Person, id=people_id)
|
||||
return_data = {
|
||||
'data': person.dict(),
|
||||
'resources': [r.resource.dict() for r in person.resourcespeople_set.all()],
|
||||
'ranges': [r.range.dict() for r in person.rangespeople_set.all()],
|
||||
'resources': [r.resource.dict() for r in person.peopleresource_set.all()],
|
||||
'ranges': [r.range.dict() for r in person.peoplerange_set.all()],
|
||||
'fields': [r.field.name for r in person.fieldspeople_set.all()],
|
||||
'methods': [r.method.name for r in person.methodspeople_set.all()],
|
||||
'scales': [r.scale.name for r in person.scalespeople_set.all()],
|
||||
|
|
37
docker-compose.prod.yml
Normal file
37
docker-compose.prod.yml
Normal file
|
@ -0,0 +1,37 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: Dockerfile.prod
|
||||
command: gunicorn gmba_django.wsgi:application --bind [::]:8000
|
||||
volumes:
|
||||
- static_volume:/data/app/app/static
|
||||
- media_volume:/data/app/app/media
|
||||
expose:
|
||||
- 8000
|
||||
env_file:
|
||||
- ./.env.prod
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: postgres:13.0-alpine
|
||||
volumes:
|
||||
- postgres_data:/data/var/lib/postgresql/data/
|
||||
env_file:
|
||||
- ./.env.prod
|
||||
nginx:
|
||||
build: ./nginx
|
||||
volumes:
|
||||
- static_volume:/data/app/app/static
|
||||
- media_volume:/data/app/app/media
|
||||
ports:
|
||||
- 1337:80
|
||||
depends_on:
|
||||
- web
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
static_volume:
|
||||
media_volume:
|
15
entrypoint.prod.sh
Executable file
15
entrypoint.prod.sh
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ "$DATABASE" = "postgres" ]
|
||||
then
|
||||
echo "Waiting for postgres..."
|
||||
|
||||
while ! nc -z $SQL_HOST $SQL_PORT; do
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
echo "PostgreSQL started"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
|
@ -4,7 +4,11 @@ DEBUG = True
|
|||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.postgresql'),
|
||||
'NAME': os.environ.get('POSTGRES_DB', 'app'),
|
||||
'USER': os.environ.get('POSTGRES_USER', 'app'),
|
||||
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', ''),
|
||||
'HOST': os.environ.get('POSTGRES_HOST', 'localhost'),
|
||||
'PORT': os.environ.get('POSTGRES_PORT', 5432),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,17 +6,20 @@ ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', "").split(",")
|
|||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.sqlite3'),
|
||||
'NAME': os.environ.get('SQL_DATABASE', os.path.join(BASE_DIR, 'db.sqlite3')),
|
||||
# 'USER': os.environ.get('SQL_USER', 'user'),
|
||||
# 'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'),
|
||||
# 'HOST': os.environ.get('SQL_HOST', 'localhost'),
|
||||
# 'PORT': os.environ.get('SQL_PORT', ''),
|
||||
'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.postgresql'),
|
||||
'NAME': os.environ.get('POSTGRES_DB', 'app'),
|
||||
'USER': os.environ.get('POSTGRES_USER', 'app'),
|
||||
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', ''),
|
||||
'HOST': os.environ.get('POSTGRES_HOST', 'localhost'),
|
||||
'PORT': os.environ.get('POSTGRES_PORT', 5432),
|
||||
}
|
||||
}
|
||||
|
||||
SECURE_SSL_REDIRECT = True
|
||||
|
||||
# See https://docs.djangoproject.com/en/2.2/ref/settings/#secure-proxy-ssl-header
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
SESSION_COOKIE_SECURE = True
|
||||
|
||||
CSRF_COOKIE_SECURE = True
|
||||
|
|
6
init.sh
Executable file
6
init.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/ash
|
||||
#python manage.py migrate
|
||||
|
||||
python manage.py collectstatic --noinput
|
||||
#
|
||||
#gunicorn gmba_django.wsgi:application --bind [::]:8000
|
4
nginx/Dockerfile
Normal file
4
nginx/Dockerfile
Normal file
|
@ -0,0 +1,4 @@
|
|||
FROM nginx:1.21-alpine
|
||||
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
COPY nginx.conf /etc/nginx/conf.d
|
28
nginx/nginx.conf
Normal file
28
nginx/nginx.conf
Normal file
|
@ -0,0 +1,28 @@
|
|||
upstream gmba_django {
|
||||
server web:8000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
client_max_body_size 256m;
|
||||
|
||||
location / {
|
||||
proxy_pass http://gmba_django;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
proxy_redirect off;
|
||||
}
|
||||
|
||||
location /static/ {
|
||||
alias /home/app/app/static/;
|
||||
expires max;
|
||||
}
|
||||
|
||||
location /media/ {
|
||||
alias /home/app/app/media/;
|
||||
expires max;
|
||||
}
|
||||
|
||||
add_header Content-Security-Policy "frame-ancestors https://www.gmba.unibe.ch";
|
||||
}
|
|
@ -6,3 +6,4 @@ sqlparse==0.4.1
|
|||
typing-extensions==3.10.0.0
|
||||
psycopg2==2.9.1
|
||||
Werkzeug==2.0.2
|
||||
gunicorn==20.1.0
|
||||
|
|
Loading…
Reference in a new issue