Commit 1d8d9bc5 authored by hypsug0's avatar hypsug0
Browse files

wip: vue sighting form

parent 12ae6240
......@@ -803,7 +803,7 @@ BS Full screen Modal
#sighting-form {
margin: 5px;
padding: 5px;
padding: 0px 5px;
border: 1px solid #ccc;
background-color: whitesmoke;
border-radius: 5px;
......@@ -811,7 +811,7 @@ BS Full screen Modal
#countdetail-form {
margin: 5px;
padding: 5px;
padding: 0px 5px;
border: 1px solid #ccc;
background-color: white;
border-radius: 5px;
......
This diff is collapsed.
......@@ -98,12 +98,12 @@ label {
&.radio-inline label,
&.checkbox-inline label,
.form-control-feedback {
color: @brand-danger;
color: @brand-warning;
}
.form-control,
.form-control:focus {
border-color: @brand-danger;
border-color: @brand-warning;
}
}
......@@ -119,12 +119,12 @@ label {
&.radio-inline label,
&.checkbox-inline label,
.form-control-feedback {
color: @brand-primary;
color: @brand-danger;
}
.form-control,
.form-control:focus {
border-color: @brand-primary;
border-color: @brand-danger;
}
}
......
.transition, .autocomplete, .showAll-transition, .autocomplete ul, .autocomplete ul li a{
transition:all 0.3s ease-out;
-moz-transition:all 0.3s ease-out;
-webkit-transition:all 0.3s ease-out;
-o-transition:all 0.3s ease-out;
}
.autocomplete ul{
font-family: sans-serif;
position: absolute;
list-style: none;
background: #f8f8f8;
padding: 10px 0;
margin: 0;
display: inline-block;
min-width: 15%;
margin-top: 10px;
}
.autocomplete ul:before{
content: "";
display: block;
position: absolute;
height: 0;
width: 0;
border: 10px solid transparent;
border-bottom: 10px solid #f8f8f8;
left: 46%;
top: -20px
}
.autocomplete ul li a{
text-decoration: none;
display: block;
background: #f8f8f8;
color: #2b2b2b;
padding: 5px;
padding-left: 10px;
}
.autocomplete ul li a:hover, .autocomplete ul li.focus-list a{
color: white;
background: #2F9AF7;
}
.autocomplete ul li a span, /*backwards compat*/
.autocomplete ul li a .autocomplete-anchor-label{
display: block;
margin-top: 3px;
color: grey;
font-size: 13px;
}
.autocomplete ul li a:hover .autocomplete-anchor-label,
.autocomplete ul li.focus-list a span, /*backwards compat*/
.autocomplete ul li a:hover .autocomplete-anchor-label,
.autocomplete ul li.focus-list a span{ /*backwards compat*/
color: white;
}
/*.showAll-transition{
opacity: 1;
height: 50px;
overflow: hidden;
}
.showAll-enter{
opacity: 0.3;
height: 0;
}
.showAll-leave{
display: none;
}*/
This diff is collapsed.
//$.fn.select2.defaults.set("theme", "bootstrap");
// $.fn.select2.defaults.set("theme", "classic");
const asyncForEach = async (array, callback) => {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array)
}
}
Vue.component('ValidationProvider', VeeValidate.ValidationProvider);
const getCookie = (name) => {
let cookieValue = null
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';')
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim()
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === name + '=') {
cookieValue = decodeURIComponent(
cookie.substring(name.length + 1)
)
break
}
}
}
return cookieValue
}
const $http = axios.create({
withCredentials: true,
})
const csrftoken = getCookie('csrftoken')
console.debug('set csrftoken', csrftoken)
if (csrftoken) {
console.debug('set csrftoken', csrftoken)
$http.defaults.headers.common['X-CSRFToken'] = csrftoken
}
const dataTableLanguage = {
processing: 'Traitement en cours...',
search: 'Rechercher&nbsp;:',
......
This diff is collapsed.
import json
import logging
from django.apps import apps
from django.http import Http404, HttpResponse
# Get an instance of a logger
logger = logging.getLogger(__name__)
def apiDicts(req):
"""List all values from all dicts in one single request"""
......@@ -25,12 +29,12 @@ def apiDict(req, model):
try:
model = apps.get_model(".".join(["dicts", model]))
print("MODEL", model)
logger.debug(f"MODEL {model}")
values = model.objects.all().values()
list_values = [entry for entry in values]
jsondicts = json.dumps(list_values)
return HttpResponse(jsondicts, content_type="application/json")
except Exception as e:
print("ERROR", e)
logger.error(f"ERROR {e}")
raise Http404
# return HttpResponse({"error": e}, status=500, content_type="application/json")
......@@ -302,6 +302,14 @@ python-versions = "*"
[package.dependencies]
djangorestframework = "*"
[[package]]
name = "drf-writable-nested"
version = "0.6.2"
description = "Writable nested helpers for django-rest-framework's serializers"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "drf-yasg"
version = "1.20.0"
......@@ -808,7 +816,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake
[metadata]
lock-version = "1.1"
python-versions = "^3.7"
content-hash = "93d726018788b011ad0ac6400cca55182ff25539144284ce396b01fdd6fc44d8"
content-hash = "572a0fd91dfdb57fef7338e39a386866c78c6591a07636d1f14b19d78f98835e"
[metadata.files]
appdirs = [
......@@ -916,6 +924,9 @@ djangorestframework-gis = [
{file = "djangorestframework-gis-0.16.tar.gz", hash = "sha256:19a873740bcdac5c963779a1755d0d4acf96c4f5b63915d452f4b866d50f77d7"},
{file = "djangorestframework_gis-0.16-py2.py3-none-any.whl", hash = "sha256:1a19c9e103b3c34ed5db182cdfbc541905c5560fc4a80f86c8b976c79bdf1e6d"},
]
drf-writable-nested = [
{file = "drf_writable_nested-0.6.2-py3-none-any.whl", hash = "sha256:bb413286bd5ebf943460ba7c2dc177d572d6447d5287228cc763062c5a12e3d6"},
]
drf-yasg = [
{file = "drf-yasg-1.20.0.tar.gz", hash = "sha256:d50f197c7f02545d0b736df88c6d5cf874f8fea2507ad85ad7de6ae5bf2d9e5a"},
{file = "drf_yasg-1.20.0-py2.py3-none-any.whl", hash = "sha256:8b72e5b1875931a8d11af407be3a9a5ba8776541492947a0df5bafda6b7f8267"},
......
[tool.poetry]
name = "dbchiroweb"
version = "1.2.1-dev"
description = "A bats survey database"
authors = ["dbChiro <project@dbchiro.org>"]
description = "A bats survey database"
license = "AGPLv3"
name = "dbchiroweb"
version = "1.2.1-dev"
[tool.poetry.dependencies]
python = "^3.7"
Django = "^2.2.17"
djangorestframework-gis = "^0.16"
Pillow = "^8.1.0"
arrow = "^0.17.0"
django-autocomplete-light = "3.5.1"
django-ckeditor = "^6.0.0"
django-crispy-forms = "^1.10.0"
django-extensions = "^3.1.0"
django-filter = "^2.4"
django-geojson = "^3.1.0"
django-leaflet = "^0.27.1"
django-nested-admin = "^3.3.3"
django-registration-redux = "^2.8"
django-ckeditor = "^6.0.0"
django-leaflet = "^0.27.1"
django-geojson = "^3.1.0"
django-tables2 = "^2.3.3"
django-extensions = "^3.1.0"
psycopg2-binary = "^2.8.6"
tablib = "^3.0.0"
arrow = "^0.17.0"
Pillow = "^8.1.0"
djangorestframework-gis = "^0.16"
drf-yasg = "^1.20.0"
gunicorn = "^20.0.4"
django-autocomplete-light = "3.5.1"
psycopg2-binary = "^2.8.6"
python = "^3.7"
tablib = "^3.0.0"
drf-writable-nested = "^0.6.2"
[tool.poetry.dev-dependencies]
django-debug-toolbar = "^3.2"
coloredlogs = "^15.0"
black = "^20.8b1"
coloredlogs = "^15.0"
django-debug-toolbar = "^3.2"
flake8 = "^3.8.4"
tox = "^3.20.1"
isort = "^5.7.0"
pre-commit = "^2.10.0"
tox = "^3.20.1"
[tool.isort]
include_trailing_comma = true
line_length = 99
multi_line_output = 3
include_trailing_comma = true
[tool.black]
line-length = 99
target-version = ['py37']
include = '\.pyi?$'
exclude = '''
(
/(
......@@ -63,9 +60,10 @@ exclude = '''
# the root of the project
)
'''
include = '\.pyi?$'
line-length = 99
target-version = ['py37']
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
requires = ["poetry-core>=1.0.0"]
......@@ -25,6 +25,42 @@ logger = logging.getLogger(__name__)
dict_fields = ("id", "code")
countdetail_fields = (
"id_countdetail",
"time",
"method",
"sex",
"age",
"precision",
"count",
"unit",
"time",
"device",
"manipulator",
"validator",
"transmitter",
"ab",
"d5",
"pouce",
"queue",
"tibia",
"pied",
"cm3",
"tragus",
"poids",
"testicule",
"epididyme",
"tuniq_vag",
"gland_taille",
"gland_coul",
"mamelle",
"gestation",
"epiphyse",
"chinspot",
"etat_sexuel",
"usure_dent",
"comment",
)
# class DictBaseSerializer(serializers.ModelSerializer):
# class Meta:
......@@ -122,45 +158,35 @@ class SexSerialized(serializers.ModelSerializer):
fields = dict_fields
class CountDetailSerializer(serializers.ModelSerializer):
# precision = CountPrecisionSerializer()
# age = AgeSerializer()
# usure_dents = BiomDent()
class CountDetailListSerializer(serializers.ListSerializer):
def create(self, validated_data):
logger.debug(f"CountDetailListSerializer vdata {validated_data}")
countdetails = [CountDetail(**item) for item in validated_data]
return CountDetail.objects.bulk_create(countdetails)
class CountDetailBaseSerializer(serializers.ModelSerializer):
class Meta:
model = CountDetail
fields = (
"id_countdetail",
"method",
"sex",
"age",
"precision",
"count",
"unit",
"time",
"device",
"manipulator",
"validator",
"transmitter",
"ab",
"d5",
"pouce",
"queue",
"tibia",
"pied",
"cm3",
"tragus",
"poids",
"testicule",
"epididyme",
"tuniq_vag",
"gland_taille",
"gland_coul",
"mamelle",
"gestation",
"epiphyse",
"chinspot",
"etat_sexuel",
"usure_dent",
"comment",
fields = countdetail_fields
class CountDetailSerializer(CountDetailBaseSerializer):
taxa = serializers.SerializerMethodField()
session = serializers.SerializerMethodField()
class Meta(CountDetailBaseSerializer.Meta):
fields = CountDetailBaseSerializer.Meta.fields + (
"taxa",
"session",
)
def get_taxa(self, obj):
return obj.sighting.codesp.pk
def get_session(self, obj):
return obj.sighting.session.pk
def create(self):
logger.debug("CREATE")
......@@ -633,30 +633,30 @@ class SightingFilteringMixin:
qs = qs.filter(total_count__lte=count_max) if count_max is not None else qs
qs = (
qs.filter(
Q(countdetail_sighting__sex__code__icontains=sex)
| Q(countdetail_sighting__sex__descr__icontains=sex)
Q(countdetails__sex__code__icontains=sex)
| Q(countdetails__sex__descr__icontains=sex)
)
if sex is not None
else qs
)
qs = (
qs.filter(
Q(countdetail_sighting__age__code__icontains=age)
| Q(countdetail_sighting__age__descr__icontains=age)
Q(countdetails__age__code__icontains=age)
| Q(countdetails__age__descr__icontains=age)
)
if age is not None
else qs
)
qs = (
qs.filter(
Q(countdetail_sighting__mammelle__code__icontains=sexual_status)
| Q(countdetail_sighting__mammelle__descr__icontains=sexual_status)
| Q(countdetail_sighting__gestation__code__icontains=sexual_status)
| Q(countdetail_sighting__gestation__descr__icontains=sexual_status)
| Q(countdetail_sighting__testicule__code__icontains=sexual_status)
| Q(countdetail_sighting__testicule__descr__icontains=sexual_status)
| Q(countdetail_sighting__etat_sexuel__icontains=sexual_status)
| Q(countdetail_sighting__etat_sexuel__icontains=sexual_status)
Q(countdetails__mammelle__code__icontains=sexual_status)
| Q(countdetails__mammelle__descr__icontains=sexual_status)
| Q(countdetails__gestation__code__icontains=sexual_status)
| Q(countdetails__gestation__descr__icontains=sexual_status)
| Q(countdetails__testicule__code__icontains=sexual_status)
| Q(countdetails__testicule__descr__icontains=sexual_status)
| Q(countdetails__etat_sexuel__icontains=sexual_status)
| Q(countdetails__etat_sexuel__icontains=sexual_status)
)
if sexual_status is not None
else qs
......
......@@ -1092,9 +1092,7 @@ class Device(models.Model):
class CountDetail(models.Model):
id_countdetail = models.AutoField(primary_key=True)
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
sighting = models.ForeignKey(
Sighting, on_delete=models.CASCADE, related_name="countdetail_sighting"
)
sighting = models.ForeignKey(Sighting, on_delete=models.CASCADE, related_name="countdetails")
method = models.ForeignKey(
Method,
on_delete=models.DO_NOTHING,
......
......@@ -2,19 +2,21 @@
import logging
from django.contrib.auth.mixins import LoginRequiredMixin
from rest_framework import generics
from rest_framework.generics import ListAPIView
from rest_framework.permissions import AllowAny, IsAuthenticated
# from rest_framework.permissions import IsAuthenticated
# from rest_framework.response import Response
# from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from rest_framework.viewsets import GenericViewSet, ModelViewSet, mixins
from sights.countdetail.serializers import CountDetailSerializer
from sights.mixins import LargeGeoJsonPageNumberPagination, SightingFilteredListWithPermissions
from sights.models import CountDetail, Sighting
from sights.observation.serializers import (
CountDetailSerializer,
EditSightingSerializer,
SightingSerializer,
EditSightingSerializerTest,
GeoSightingSerializer,
)
# Get an instance of a logger
......@@ -24,9 +26,9 @@ logger = logging.getLogger(__name__)
class GeoJSONSighting(
LoginRequiredMixin,
SightingFilteredListWithPermissions,
generics.ListAPIView,
ListAPIView,
):
serializer_class = SightingSerializer
serializer_class = GeoSightingSerializer
pagination_class = LargeGeoJsonPageNumberPagination
def get_queryset(self, *args, **kwargs):
......@@ -45,53 +47,92 @@ class GeoJSONSighting(
class EditSighting(ModelViewSet):
serializer_class = EditSightingSerializer
# permission_class = [IsAuthenticated]
serializer_class = EditSightingSerializerTest
permission_class = [
IsAuthenticated,
]
def get_queryset(self):
session = self.kwargs["session"]
return Sighting.objects.filter(session=session)
# def list(self, request, *args, **kwargs):
# queryset = self.filter_queryset(self.get_queryset())
# session = self.kwargs["session"]
# queryset = Sighting.objects.filter(session=session).order_by("-timestamp_update")
# serializer = EditSightingSerializer(queryset, many=True)
# return Response(serializer.data)
# return Response(serializer.data)
if self.action in ("list", "create"):
session = self.kwargs["session"]
qs = Sighting.objects.filter(session=session)
else:
qs = Sighting.objects.all()
return qs
# def get(self, request, pk=None):
# """
# Return a session observations.
# """
# obs = [user.username for user in Sighting.objects.all()]
# user = get_object_or_404(queryset, pk=pk)
# serializer = UserSerializer(user)
# return Response(serializer.data)
# return Response(obs)
def create(self, request, *args, **kwargs):
request.data["created_by"] = self.request.user.pk
logger.debug(f"create data {request.data}")
return super(EditSighting, self).create(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
request.data["updated_by"] = self.request.user.pk
logger.debug(f"update data {request.data}")
return super().update(request, *args, **kwargs)
class SessionSightingsListView(generics.ListCreateAPIView):
class DeleteSighting(mixins.DestroyModelMixin, GenericViewSet):
serializer_class = EditSightingSerializer
queryset = Sighting.objects.all()
# permission_class = [IsAuthenticated]
class SessionCountDetailsListView(ModelViewSet):
permission_classes = (AllowAny,)
serializer_class = CountDetailSerializer
def get_queryset(self):
session = self.kwargs["session"]
return Sighting.objects.filter(session=session)
if self.action == "list":
session = self.kwargs["session"]
return CountDetail.objects.filter(sighting__session=session)
else:
return CountDetail.objects.all()
# def get_serializer_class(self):
# return CountDetailSerializer
# def list(self, request, session):
# # session = self.kwargs["session"]
# logger.debug(f"<SessionCountDetailsListView.list>")
# q = CountDetail.objects.filter(sighting__session=session)
# serializer = CountDeta(q, many=True)
# logger.debug(f"A {CountDetailBaseSerializer.Meta.fields}")
# logger.debug(f"B {serializer.data}")
# logger.debug(f"C {q.all()}")
# return Response(serializer.data)
class SessionSightingsView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = EditSightingSerializer
# def create(self, request, session):
# logger.debug(f"<SessionCountDetailsListView.create>")
# logger.debug(f"request {request.data}")