Compare commits
3 Commits
6884084f2a
...
070849c427
Author | SHA1 | Date | |
---|---|---|---|
070849c427 | |||
735191947d | |||
0486234b9f |
@ -18,7 +18,7 @@ function App() {
|
|||||||
element: <Home />,
|
element: <Home />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/station/:theme/:stopId",
|
path: "/station/:theme/:stationSlug",
|
||||||
element: <Station />
|
element: <Station />
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {Autocomplete, TextField} from "@mui/material";
|
import {Autocomplete, TextField} from "@mui/material";
|
||||||
import {useRef, useState} from "react";
|
import {useRef, useState} from "react";
|
||||||
|
|
||||||
function AutocompleteStop(params) {
|
function AutocompleteStation(params) {
|
||||||
const [options, setOptions] = useState([])
|
const [options, setOptions] = useState([])
|
||||||
const previousController = useRef()
|
const previousController = useRef()
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ function AutocompleteStop(params) {
|
|||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
const signal = controller.signal
|
const signal = controller.signal
|
||||||
previousController.current = controller
|
previousController.current = controller
|
||||||
fetch("/api/gtfs/stop/?location_type=1&search=" + value, {signal})
|
fetch("/api/core/station/?search=" + value, {signal})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => data.results)
|
.then(data => data.results)
|
||||||
.then(setOptions)
|
.then(setOptions)
|
||||||
@ -40,24 +40,7 @@ function AutocompleteStop(params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getOptionGroup(option) {
|
function getOptionGroup(option) {
|
||||||
switch (option.gtfs_feed) {
|
return option.country
|
||||||
case "FR-SNCF-TGV":
|
|
||||||
case "FR-SNCF-IC":
|
|
||||||
case "FR-SNCF-TER":
|
|
||||||
return "TGV/TER/Intercités"
|
|
||||||
case "FR-IDF-TN":
|
|
||||||
return "Transilien"
|
|
||||||
case "FR-EUROSTAR":
|
|
||||||
return "Eurostar"
|
|
||||||
case "IT-FRA-TI":
|
|
||||||
return "Trenitalia France"
|
|
||||||
case "ES-RENFE":
|
|
||||||
return "RENFE"
|
|
||||||
case "AT-OBB":
|
|
||||||
return "ÖBB"
|
|
||||||
default:
|
|
||||||
return option.gtfs_feed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AutocompleteStop;
|
export default AutocompleteStation;
|
@ -1,11 +1,11 @@
|
|||||||
import AutocompleteStop from "./AutocompleteStop"
|
import AutocompleteStation from "./AutocompleteStation"
|
||||||
import {useNavigate} from "react-router-dom"
|
import {useNavigate} from "react-router-dom"
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
function onStationSelected(event, stop) {
|
function onStationSelected(event, station) {
|
||||||
navigate(`/station/sncf/${stop.id}/`)
|
navigate(`/station/sncf/${station.slug}/`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
@ -13,7 +13,7 @@ function Home() {
|
|||||||
<h2>
|
<h2>
|
||||||
Choisissez une gare dont vous désirez connaître le tableau des prochains départs et arrivées :
|
Choisissez une gare dont vous désirez connaître le tableau des prochains départs et arrivées :
|
||||||
</h2>
|
</h2>
|
||||||
<AutocompleteStop onChange={onStationSelected} />
|
<AutocompleteStation onChange={onStationSelected} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@ import {Box, Button, FormLabel} from "@mui/material";
|
|||||||
import {DatePicker, TimePicker} from "@mui/x-date-pickers";
|
import {DatePicker, TimePicker} from "@mui/x-date-pickers";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {useQuery, useQueryClient} from "@tanstack/react-query";
|
import {useQuery, useQueryClient} from "@tanstack/react-query";
|
||||||
import AutocompleteStop from "./AutocompleteStop";
|
import AutocompleteStation from "./AutocompleteStation";
|
||||||
|
|
||||||
function DateTimeSelector({stop, date, time}) {
|
function DateTimeSelector({station, date, time}) {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
function onStationSelected(event, stop) {
|
function onStationSelected(event, station) {
|
||||||
if (stop !== null)
|
if (station !== null)
|
||||||
navigate(`/station/sncf/${stop.id}/`)
|
navigate(`/station/sncf/${station.slug}/`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
@ -20,7 +20,7 @@ function DateTimeSelector({stop, date, time}) {
|
|||||||
<FormLabel>
|
<FormLabel>
|
||||||
Changer la gare recherchée :
|
Changer la gare recherchée :
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<AutocompleteStop onChange={onStationSelected} />
|
<AutocompleteStation onChange={onStationSelected} />
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
Modifier la date et l'heure de recherche :
|
Modifier la date et l'heure de recherche :
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
@ -32,7 +32,7 @@ function DateTimeSelector({stop, date, time}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Station() {
|
function Station() {
|
||||||
let {stopId, theme} = useParams()
|
let {theme, stationSlug} = useParams()
|
||||||
let [searchParams, _setSearchParams] = useSearchParams()
|
let [searchParams, _setSearchParams] = useSearchParams()
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
let dateNow = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
|
let dateNow = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
|
||||||
@ -41,13 +41,13 @@ function Station() {
|
|||||||
let [time, setTime] = useState(searchParams.get('time') || timeNow)
|
let [time, setTime] = useState(searchParams.get('time') || timeNow)
|
||||||
|
|
||||||
useQueryClient()
|
useQueryClient()
|
||||||
const stopQuery = useQuery({
|
const stationQuery = useQuery({
|
||||||
queryKey: ['stop', stopId],
|
queryKey: ['station', stationSlug],
|
||||||
queryFn: () => fetch(`/api/gtfs/stop/${stopId}/`)
|
queryFn: () => fetch(`/api/core/station/${stationSlug}/`)
|
||||||
.then(response => response.json()),
|
.then(response => response.json()),
|
||||||
enabled: !!stopId,
|
enabled: !!stationSlug,
|
||||||
})
|
})
|
||||||
const stop = stopQuery.data ?? {name: "Chargement…"}
|
const station = stationQuery.data ?? {name: "Chargement…"}
|
||||||
|
|
||||||
if (time === timeNow) {
|
if (time === timeNow) {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
@ -62,13 +62,13 @@ function Station() {
|
|||||||
return (
|
return (
|
||||||
<div className="Station">
|
<div className="Station">
|
||||||
<header className="App-header">
|
<header className="App-header">
|
||||||
<h1>Horaires en gare de {stop.name}</h1>
|
<h1>Horaires en gare de {station.name}</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<DateTimeSelector stop={stop} date={date} time={time} />
|
<DateTimeSelector station={station} date={date} time={time} />
|
||||||
<TrainsTable stop={stop} date={date} time={time} tableType="departures" />
|
<TrainsTable station={station} date={date} time={time} tableType="departures" />
|
||||||
<TrainsTable stop={stop} date={date} time={time} tableType="arrivals" />
|
<TrainsTable station={station} date={date} time={time} tableType="arrivals" />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -26,12 +26,12 @@ const StyledTableRow = styled(TableRow)(({ theme, tabletype }) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function TrainsTable({stop, date, time, tableType}) {
|
function TrainsTable({station, date, time, tableType}) {
|
||||||
return <>
|
return <>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table>
|
<Table>
|
||||||
<TrainsTableHeader tableType={tableType} />
|
<TrainsTableHeader tableType={tableType} />
|
||||||
<TrainsTableBody stop={stop} date={date} time={time} tableType={tableType} />
|
<TrainsTableBody station={station} date={date} time={time} tableType={tableType} />
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</>
|
</>
|
||||||
@ -49,7 +49,7 @@ function TrainsTableHeader({tableType}) {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
function TrainsTableBody({stop, date, time, tableType}) {
|
function TrainsTableBody({station, date, time, tableType}) {
|
||||||
const filterTime = useCallback((train) => {
|
const filterTime = useCallback((train) => {
|
||||||
if (tableType === "departures")
|
if (tableType === "departures")
|
||||||
return `${train.departure_date}T${train.departure_time_24h}` >= `${date}T${time}`
|
return `${train.departure_date}T${train.departure_time_24h}` >= `${date}T${time}`
|
||||||
@ -58,16 +58,16 @@ function TrainsTableBody({stop, date, time, tableType}) {
|
|||||||
}, [date, time, tableType])
|
}, [date, time, tableType])
|
||||||
|
|
||||||
const updateTrains = useCallback(() => {
|
const updateTrains = useCallback(() => {
|
||||||
return fetch(`/api/station/next_${tableType}/?stop_id=${stop.id}&date=${date}&time=${time}&offset=${0}&limit=${20}`)
|
return fetch(`/api/station/next_${tableType}/?station_slug=${station.slug}&date=${date}&time=${time}&offset=${0}&limit=${20}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => data.results)
|
.then(data => data.results)
|
||||||
.then(data => [...data])
|
.then(data => [...data])
|
||||||
}, [stop.id, date, time, tableType])
|
}, [station.id, date, time, tableType])
|
||||||
|
|
||||||
const trainsQuery = useQuery({
|
const trainsQuery = useQuery({
|
||||||
queryKey: ['trains', stop.id, tableType],
|
queryKey: ['trains', station.id, tableType],
|
||||||
queryFn: updateTrains,
|
queryFn: updateTrains,
|
||||||
enabled: !!stop.id,
|
enabled: !!station.id,
|
||||||
})
|
})
|
||||||
const trains = useMemo(() => trainsQuery.data ?? [], [trainsQuery.data])
|
const trains = useMemo(() => trainsQuery.data ?? [], [trainsQuery.data])
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ function TrainRow({train, tableType, date, time}) {
|
|||||||
|
|
||||||
const stopTimesQuery = useQuery({
|
const stopTimesQuery = useQuery({
|
||||||
queryKey: ['stop_times', trip.id],
|
queryKey: ['stop_times', trip.id],
|
||||||
queryFn: () => fetch(`/api/gtfs/stop_time/?trip=${trip.id}&order=stop_sequence&limit=1000`)
|
queryFn: () => fetch(`/api/gtfs/stop_time/?${new URLSearchParams({trip: trip.id, order: 'stop_sequence', limit: 1000})}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => data.results),
|
.then(data => data.results),
|
||||||
enabled: !!trip.id,
|
enabled: !!trip.id,
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from trainvel.core.models import Station
|
||||||
from trainvel.gtfs.models import Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate, \
|
from trainvel.gtfs.models import Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate, \
|
||||||
Transfer, FeedInfo, TripUpdate, StopTimeUpdate
|
Transfer, FeedInfo, TripUpdate, StopTimeUpdate
|
||||||
|
|
||||||
|
|
||||||
|
class StationSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Station
|
||||||
|
lookup_field = 'slug'
|
||||||
|
fields = ('id', 'slug', 'name', 'uic', 'uic8_sncf', 'latitude', 'longitude', 'country',
|
||||||
|
'country_hint', 'main_station_hint',)
|
||||||
|
|
||||||
|
|
||||||
class AgencySerializer(serializers.ModelSerializer):
|
class AgencySerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Agency
|
model = Agency
|
||||||
|
@ -10,13 +10,28 @@ from rest_framework.filters import OrderingFilter, SearchFilter
|
|||||||
|
|
||||||
from trainvel.api.serializers import AgencySerializer, StopSerializer, RouteSerializer, TripSerializer, \
|
from trainvel.api.serializers import AgencySerializer, StopSerializer, RouteSerializer, TripSerializer, \
|
||||||
StopTimeSerializer, CalendarSerializer, CalendarDateSerializer, TransferSerializer, \
|
StopTimeSerializer, CalendarSerializer, CalendarDateSerializer, TransferSerializer, \
|
||||||
FeedInfoSerializer, TripUpdateSerializer, StopTimeUpdateSerializer
|
FeedInfoSerializer, TripUpdateSerializer, StopTimeUpdateSerializer, StationSerializer
|
||||||
from trainvel.gtfs.models import Agency, Calendar, CalendarDate, FeedInfo, GTFSFeed, Route, Stop, StopTime, StopTimeUpdate, \
|
from trainvel.core.models import Station
|
||||||
Transfer, Trip, TripUpdate
|
from trainvel.gtfs.models import Agency, Calendar, CalendarDate, FeedInfo, GTFSFeed, Route, Stop, StopTime, \
|
||||||
|
StopTimeUpdate, \
|
||||||
|
Transfer, Trip, TripUpdate, PickupType
|
||||||
|
|
||||||
CACHE_CONTROL = cache_control(max_age=7200)
|
CACHE_CONTROL = cache_control(max_age=30)
|
||||||
LAST_MODIFIED = last_modified(lambda *args, **kwargs: GTFSFeed.objects.order_by('-last_modified').first().last_modified)
|
LAST_MODIFIED = last_modified(lambda *args, **kwargs: GTFSFeed.objects.order_by('-last_modified').first().last_modified)
|
||||||
LOOKUP_VALUE_REGEX = r"[\w.: |-]+"
|
LOOKUP_VALUE_REGEX = r"[\w.: |+-]+"
|
||||||
|
|
||||||
|
|
||||||
|
class StationViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
|
queryset = Station.objects.filter(is_suggestable=True)
|
||||||
|
serializer_class = StationSerializer
|
||||||
|
filter_backends = [DjangoFilterBackend, SearchFilter]
|
||||||
|
filterset_fields = '__all__'
|
||||||
|
search_fields = ['name', 'slug',
|
||||||
|
'info_de', 'info_en', 'info_es', 'info_fr', 'info_it', 'info_nb', 'info_nl', 'info_cs',
|
||||||
|
'info_da', 'info_hu', 'info_ja', 'info_ko', 'info_pl', 'info_pt', 'info_ru', 'info_sv',
|
||||||
|
'info_tr', 'info_zh', ]
|
||||||
|
lookup_field = 'slug'
|
||||||
|
lookup_value_regex = LOOKUP_VALUE_REGEX
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(name='list', decorator=[CACHE_CONTROL, LAST_MODIFIED])
|
@method_decorator(name='list', decorator=[CACHE_CONTROL, LAST_MODIFIED])
|
||||||
@ -135,8 +150,7 @@ class NextDeparturesViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|
||||||
stop_id = self.request.query_params.get('stop_id', None)
|
station_slug = self.request.query_params.get('station_slug', None)
|
||||||
stop_name = self.request.query_params.get('stop_name', None)
|
|
||||||
query_date = date.fromisoformat(self.request.query_params.get('date', now.date().isoformat()))
|
query_date = date.fromisoformat(self.request.query_params.get('date', now.date().isoformat()))
|
||||||
query_time = self.request.query_params.get('time', now.time().isoformat(timespec='seconds'))
|
query_time = self.request.query_params.get('time', now.time().isoformat(timespec='seconds'))
|
||||||
query_time = timedelta(seconds=int(query_time[:2]) * 3600
|
query_time = timedelta(seconds=int(query_time[:2]) * 3600
|
||||||
@ -148,16 +162,10 @@ class NextDeparturesViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
tomorrow = query_date + timedelta(days=1)
|
tomorrow = query_date + timedelta(days=1)
|
||||||
|
|
||||||
stop_filter = Q(stop__location_type=0)
|
stop_filter = Q(stop__location_type=0)
|
||||||
if stop_id:
|
if station_slug:
|
||||||
stop = Stop.objects.get(id=stop_id)
|
station = Station.objects.get(is_suggestable=True, slug=station_slug)
|
||||||
stops = Stop.objects.filter(Q(id=stop_id)
|
near_stops = station.get_near_stops()
|
||||||
| Q(parent_station=stop_id))
|
stop_filter = Q(stop_id__in=near_stops.values_list('id', flat=True))
|
||||||
if stop.location_type == 0 and stop.parent_station_id is not None:
|
|
||||||
stops |= Stop.objects.filter(parent_station=stop.parent_station_id)
|
|
||||||
stop_filter = Q(stop__in=stops.values_list('id', flat=True))
|
|
||||||
elif stop_name:
|
|
||||||
stops = Stop.objects.filter(name__iexact=stop_name).values_list('id', flat=True)
|
|
||||||
stop_filter = Q(stop__in=stops)
|
|
||||||
|
|
||||||
def calendar_filter(d: date):
|
def calendar_filter(d: date):
|
||||||
return Q(trip__service_id__in=CalendarDate.objects.filter(date=d, exception_type=1)
|
return Q(trip__service_id__in=CalendarDate.objects.filter(date=d, exception_type=1)
|
||||||
@ -189,7 +197,7 @@ class NextDeparturesViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
qs_today = StopTime.objects.filter(stop_filter) \
|
qs_today = StopTime.objects.filter(stop_filter) \
|
||||||
.annotate(departure_time_real=departure_time_real(query_date)) \
|
.annotate(departure_time_real=departure_time_real(query_date)) \
|
||||||
.filter(departure_time_real__gte=query_time) \
|
.filter(departure_time_real__gte=query_time) \
|
||||||
.filter(Q(pickup_type=0) | canceled_filter(query_date)) \
|
.filter(Q(pickup_type=PickupType.REGULAR) | canceled_filter(query_date)) \
|
||||||
.filter(calendar_filter(query_date)) \
|
.filter(calendar_filter(query_date)) \
|
||||||
.annotate(departure_date=Value(query_date)) \
|
.annotate(departure_date=Value(query_date)) \
|
||||||
.annotate(departure_time_24h=F('departure_time'))
|
.annotate(departure_time_24h=F('departure_time'))
|
||||||
@ -221,8 +229,7 @@ class NextArrivalsViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|
||||||
stop_id = self.request.query_params.get('stop_id', None)
|
station_slug = self.request.query_params.get('station_slug', None)
|
||||||
stop_name = self.request.query_params.get('stop_name', None)
|
|
||||||
query_date = date.fromisoformat(self.request.query_params.get('date', now.date().isoformat()))
|
query_date = date.fromisoformat(self.request.query_params.get('date', now.date().isoformat()))
|
||||||
query_time = self.request.query_params.get('time', now.time().isoformat(timespec='seconds'))
|
query_time = self.request.query_params.get('time', now.time().isoformat(timespec='seconds'))
|
||||||
query_time = timedelta(seconds=int(query_time[:2]) * 3600
|
query_time = timedelta(seconds=int(query_time[:2]) * 3600
|
||||||
@ -235,16 +242,10 @@ class NextArrivalsViewSet(viewsets.ReadOnlyModelViewSet):
|
|||||||
tomorrow = query_date + timedelta(days=1)
|
tomorrow = query_date + timedelta(days=1)
|
||||||
|
|
||||||
stop_filter = Q(stop__location_type=0)
|
stop_filter = Q(stop__location_type=0)
|
||||||
if stop_id:
|
if station_slug:
|
||||||
stop = Stop.objects.get(id=stop_id)
|
station = Station.objects.get(is_suggestable=True, slug=station_slug)
|
||||||
stops = Stop.objects.filter(Q(id=stop_id)
|
near_stops = station.get_near_stops()
|
||||||
| Q(parent_station=stop_id))
|
stop_filter = Q(stop_id__in=near_stops.values_list('id', flat=True))
|
||||||
if stop.location_type == 0 and stop.parent_station_id is not None:
|
|
||||||
stops |= Stop.objects.filter(parent_station=stop.parent_station_id)
|
|
||||||
stop_filter = Q(stop__in=stops.values_list('id', flat=True))
|
|
||||||
elif stop_name:
|
|
||||||
stops = Stop.objects.filter(name__iexact=stop_name).values_list('id', flat=True)
|
|
||||||
stop_filter = Q(stop__in=stops)
|
|
||||||
|
|
||||||
def calendar_filter(d: date):
|
def calendar_filter(d: date):
|
||||||
return Q(trip__service_id__in=CalendarDate.objects.filter(date=d, exception_type=1)
|
return Q(trip__service_id__in=CalendarDate.objects.filter(date=d, exception_type=1)
|
||||||
|
0
trainvel/core/__init__.py
Normal file
0
trainvel/core/__init__.py
Normal file
23
trainvel/core/admin.py
Normal file
23
trainvel/core/admin.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from trainvel.core.models import Station
|
||||||
|
|
||||||
|
|
||||||
|
class StationInline(admin.TabularInline):
|
||||||
|
model = Station
|
||||||
|
extra = 0
|
||||||
|
autocomplete_fields = ('parent_station', 'same_as',)
|
||||||
|
show_change_link = True
|
||||||
|
ordering = ('name',)
|
||||||
|
readonly_fields = ('id',)
|
||||||
|
fk_name = 'parent_station'
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Station)
|
||||||
|
class StationAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', 'country', 'uic', 'latitude', 'longitude',)
|
||||||
|
list_filter = ('country', 'is_city', 'is_main_station', 'is_airport', 'is_suggestable',
|
||||||
|
'country_hint', 'main_station_hint',)
|
||||||
|
search_fields = ('name', 'slug',)
|
||||||
|
autocomplete_fields = ('parent_station', 'same_as',)
|
||||||
|
inlines = [StationInline]
|
8
trainvel/core/apps.py
Normal file
8
trainvel/core/apps.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class CoreConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "trainvel.core"
|
||||||
|
verbose_name = _("Trainvel - Core")
|
325
trainvel/core/locale/fr/LC_MESSAGES/django.po
Normal file
325
trainvel/core/locale/fr/LC_MESSAGES/django.po
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: 1.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2024-05-09 22:04+0200\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: Emmy D'Anello <ynerant@emy.lu>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
|
||||||
|
#: trainvel/core/apps.py:8
|
||||||
|
msgid "Trainvel - Core"
|
||||||
|
msgstr "Trainvel - Cœur"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:15
|
||||||
|
msgid "name"
|
||||||
|
msgstr "nom"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:20
|
||||||
|
msgid "slug"
|
||||||
|
msgstr "slug"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:24
|
||||||
|
msgid "UIC"
|
||||||
|
msgstr "UIC"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:31
|
||||||
|
msgid "UIC8 SNCF"
|
||||||
|
msgstr "UIC8 SNCF"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:38
|
||||||
|
msgid "latitude"
|
||||||
|
msgstr "latitude"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:45
|
||||||
|
msgid "longitude"
|
||||||
|
msgstr "longitude"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:54
|
||||||
|
msgid "parent station"
|
||||||
|
msgstr "gare parente"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:63
|
||||||
|
msgid "country"
|
||||||
|
msgstr "pays"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:69
|
||||||
|
msgid "timezone"
|
||||||
|
msgstr "fuseau horaire"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:73
|
||||||
|
msgid "is city"
|
||||||
|
msgstr "est une ville"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:77
|
||||||
|
msgid "is main station"
|
||||||
|
msgstr "est une gare principale"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:81
|
||||||
|
msgid "is airport"
|
||||||
|
msgstr "est un aéroport"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:85
|
||||||
|
msgid "is suggestable"
|
||||||
|
msgstr "est suggérable"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:89
|
||||||
|
msgid "country hint"
|
||||||
|
msgstr "indice de pays"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:93
|
||||||
|
msgid "main station hint"
|
||||||
|
msgstr "indice de gare principale"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:98
|
||||||
|
msgid "SNCF ID"
|
||||||
|
msgstr "ID SNCF"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:106
|
||||||
|
msgid "SNCF TVS ID"
|
||||||
|
msgstr "ID SNCF TVS"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:113
|
||||||
|
msgid "SNCF is enabled"
|
||||||
|
msgstr "SNCF est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:118
|
||||||
|
msgid "Entur ID"
|
||||||
|
msgstr "ID Entur"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:125
|
||||||
|
msgid "Entur is enabled"
|
||||||
|
msgstr "Entur est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:129
|
||||||
|
msgid "DB ID"
|
||||||
|
msgstr "ID DB"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:136
|
||||||
|
msgid "DB is enabled"
|
||||||
|
msgstr "DB est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:141
|
||||||
|
msgid "Busbud ID"
|
||||||
|
msgstr "ID Busbud"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:148
|
||||||
|
msgid "Busbud is enabled"
|
||||||
|
msgstr "Busbud est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:153
|
||||||
|
msgid "distribusion ID"
|
||||||
|
msgstr "ID distribusion"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:160
|
||||||
|
msgid "distribusion is enabled"
|
||||||
|
msgstr "distribusion est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:164
|
||||||
|
msgid "Flixbus ID"
|
||||||
|
msgstr "ID Flixbus"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:171
|
||||||
|
msgid "Flixbus is enabled"
|
||||||
|
msgstr "Flixbus est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:175
|
||||||
|
msgid "CFF ID"
|
||||||
|
msgstr "ID CFF"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:182
|
||||||
|
msgid "CFF is enabled"
|
||||||
|
msgstr "CFF est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:187
|
||||||
|
msgid "Leo Express ID"
|
||||||
|
msgstr "ID Leo Express"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:194
|
||||||
|
msgid "Leo Express is enabled"
|
||||||
|
msgstr "Leo Express est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:198
|
||||||
|
msgid "ÖBB ID"
|
||||||
|
msgstr "ID ÖBB"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:205
|
||||||
|
msgid "ÖBB is enabled"
|
||||||
|
msgstr "ÖBB est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:210
|
||||||
|
msgid "Ouigo ID"
|
||||||
|
msgstr "ID Ouigo"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:217
|
||||||
|
msgid "Ouigo is enabled"
|
||||||
|
msgstr "Ouigo est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:221
|
||||||
|
msgid "Trenitalia ID"
|
||||||
|
msgstr "ID Trenitalia"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:228
|
||||||
|
msgid "Trenitalia is enabled"
|
||||||
|
msgstr "Trenitalia est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:233
|
||||||
|
msgid "Trenitalia RTVT ID"
|
||||||
|
msgstr "ID Trenitalia RTVT"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:241
|
||||||
|
msgid "Trenord ID"
|
||||||
|
msgstr "ID Trenord"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:249
|
||||||
|
msgid "NTV RTIV ID"
|
||||||
|
msgstr "ID NTV RTIV"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:257
|
||||||
|
msgid "NTV ID"
|
||||||
|
msgstr "ID NTV"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:264
|
||||||
|
msgid "NTV is enabled"
|
||||||
|
msgstr "NTV est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:269
|
||||||
|
msgid "HKX ID"
|
||||||
|
msgstr "ID HKX"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:276
|
||||||
|
msgid "HKX is enabled"
|
||||||
|
msgstr "HKX est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:280
|
||||||
|
msgid "Renfe ID"
|
||||||
|
msgstr "ID Renfe"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:287
|
||||||
|
msgid "Renfe is enabled"
|
||||||
|
msgstr "Renfe est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:292
|
||||||
|
msgid "ATOC ID"
|
||||||
|
msgstr "ID ATOC"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:299
|
||||||
|
msgid "ATOC is enabled"
|
||||||
|
msgstr "ATOC est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:304
|
||||||
|
msgid "Benerail ID"
|
||||||
|
msgstr "ID Benerail"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:311
|
||||||
|
msgid "Benerail is enabled"
|
||||||
|
msgstr "Benerail est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:316
|
||||||
|
msgid "Westbahn ID"
|
||||||
|
msgstr "ID Westbahn"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:323
|
||||||
|
msgid "Westbahn is enabled"
|
||||||
|
msgstr "Westbahn est activé"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:327
|
||||||
|
msgid "SNCF self-service machine"
|
||||||
|
msgstr "Automate self-service SNCF"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:333
|
||||||
|
msgid "same as"
|
||||||
|
msgstr "identique à"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:342
|
||||||
|
msgid "info (DE)"
|
||||||
|
msgstr "info (DE)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:350
|
||||||
|
msgid "info (EN)"
|
||||||
|
msgstr "info (EN)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:358
|
||||||
|
msgid "info (ES)"
|
||||||
|
msgstr "info (ES)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:366
|
||||||
|
msgid "info (FR)"
|
||||||
|
msgstr "info (FR)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:374
|
||||||
|
msgid "info (IT)"
|
||||||
|
msgstr "info (IT)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:382
|
||||||
|
msgid "info (NB)"
|
||||||
|
msgstr "info (NB)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:390
|
||||||
|
msgid "info (NL)"
|
||||||
|
msgstr "info (NL)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:398
|
||||||
|
msgid "info (CS)"
|
||||||
|
msgstr "info (CS)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:406
|
||||||
|
msgid "info (DA)"
|
||||||
|
msgstr "info (DA)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:414
|
||||||
|
msgid "info (HU)"
|
||||||
|
msgstr "info (HU)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:422
|
||||||
|
msgid "info (JA)"
|
||||||
|
msgstr "info (JA)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:430
|
||||||
|
msgid "info (KO)"
|
||||||
|
msgstr "info (KO)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:438
|
||||||
|
msgid "info (PL)"
|
||||||
|
msgstr "info (PL)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:446
|
||||||
|
msgid "info (PT)"
|
||||||
|
msgstr "info (PT)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:454
|
||||||
|
msgid "info (RU)"
|
||||||
|
msgstr "info (RU)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:462
|
||||||
|
msgid "info (SV)"
|
||||||
|
msgstr "info (SV)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:470
|
||||||
|
msgid "info (TR)"
|
||||||
|
msgstr "info (TR)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:478
|
||||||
|
msgid "info (ZH)"
|
||||||
|
msgstr "info (ZH)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:486
|
||||||
|
msgid "normalized code (Trainline)"
|
||||||
|
msgstr "code normalisé (Trainline)"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:491
|
||||||
|
msgid "IATA airport code"
|
||||||
|
msgstr "code aéroport IATA"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:501
|
||||||
|
msgid "station"
|
||||||
|
msgstr "gare"
|
||||||
|
|
||||||
|
#: trainvel/core/models.py:502
|
||||||
|
msgid "stations"
|
||||||
|
msgstr "gares"
|
0
trainvel/core/management/__init__.py
Normal file
0
trainvel/core/management/__init__.py
Normal file
0
trainvel/core/management/commands/__init__.py
Normal file
0
trainvel/core/management/commands/__init__.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import csv
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
from trainvel.core.models import Station
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
def convert_value(value: str) -> str:
|
||||||
|
return True if value == 't' else False if value == 'f' else (value or None)
|
||||||
|
|
||||||
|
stations, stations_without_fk = [], []
|
||||||
|
|
||||||
|
STATIONS_URL = "https://raw.githubusercontent.com/trainline-eu/stations/master/stations.csv"
|
||||||
|
with requests.get(STATIONS_URL, stream=True) as resp:
|
||||||
|
for row in csv.DictReader(tqdm(resp.iter_lines(decode_unicode=True)), delimiter=';'):
|
||||||
|
row: dict
|
||||||
|
values = {k.replace(':', '_').replace('normalised_code', 'normalized_code_trainline')
|
||||||
|
.replace('same_as', 'same_as_id'): convert_value(v)
|
||||||
|
for k, v in row.items()}
|
||||||
|
values_without_fk = values.copy()
|
||||||
|
del values_without_fk['same_as_id']
|
||||||
|
del values_without_fk['parent_station_id']
|
||||||
|
stations.append(Station(**values))
|
||||||
|
stations_without_fk.append(Station(**values_without_fk))
|
||||||
|
|
||||||
|
Station.objects.bulk_create(stations_without_fk, update_conflicts=True, unique_fields=['id'],
|
||||||
|
update_fields=[k for k in values_without_fk.keys() if k != 'id'])
|
||||||
|
Station.objects.bulk_create(stations, update_conflicts=True, unique_fields=['id'],
|
||||||
|
update_fields=['same_as_id', 'parent_station_id'])
|
603
trainvel/core/migrations/0001_initial.py
Normal file
603
trainvel/core/migrations/0001_initial.py
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
# Generated by Django 5.0.1 on 2024-05-09 22:15
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Station",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=255, verbose_name="name")),
|
||||||
|
("slug", models.SlugField(max_length=255, verbose_name="slug")),
|
||||||
|
(
|
||||||
|
"uic",
|
||||||
|
models.IntegerField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="UIC"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"uic8_sncf",
|
||||||
|
models.IntegerField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="UIC8 SNCF"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"latitude",
|
||||||
|
models.FloatField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="latitude"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"longitude",
|
||||||
|
models.FloatField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="longitude"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"country",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("AL", "Albania"),
|
||||||
|
("AD", "Andorra"),
|
||||||
|
("AM", "Armenia"),
|
||||||
|
("AT", "Austria"),
|
||||||
|
("AZ", "Azerbaijan"),
|
||||||
|
("BE", "Belgium"),
|
||||||
|
("BA", "Bosnia and Herzegovina"),
|
||||||
|
("BG", "Bulgaria"),
|
||||||
|
("HR", "Croatia"),
|
||||||
|
("CY", "Cyprus"),
|
||||||
|
("CZ", "Czech Republic"),
|
||||||
|
("DK", "Denmark"),
|
||||||
|
("EE", "Estonia"),
|
||||||
|
("FI", "Finland"),
|
||||||
|
("FR", "France"),
|
||||||
|
("GE", "Georgia"),
|
||||||
|
("DE", "Germany"),
|
||||||
|
("GR", "Greece"),
|
||||||
|
("HU", "Hungary"),
|
||||||
|
("IS", "Iceland"),
|
||||||
|
("IE", "Ireland"),
|
||||||
|
("IT", "Italy"),
|
||||||
|
("LV", "Latvia"),
|
||||||
|
("LI", "Liechtenstein"),
|
||||||
|
("LT", "Lithuania"),
|
||||||
|
("LU", "Luxembourg"),
|
||||||
|
("MT", "Malta"),
|
||||||
|
("MD", "Moldova"),
|
||||||
|
("MC", "Monaco"),
|
||||||
|
("ME", "Montenegro"),
|
||||||
|
("NL", "Netherlands"),
|
||||||
|
("MK", "North Macedonia"),
|
||||||
|
("NO", "Norway"),
|
||||||
|
("PL", "Poland"),
|
||||||
|
("PT", "Portugal"),
|
||||||
|
("RO", "Romania"),
|
||||||
|
("SM", "San Marino"),
|
||||||
|
("RS", "Serbia"),
|
||||||
|
("SK", "Slovakia"),
|
||||||
|
("SI", "Slovenia"),
|
||||||
|
("ES", "Spain"),
|
||||||
|
("SE", "Sweden"),
|
||||||
|
("CH", "Switzerland"),
|
||||||
|
("TR", "Turkey"),
|
||||||
|
("GB", "United Kingdom"),
|
||||||
|
("UA", "Ukraine"),
|
||||||
|
],
|
||||||
|
max_length=255,
|
||||||
|
verbose_name="country",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"time_zone",
|
||||||
|
models.CharField(max_length=255, verbose_name="timezone"),
|
||||||
|
),
|
||||||
|
("is_city", models.BooleanField(verbose_name="is city")),
|
||||||
|
(
|
||||||
|
"is_main_station",
|
||||||
|
models.BooleanField(verbose_name="is main station"),
|
||||||
|
),
|
||||||
|
("is_airport", models.BooleanField(verbose_name="is airport")),
|
||||||
|
("is_suggestable", models.BooleanField(verbose_name="is suggestable")),
|
||||||
|
("country_hint", models.BooleanField(verbose_name="country hint")),
|
||||||
|
(
|
||||||
|
"main_station_hint",
|
||||||
|
models.BooleanField(verbose_name="main station hint"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"sncf_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=5,
|
||||||
|
null=True,
|
||||||
|
verbose_name="SNCF ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"sncf_tvs_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=3,
|
||||||
|
null=True,
|
||||||
|
verbose_name="SNCF TVS ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"sncf_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="SNCF is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"entur_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Entur ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"entur_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Entur is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"db_id",
|
||||||
|
models.IntegerField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="DB ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("db_is_enabled", models.BooleanField(verbose_name="DB is enabled")),
|
||||||
|
(
|
||||||
|
"busbud_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Busbud ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"busbud_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Busbud is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"distribusion_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="distribusion ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"distribusion_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="distribusion is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flixbus_id",
|
||||||
|
models.IntegerField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="Flixbus ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"flixbus_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Flixbus is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"cff_id",
|
||||||
|
models.IntegerField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="CFF ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("cff_is_enabled", models.BooleanField(verbose_name="CFF is enabled")),
|
||||||
|
(
|
||||||
|
"leoexpress_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Leo Express ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"leoexpress_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Leo Express is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"obb_id",
|
||||||
|
models.IntegerField(
|
||||||
|
blank=True, default=None, null=True, verbose_name="ÖBB ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("obb_is_enabled", models.BooleanField(verbose_name="ÖBB is enabled")),
|
||||||
|
(
|
||||||
|
"ouigo_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Ouigo ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ouigo_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Ouigo is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"trenitalia_id",
|
||||||
|
models.IntegerField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Trenitalia ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"trenitalia_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Trenitalia is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"trenitalia_rtvt_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Trenitalia RTVT ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"trenord_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Trenord ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ntv_rtiv_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="NTV RTIV ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"ntv_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="NTV ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("ntv_is_enabled", models.BooleanField(verbose_name="NTV is enabled")),
|
||||||
|
(
|
||||||
|
"hkx_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="HKX ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("hkx_is_enabled", models.BooleanField(verbose_name="HKX is enabled")),
|
||||||
|
(
|
||||||
|
"renfe_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Renfe ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"renfe_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Renfe is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"atoc_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="ATOC ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"atoc_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="ATOC is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"benerail_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Benerail ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"benerail_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Benerail is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"westbahn_id",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Westbahn ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"westbahn_is_enabled",
|
||||||
|
models.BooleanField(verbose_name="Westbahn is enabled"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"sncf_self_service_machine",
|
||||||
|
models.BooleanField(verbose_name="SNCF self-service machine"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_de",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (DE)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_en",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (EN)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_es",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (ES)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_fr",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (FR)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_it",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (IT)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_nb",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (NB)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_nl",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (NL)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_cs",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (CS)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_da",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (DA)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_hu",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (HU)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_ja",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (JA)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_ko",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (KO)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_pl",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (PL)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_pt",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (PT)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_ru",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (RU)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_sv",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (SV)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_tr",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (TR)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"info_zh",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="info (ZH)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"normalized_code_trainline",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="normalized code (Trainline)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"iata_airport_code",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
verbose_name="IATA airport code",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"parent_station",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="children",
|
||||||
|
to="core.station",
|
||||||
|
verbose_name="parent station",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"same_as",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="same_as_other",
|
||||||
|
to="core.station",
|
||||||
|
verbose_name="same as",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "station",
|
||||||
|
"verbose_name_plural": "stations",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
0
trainvel/core/migrations/__init__.py
Normal file
0
trainvel/core/migrations/__init__.py
Normal file
519
trainvel/core/models.py
Normal file
519
trainvel/core/models.py
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models import F, QuerySet
|
||||||
|
from django.db.models.functions import ACos, Sin, Radians, Cos
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from trainvel.gtfs.models import Country, Stop
|
||||||
|
|
||||||
|
|
||||||
|
class Station(models.Model):
|
||||||
|
"""
|
||||||
|
Describes the content of the stations CSV file generated by Trainline.
|
||||||
|
The CSV file can be found at https://raw.githubusercontent.com/trainline-eu/stations/master/stations.csv
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
slug = models.SlugField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("slug"),
|
||||||
|
)
|
||||||
|
|
||||||
|
uic = models.IntegerField(
|
||||||
|
verbose_name=_("UIC"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
uic8_sncf = models.IntegerField(
|
||||||
|
verbose_name=_("UIC8 SNCF"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
latitude = models.FloatField(
|
||||||
|
verbose_name=_("latitude"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
longitude = models.FloatField(
|
||||||
|
verbose_name=_("longitude"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
parent_station = models.ForeignKey(
|
||||||
|
"Station",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name=_("parent station"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
related_name="children",
|
||||||
|
)
|
||||||
|
|
||||||
|
country = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("country"),
|
||||||
|
choices=Country,
|
||||||
|
)
|
||||||
|
|
||||||
|
time_zone = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("timezone"),
|
||||||
|
)
|
||||||
|
|
||||||
|
is_city = models.BooleanField(
|
||||||
|
verbose_name=_("is city"),
|
||||||
|
)
|
||||||
|
|
||||||
|
is_main_station = models.BooleanField(
|
||||||
|
verbose_name=_("is main station"),
|
||||||
|
)
|
||||||
|
|
||||||
|
is_airport = models.BooleanField(
|
||||||
|
verbose_name=_("is airport"),
|
||||||
|
)
|
||||||
|
|
||||||
|
is_suggestable = models.BooleanField(
|
||||||
|
verbose_name=_("is suggestable"),
|
||||||
|
)
|
||||||
|
|
||||||
|
country_hint = models.BooleanField(
|
||||||
|
verbose_name=_("country hint"),
|
||||||
|
)
|
||||||
|
|
||||||
|
main_station_hint = models.BooleanField(
|
||||||
|
verbose_name=_("main station hint"),
|
||||||
|
)
|
||||||
|
|
||||||
|
sncf_id = models.CharField(
|
||||||
|
max_length=5,
|
||||||
|
verbose_name=_("SNCF ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
sncf_tvs_id = models.CharField(
|
||||||
|
max_length=3,
|
||||||
|
verbose_name=_("SNCF TVS ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
sncf_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("SNCF is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
entur_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Entur ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
entur_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Entur is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
db_id = models.IntegerField(
|
||||||
|
verbose_name=_("DB ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
db_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("DB is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
busbud_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Busbud ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
busbud_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Busbud is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
distribusion_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("distribusion ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
distribusion_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("distribusion is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
flixbus_id = models.IntegerField(
|
||||||
|
verbose_name=_("Flixbus ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
flixbus_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Flixbus is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
cff_id = models.IntegerField(
|
||||||
|
verbose_name=_("CFF ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
cff_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("CFF is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
leoexpress_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Leo Express ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
leoexpress_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Leo Express is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
obb_id = models.IntegerField(
|
||||||
|
verbose_name=_("ÖBB ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
obb_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("ÖBB is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
ouigo_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Ouigo ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
ouigo_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Ouigo is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
trenitalia_id = models.IntegerField(
|
||||||
|
verbose_name=_("Trenitalia ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
trenitalia_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Trenitalia is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
trenitalia_rtvt_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Trenitalia RTVT ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
trenord_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Trenord ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
ntv_rtiv_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("NTV RTIV ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
ntv_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("NTV ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
ntv_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("NTV is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
hkx_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("HKX ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
hkx_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("HKX is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
renfe_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Renfe ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
renfe_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Renfe is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
atoc_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("ATOC ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
atoc_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("ATOC is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
benerail_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Benerail ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
benerail_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Benerail is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
westbahn_id = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("Westbahn ID"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
westbahn_is_enabled = models.BooleanField(
|
||||||
|
verbose_name=_("Westbahn is enabled"),
|
||||||
|
)
|
||||||
|
|
||||||
|
sncf_self_service_machine = models.BooleanField(
|
||||||
|
verbose_name=_("SNCF self-service machine"),
|
||||||
|
)
|
||||||
|
|
||||||
|
same_as = models.ForeignKey(
|
||||||
|
"Station",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
verbose_name=_("same as"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
related_name="same_as_other",
|
||||||
|
)
|
||||||
|
|
||||||
|
info_de = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (DE)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_en = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (EN)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_es = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (ES)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_fr = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (FR)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_it = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (IT)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_nb = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (NB)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_nl = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (NL)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_cs = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (CS)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_da = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (DA)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_hu = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (HU)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_ja = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (JA)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_ko = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (KO)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_pl = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (PL)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_pt = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (PT)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_ru = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (RU)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_sv = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (SV)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_tr = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (TR)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
info_zh = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("info (ZH)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
normalized_code_trainline = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("normalized code (Trainline)"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
iata_airport_code = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("IATA airport code"),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_near_stops(self, radius: float = settings.STATION_RADIUS) -> QuerySet[Stop]:
|
||||||
|
"""
|
||||||
|
Returns a queryset of all stops that are in a radius of radius meters around the station.
|
||||||
|
It calculates a distance from each stop to the station using spatial coordinates.
|
||||||
|
"""
|
||||||
|
return Stop.objects.annotate(distance=6371000 * ACos(
|
||||||
|
Sin(Radians(self.latitude)) * Sin(Radians(F('lat')))
|
||||||
|
+ Cos(Radians(self.latitude)) * Cos(Radians(F('lat'))) * Cos(Radians(F('lon')) - Radians(self.longitude))))\
|
||||||
|
.filter(distance__lte=radius)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("station")
|
||||||
|
verbose_name_plural = _("stations")
|
3
trainvel/core/tests.py
Normal file
3
trainvel/core/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
3
trainvel/core/views.py
Normal file
3
trainvel/core/views.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
@ -88,5 +88,15 @@
|
|||||||
"feed_url": "https://opentransportdata.swiss/fr/dataset/timetable-2024-gtfs2020/permalink",
|
"feed_url": "https://opentransportdata.swiss/fr/dataset/timetable-2024-gtfs2020/permalink",
|
||||||
"rt_feed_url": "https://api.opentransportdata.swiss/gtfsrt2020"
|
"rt_feed_url": "https://api.opentransportdata.swiss/gtfsrt2020"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "gtfs.gtfsfeed",
|
||||||
|
"pk": "LU-ALL",
|
||||||
|
"fields": {
|
||||||
|
"name": "CFL",
|
||||||
|
"country": "LU",
|
||||||
|
"feed_url": "https://data.public.lu/fr/datasets/r/aab2922d-27ff-4e53-a789-d990cf1ceb1e",
|
||||||
|
"rt_feed_url": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -155,7 +155,7 @@ class Command(BaseCommand):
|
|||||||
unique_fields=['id'])
|
unique_fields=['id'])
|
||||||
routes.clear()
|
routes.clear()
|
||||||
|
|
||||||
# Calendar.objects.filter(gtfs_feed=gtfs_feed).delete()
|
Calendar.objects.filter(gtfs_feed=gtfs_feed).delete()
|
||||||
calendars = {}
|
calendars = {}
|
||||||
if "calendar.txt" in zipfile.namelist():
|
if "calendar.txt" in zipfile.namelist():
|
||||||
for calendar_dict in csv.DictReader(tqdm(read_file("calendar.txt"), desc="Calendars")):
|
for calendar_dict in csv.DictReader(tqdm(read_file("calendar.txt"), desc="Calendars")):
|
||||||
@ -294,14 +294,14 @@ class Command(BaseCommand):
|
|||||||
dep_h, dep_m, dep_s = map(int, dep_time.split(':'))
|
dep_h, dep_m, dep_s = map(int, dep_time.split(':'))
|
||||||
dep_time = dep_h * 3600 + dep_m * 60 + dep_s
|
dep_time = dep_h * 3600 + dep_m * 60 + dep_s
|
||||||
|
|
||||||
pickup_type = stop_time_dict.get('pickup_type', 0)
|
pickup_type = stop_time_dict.get('pickup_type', PickupType.REGULAR)
|
||||||
drop_off_type = stop_time_dict.get('drop_off_type', 0)
|
drop_off_type = stop_time_dict.get('drop_off_type', PickupType.REGULAR)
|
||||||
if stop_time_dict['stop_sequence'] == "1":
|
# if stop_time_dict['stop_sequence'] == "1":
|
||||||
# First stop
|
# # First stop
|
||||||
drop_off_type = PickupType.NONE
|
# drop_off_type = PickupType.NONE
|
||||||
elif arr_time == dep_time:
|
# elif arr_time == dep_time:
|
||||||
# Last stop
|
# # Last stop
|
||||||
pickup_type = PickupType.NONE
|
# pickup_type = PickupType.NONE
|
||||||
|
|
||||||
st = StopTime(
|
st = StopTime(
|
||||||
id=f"{gtfs_code}-{stop_time_dict['trip_id']}-{stop_time_dict['stop_id']}"
|
id=f"{gtfs_code}-{stop_time_dict['trip_id']}-{stop_time_dict['stop_id']}"
|
||||||
@ -349,7 +349,7 @@ class Command(BaseCommand):
|
|||||||
from_stop_id=from_stop_id,
|
from_stop_id=from_stop_id,
|
||||||
to_stop_id=to_stop_id,
|
to_stop_id=to_stop_id,
|
||||||
transfer_type=transfer_dict['transfer_type'],
|
transfer_type=transfer_dict['transfer_type'],
|
||||||
min_transfer_time=transfer_dict['min_transfer_time'],
|
min_transfer_time=transfer_dict.get('min_transfer_time', 0) or 0,
|
||||||
)
|
)
|
||||||
transfers.append(transfer)
|
transfers.append(transfer)
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class Command(BaseCommand):
|
|||||||
headers = {}
|
headers = {}
|
||||||
if gtfs_code == "CH-ALL":
|
if gtfs_code == "CH-ALL":
|
||||||
headers["Authorization"] = settings.OPENTRANSPORTDATA_SWISS_TOKEN
|
headers["Authorization"] = settings.OPENTRANSPORTDATA_SWISS_TOKEN
|
||||||
resp = requests.get(gtfs_feed.rt_feed_url, allow_redirects=True)
|
resp = requests.get(gtfs_feed.rt_feed_url, allow_redirects=True, headers=headers)
|
||||||
feed_message = FeedMessage()
|
feed_message = FeedMessage()
|
||||||
feed_message.ParseFromString(resp.content)
|
feed_message.ParseFromString(resp.content)
|
||||||
|
|
||||||
@ -41,87 +41,88 @@ class Command(BaseCommand):
|
|||||||
f.write(str(feed_message))
|
f.write(str(feed_message))
|
||||||
|
|
||||||
for entity in feed_message.entity:
|
for entity in feed_message.entity:
|
||||||
if entity.HasField("trip_update"):
|
try:
|
||||||
trip_update = entity.trip_update
|
if entity.HasField("trip_update"):
|
||||||
trip_id = trip_update.trip.trip_id
|
trip_update = entity.trip_update
|
||||||
trip_id = f"{gtfs_code}-{trip_id}"
|
trip_id = trip_update.trip.trip_id
|
||||||
|
trip_id = f"{gtfs_code}-{trip_id}"
|
||||||
|
|
||||||
start_date = date(year=int(trip_update.trip.start_date[:4]),
|
start_date = date(year=int(trip_update.trip.start_date[:4]),
|
||||||
month=int(trip_update.trip.start_date[4:6]),
|
month=int(trip_update.trip.start_date[4:6]),
|
||||||
day=int(trip_update.trip.start_date[6:]))
|
day=int(trip_update.trip.start_date[6:]))
|
||||||
start_dt = datetime.combine(start_date, time(0), tzinfo=ZoneInfo("Europe/Paris"))
|
start_dt = datetime.combine(start_date, time(0), tzinfo=ZoneInfo("Europe/Paris"))
|
||||||
|
|
||||||
if trip_update.trip.schedule_relationship == TripScheduleRelationship.ADDED:
|
if trip_update.trip.schedule_relationship == TripScheduleRelationship.ADDED:
|
||||||
# C'est un trajet nouveau. On crée le trajet associé.
|
# C'est un trajet nouveau. On crée le trajet associé.
|
||||||
self.create_trip(trip_update, trip_id, start_dt, gtfs_feed)
|
self.create_trip(trip_update, trip_id, start_dt, gtfs_feed)
|
||||||
|
|
||||||
if not Trip.objects.filter(id=trip_id).exists():
|
if not Trip.objects.filter(id=trip_id).exists():
|
||||||
self.stdout.write(f"Trip {trip_id} does not exist in the GTFS feed.")
|
self.stdout.write(f"Trip {trip_id} does not exist in the GTFS feed.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Création du TripUpdate
|
# Création du TripUpdate
|
||||||
tu, _created = TripUpdate.objects.update_or_create(
|
tu, _created = TripUpdate.objects.update_or_create(
|
||||||
trip_id=trip_id,
|
trip_id=trip_id,
|
||||||
start_date=trip_update.trip.start_date,
|
start_date=trip_update.trip.start_date,
|
||||||
start_time=trip_update.trip.start_time,
|
start_time=trip_update.trip.start_time,
|
||||||
defaults=dict(
|
defaults=dict(
|
||||||
schedule_relationship=trip_update.trip.schedule_relationship,
|
schedule_relationship=trip_update.trip.schedule_relationship,
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for stop_sequence, stop_time_update in enumerate(trip_update.stop_time_update):
|
|
||||||
stop_id = stop_time_update.stop_id
|
|
||||||
stop_id = f"{gtfs_code}-{stop_id}"
|
|
||||||
if StopTime.objects.filter(trip_id=trip_id, stop=stop_id).exists():
|
|
||||||
st = StopTime.objects.filter(trip_id=trip_id, stop=stop_id)
|
|
||||||
if st.count() > 1:
|
|
||||||
st = st.get(stop_sequence=stop_sequence)
|
|
||||||
else:
|
|
||||||
st = st.first()
|
|
||||||
else:
|
|
||||||
# Stop is added
|
|
||||||
st = StopTime.objects.create(
|
|
||||||
id=f"{trip_id}-{stop_time_update.stop_id}",
|
|
||||||
trip_id=trip_id,
|
|
||||||
stop_id=stop_id,
|
|
||||||
defaults={
|
|
||||||
"stop_sequence": stop_sequence,
|
|
||||||
"arrival_time": datetime.fromtimestamp(stop_time_update.arrival.time,
|
|
||||||
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
|
||||||
"departure_time": datetime.fromtimestamp(stop_time_update.departure.time,
|
|
||||||
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
|
||||||
"pickup_type": (PickupType.REGULAR if stop_time_update.departure.time
|
|
||||||
else PickupType.NONE),
|
|
||||||
"drop_off_type": (PickupType.REGULAR if stop_time_update.arrival.time
|
|
||||||
else PickupType.NONE),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if stop_time_update.schedule_relationship == StopScheduleRelationship.SKIPPED:
|
for stop_sequence, stop_time_update in enumerate(trip_update.stop_time_update):
|
||||||
if st.pickup_type != PickupType.NONE or st.drop_off_type != PickupType.NONE:
|
stop_id = stop_time_update.stop_id
|
||||||
st.pickup_type = PickupType.NONE
|
stop_id = f"{gtfs_code}-{stop_id}"
|
||||||
st.drop_off_type = PickupType.NONE
|
if StopTime.objects.filter(trip_id=trip_id, stop=stop_id).exists():
|
||||||
|
st = StopTime.objects.filter(trip_id=trip_id, stop=stop_id)
|
||||||
|
if st.count() > 1:
|
||||||
|
st = st.get(stop_sequence=stop_sequence)
|
||||||
|
else:
|
||||||
|
st = st.first()
|
||||||
|
else:
|
||||||
|
# Stop is added
|
||||||
|
st = StopTime.objects.create(
|
||||||
|
id=f"{trip_id}-{stop_time_update.stop_id}",
|
||||||
|
trip_id=trip_id,
|
||||||
|
stop_id=stop_id,
|
||||||
|
stop_sequence=stop_sequence,
|
||||||
|
arrival_time=datetime.fromtimestamp(stop_time_update.arrival.time,
|
||||||
|
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
||||||
|
departure_time=datetime.fromtimestamp(stop_time_update.departure.time,
|
||||||
|
tz=ZoneInfo("Europe/Paris")) - start_dt,
|
||||||
|
pickup_type=(PickupType.REGULAR if stop_time_update.departure.time
|
||||||
|
else PickupType.NONE),
|
||||||
|
drop_off_type=(PickupType.REGULAR if stop_time_update.arrival.time
|
||||||
|
else PickupType.NONE),
|
||||||
|
)
|
||||||
|
|
||||||
|
if stop_time_update.schedule_relationship == StopScheduleRelationship.SKIPPED:
|
||||||
|
if st.pickup_type != PickupType.NONE or st.drop_off_type != PickupType.NONE:
|
||||||
|
st.pickup_type = PickupType.NONE
|
||||||
|
st.drop_off_type = PickupType.NONE
|
||||||
|
st.save()
|
||||||
|
|
||||||
|
if st.stop_sequence != stop_sequence:
|
||||||
|
st.stop_sequence = stop_sequence
|
||||||
st.save()
|
st.save()
|
||||||
|
|
||||||
if st.stop_sequence != stop_sequence:
|
st_update = StopTimeUpdate(
|
||||||
st.stop_sequence = stop_sequence
|
trip_update=tu,
|
||||||
st.save()
|
stop_time=st,
|
||||||
|
arrival_delay=timedelta(seconds=stop_time_update.arrival.delay),
|
||||||
st_update = StopTimeUpdate(
|
arrival_time=datetime.fromtimestamp(stop_time_update.arrival.time,
|
||||||
trip_update=tu,
|
tz=ZoneInfo("Europe/Paris")),
|
||||||
stop_time=st,
|
departure_delay=timedelta(seconds=stop_time_update.departure.delay),
|
||||||
arrival_delay=timedelta(seconds=stop_time_update.arrival.delay),
|
departure_time=datetime.fromtimestamp(stop_time_update.departure.time,
|
||||||
arrival_time=datetime.fromtimestamp(stop_time_update.arrival.time,
|
tz=ZoneInfo("Europe/Paris")),
|
||||||
tz=ZoneInfo("Europe/Paris")),
|
schedule_relationship=stop_time_update.schedule_relationship
|
||||||
departure_delay=timedelta(seconds=stop_time_update.departure.delay),
|
or StopScheduleRelationship.SCHEDULED,
|
||||||
departure_time=datetime.fromtimestamp(stop_time_update.departure.time,
|
)
|
||||||
tz=ZoneInfo("Europe/Paris")),
|
stop_times_updates.append(st_update)
|
||||||
schedule_relationship=stop_time_update.schedule_relationship
|
else:
|
||||||
or StopScheduleRelationship.SCHEDULED,
|
self.stdout.write(str(entity))
|
||||||
)
|
except Exception as e:
|
||||||
stop_times_updates.append(st_update)
|
self.stderr.write(self.style.ERROR(f"Error while processing entity: {e}"))
|
||||||
else:
|
|
||||||
self.stdout.write(str(entity))
|
|
||||||
|
|
||||||
StopTimeUpdate.objects.bulk_create(stop_times_updates,
|
StopTimeUpdate.objects.bulk_create(stop_times_updates,
|
||||||
update_conflicts=True,
|
update_conflicts=True,
|
||||||
|
@ -45,6 +45,7 @@ INSTALLED_APPS = [
|
|||||||
"rest_framework",
|
"rest_framework",
|
||||||
|
|
||||||
"trainvel.api",
|
"trainvel.api",
|
||||||
|
"trainvel.core",
|
||||||
"trainvel.gtfs",
|
"trainvel.gtfs",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -150,6 +151,8 @@ REST_FRAMEWORK = {
|
|||||||
'PAGE_SIZE': 20,
|
'PAGE_SIZE': 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATION_RADIUS = 300
|
||||||
|
|
||||||
OPENTRANSPORTDATA_SWISS_TOKEN = "CHANGE ME"
|
OPENTRANSPORTDATA_SWISS_TOKEN = "CHANGE ME"
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,11 +18,12 @@ from django.contrib import admin
|
|||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
|
|
||||||
from trainvel.api.views import AgencyViewSet, StopViewSet, RouteViewSet, TripViewSet, StopTimeViewSet, \
|
from trainvel.api.views import AgencyViewSet, StopViewSet, RouteViewSet, StationViewSet, TripViewSet, StopTimeViewSet, \
|
||||||
CalendarViewSet, CalendarDateViewSet, TransferViewSet, FeedInfoViewSet, NextDeparturesViewSet, NextArrivalsViewSet, \
|
CalendarViewSet, CalendarDateViewSet, TransferViewSet, FeedInfoViewSet, NextDeparturesViewSet, NextArrivalsViewSet, \
|
||||||
TripUpdateViewSet, StopTimeUpdateViewSet
|
TripUpdateViewSet, StopTimeUpdateViewSet
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
|
router.register("core/station", StationViewSet)
|
||||||
router.register("gtfs/agency", AgencyViewSet)
|
router.register("gtfs/agency", AgencyViewSet)
|
||||||
router.register("gtfs/stop", StopViewSet)
|
router.register("gtfs/stop", StopViewSet)
|
||||||
router.register("gtfs/route", RouteViewSet)
|
router.register("gtfs/route", RouteViewSet)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user