Cookies and tests
- Added cookie banner - Improved tests and fixed models accordingly
This commit is contained in:
parent
cf6fcda0ed
commit
53ab731787
|
|
@ -34,7 +34,7 @@ class_names = [
|
||||||
"Level": pt_map.models.Level,
|
"Level": pt_map.models.Level,
|
||||||
"LocationGroup": pt_map.models.LocationGroup,
|
"LocationGroup": pt_map.models.LocationGroup,
|
||||||
"LocationGroupStop": pt_map.models.LocationGroupStop,
|
"LocationGroupStop": pt_map.models.LocationGroupStop,
|
||||||
"LocationsGeojson": pt_map.models.LocationsGeojson,
|
"Location": pt_map.models.Location,
|
||||||
"BookingRule": pt_map.models.BookingRule,
|
"BookingRule": pt_map.models.BookingRule,
|
||||||
"Translation": pt_map.models.Translation,
|
"Translation": pt_map.models.Translation,
|
||||||
"FeedInfo": pt_map.models.FeedInfo,
|
"FeedInfo": pt_map.models.FeedInfo,
|
||||||
|
|
@ -66,7 +66,7 @@ class_names = [
|
||||||
"levels": pt_map.models.Level,
|
"levels": pt_map.models.Level,
|
||||||
"location_groups": pt_map.models.LocationGroup,
|
"location_groups": pt_map.models.LocationGroup,
|
||||||
"location_group_stops": pt_map.models.LocationGroupStop,
|
"location_group_stops": pt_map.models.LocationGroupStop,
|
||||||
"locations": pt_map.models.LocationsGeojson,
|
"locations": pt_map.models.Location,
|
||||||
"booking_rules": pt_map.models.BookingRule,
|
"booking_rules": pt_map.models.BookingRule,
|
||||||
"translations": pt_map.models.Translation,
|
"translations": pt_map.models.Translation,
|
||||||
"feed_info": pt_map.models.FeedInfo,
|
"feed_info": pt_map.models.FeedInfo,
|
||||||
|
|
@ -98,7 +98,7 @@ class_names = [
|
||||||
pt_map.models.Level: "Level",
|
pt_map.models.Level: "Level",
|
||||||
pt_map.models.LocationGroup: "LocationGroup",
|
pt_map.models.LocationGroup: "LocationGroup",
|
||||||
pt_map.models.LocationGroupStop: "LocationGroupStop",
|
pt_map.models.LocationGroupStop: "LocationGroupStop",
|
||||||
pt_map.models.LocationsGeojson: "LocationsGeojson",
|
pt_map.models.Location: "Location",
|
||||||
pt_map.models.BookingRule: "BookingRule",
|
pt_map.models.BookingRule: "BookingRule",
|
||||||
pt_map.models.Translation: "Translation",
|
pt_map.models.Translation: "Translation",
|
||||||
pt_map.models.FeedInfo: "FeedInfo",
|
pt_map.models.FeedInfo: "FeedInfo",
|
||||||
|
|
@ -130,7 +130,7 @@ pt_map.models.Shape: "shapes",
|
||||||
pt_map.models.Level: "levels",
|
pt_map.models.Level: "levels",
|
||||||
pt_map.models.LocationGroup: "location_groups",
|
pt_map.models.LocationGroup: "location_groups",
|
||||||
pt_map.models.LocationGroupStop: "location_group_stops",
|
pt_map.models.LocationGroupStop: "location_group_stops",
|
||||||
pt_map.models.LocationsGeojson: "locations",
|
pt_map.models.Location: "locations",
|
||||||
pt_map.models.BookingRule: "booking_rules",
|
pt_map.models.BookingRule: "booking_rules",
|
||||||
pt_map.models.Translation: "translations",
|
pt_map.models.Translation: "translations",
|
||||||
pt_map.models.FeedInfo: "feed_info",
|
pt_map.models.FeedInfo: "feed_info",
|
||||||
|
|
@ -166,7 +166,7 @@ file_names = {
|
||||||
pt_map.models.Level: "levels.txt",
|
pt_map.models.Level: "levels.txt",
|
||||||
pt_map.models.LocationGroup: "location_groups.txt",
|
pt_map.models.LocationGroup: "location_groups.txt",
|
||||||
pt_map.models.LocationGroupStop: "location_group_stops.txt",
|
pt_map.models.LocationGroupStop: "location_group_stops.txt",
|
||||||
pt_map.models.LocationsGeojson: "locations.geojson",
|
pt_map.models.Location: "locations.geojson",
|
||||||
pt_map.models.BookingRule: "booking_rules.txt",
|
pt_map.models.BookingRule: "booking_rules.txt",
|
||||||
pt_map.models.Translation: "translations.txt",
|
pt_map.models.Translation: "translations.txt",
|
||||||
pt_map.models.FeedInfo: "feed_info.txt",
|
pt_map.models.FeedInfo: "feed_info.txt",
|
||||||
|
|
@ -199,7 +199,7 @@ reversed_file_mapping = {
|
||||||
"Level": "levels",
|
"Level": "levels",
|
||||||
"LocationGroup": "location_groups",
|
"LocationGroup": "location_groups",
|
||||||
"LocationGroupStop": "location_group_stops",
|
"LocationGroupStop": "location_group_stops",
|
||||||
"LocationsGeojson": "locations_geojson",
|
"Location": "locations_geojson",
|
||||||
"BookingRule": "booking_rules",
|
"BookingRule": "booking_rules",
|
||||||
"Translation": "translations",
|
"Translation": "translations",
|
||||||
"FeedInfo": "feed_info",
|
"FeedInfo": "feed_info",
|
||||||
|
|
@ -207,7 +207,7 @@ reversed_file_mapping = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case_swap = {'Agency': 'agency', 'Stop': 'stops', 'Route': 'routes', 'Trip': 'trips', 'StopTime': 'stop_times', 'Calendar': 'calendar', 'CalendarDate': 'calendar_dates', 'FareAttribute': 'fare_attributes', 'FareRule': 'fare_rules', 'Timeframe': 'timeframes', 'FareMedium': 'fare_media', 'FareProduct': 'fare_products', 'FareLegRule': 'fare_leg_rules', 'FareTransferRule': 'fare_transfer_rules', 'Area': 'areas', 'StopArea': 'stop_areas', 'Network': 'networks', 'RouteNetwork': 'route_networks', 'Shape': 'shapes', 'Frequency': 'frequencies', 'Transfer': 'transfers', 'Pathway': 'pathways', 'Level': 'levels', 'LocationGroup': 'location_groups', 'LocationGroupStop': 'location_group_stops', 'LocationsGeojson': 'locations_geojson', 'BookingRule': 'booking_rules', 'Translation': 'translations', 'FeedInfo': 'feed_info', 'Attribution': 'attributions'}
|
case_swap = {'Agency': 'agency', 'Stop': 'stops', 'Route': 'routes', 'Trip': 'trips', 'StopTime': 'stop_times', 'Calendar': 'calendar', 'CalendarDate': 'calendar_dates', 'FareAttribute': 'fare_attributes', 'FareRule': 'fare_rules', 'Timeframe': 'timeframes', 'FareMedium': 'fare_media', 'FareProduct': 'fare_products', 'FareLegRule': 'fare_leg_rules', 'FareTransferRule': 'fare_transfer_rules', 'Area': 'areas', 'StopArea': 'stop_areas', 'Network': 'networks', 'RouteNetwork': 'route_networks', 'Shape': 'shapes', 'Frequency': 'frequencies', 'Transfer': 'transfers', 'Pathway': 'pathways', 'Level': 'levels', 'LocationGroup': 'location_groups', 'LocationGroupStop': 'location_group_stops', 'Location': 'locations_geojson', 'BookingRule': 'booking_rules', 'Translation': 'translations', 'FeedInfo': 'feed_info', 'Attribution': 'attributions'}
|
||||||
|
|
||||||
|
|
||||||
primary_keys = {
|
primary_keys = {
|
||||||
|
|
@ -221,7 +221,7 @@ primary_keys = {
|
||||||
pt_map.models.CalendarDate: "calendar_date_id",
|
pt_map.models.CalendarDate: "calendar_date_id",
|
||||||
pt_map.models.Trip: "trip_id",
|
pt_map.models.Trip: "trip_id",
|
||||||
pt_map.models.LocationGroup: "location_group_id",
|
pt_map.models.LocationGroup: "location_group_id",
|
||||||
pt_map.models.LocationsGeojson: "location_id",
|
pt_map.models.Location: "location_id",
|
||||||
pt_map.models.StopTime: "stop_time_id",
|
pt_map.models.StopTime: "stop_time_id",
|
||||||
pt_map.models.FareAttribute: "fare_id",
|
pt_map.models.FareAttribute: "fare_id",
|
||||||
pt_map.models.FareRule: "fare_rule_id",
|
pt_map.models.FareRule: "fare_rule_id",
|
||||||
|
|
@ -255,7 +255,7 @@ classes_by_primary_keys = {
|
||||||
'calendar_date_id': pt_map.models.CalendarDate,
|
'calendar_date_id': pt_map.models.CalendarDate,
|
||||||
'trip_id': pt_map.models.Trip,
|
'trip_id': pt_map.models.Trip,
|
||||||
'location_group_id': pt_map.models.LocationGroup,
|
'location_group_id': pt_map.models.LocationGroup,
|
||||||
'location_id': pt_map.models.LocationsGeojson,
|
'location_id': pt_map.models.Location,
|
||||||
'stop_time_id': pt_map.models.StopTime,
|
'stop_time_id': pt_map.models.StopTime,
|
||||||
'fare_id': pt_map.models.FareAttribute,
|
'fare_id': pt_map.models.FareAttribute,
|
||||||
'fare_rule_id': pt_map.models.FareRule,
|
'fare_rule_id': pt_map.models.FareRule,
|
||||||
|
|
@ -288,8 +288,8 @@ foreign_keys = [
|
||||||
(pt_map.models.CalendarDate, [(pt_map.models.FeedInfo, 'feed_info_id'),]),
|
(pt_map.models.CalendarDate, [(pt_map.models.FeedInfo, 'feed_info_id'),]),
|
||||||
(pt_map.models.Trip, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Route, 'route_id'), (pt_map.models.Shape, 'shape_id'), ]),
|
(pt_map.models.Trip, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Route, 'route_id'), (pt_map.models.Shape, 'shape_id'), ]),
|
||||||
(pt_map.models.LocationGroup, [(pt_map.models.FeedInfo, 'feed_info_id'),]),
|
(pt_map.models.LocationGroup, [(pt_map.models.FeedInfo, 'feed_info_id'),]),
|
||||||
(pt_map.models.LocationsGeojson, [(pt_map.models.FeedInfo, 'feed_info_id'),]),
|
(pt_map.models.Location, [(pt_map.models.FeedInfo, 'feed_info_id'),]),
|
||||||
(pt_map.models.StopTime, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Trip, 'trip_id'), (pt_map.models.Stop, 'stop_id'), (pt_map.models.LocationGroup, 'location_group_id'), (pt_map.models.LocationsGeojson, 'location_id'), ]),
|
(pt_map.models.StopTime, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Trip, 'trip_id'), (pt_map.models.Stop, 'stop_id'), (pt_map.models.LocationGroup, 'location_group_id'), (pt_map.models.Location, 'location_id'), ]),
|
||||||
(pt_map.models.FareAttribute, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Agency, 'agency_id'), ]),
|
(pt_map.models.FareAttribute, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Agency, 'agency_id'), ]),
|
||||||
(pt_map.models.FareRule, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.FareAttribute, 'fare_id'), (pt_map.models.Route, 'route_id'), ]),
|
(pt_map.models.FareRule, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.FareAttribute, 'fare_id'), (pt_map.models.Route, 'route_id'), ]),
|
||||||
(pt_map.models.Frequency, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Trip, 'trip_id'), ]),
|
(pt_map.models.Frequency, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.Trip, 'trip_id'), ]),
|
||||||
|
|
@ -325,7 +325,7 @@ fks = {
|
||||||
'trip_id': pt_map.models.Trip,
|
'trip_id': pt_map.models.Trip,
|
||||||
'stop_id': pt_map.models.Stop,
|
'stop_id': pt_map.models.Stop,
|
||||||
'location_group_id': pt_map.models.LocationGroup,
|
'location_group_id': pt_map.models.LocationGroup,
|
||||||
'location_id': pt_map.models.LocationsGeojson,
|
'location_id': pt_map.models.Location,
|
||||||
'fare_id': pt_map.models.FareAttribute,
|
'fare_id': pt_map.models.FareAttribute,
|
||||||
'from_stop_id': pt_map.models.Stop,
|
'from_stop_id': pt_map.models.Stop,
|
||||||
'to_stop_id': pt_map.models.Stop,
|
'to_stop_id': pt_map.models.Stop,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-01 13:18
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pt_map', '0021_alter_stoptime_continuous_drop_off'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Location',
|
||||||
|
fields=[
|
||||||
|
('location_id', models.CharField(max_length=255, primary_key=True, serialize=False)),
|
||||||
|
('stop_name', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
('stop_desc', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
('latitude', models.FloatField()),
|
||||||
|
('longitude', models.FloatField()),
|
||||||
|
('location_type', models.CharField(choices=[('Polygon', 'Polygon'), ('MultiPolygon', 'MultiPolygon')], max_length=255)),
|
||||||
|
('feed_info_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pt_map.feedinfo')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stoptime',
|
||||||
|
name='location_id',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pt_map.location'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='LocationsGeojson',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-01 13:29
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pt_map', '0022_location_alter_stoptime_location_id_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='location',
|
||||||
|
old_name='location_type',
|
||||||
|
new_name='geometry_type',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-02 14:36
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pt_map', '0023_rename_location_type_location_geometry_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='contains_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='destination_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='origin_id',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='contains_id',
|
||||||
|
field=models.ManyToManyField(blank=True, null=True, related_name='fare_rules_for_zone_contains', to='pt_map.route'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='destination_id',
|
||||||
|
field=models.ManyToManyField(blank=True, null=True, related_name='fare_rules_for_zone_as_destination', to='pt_map.route'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='origin_id',
|
||||||
|
field=models.ManyToManyField(blank=True, null=True, related_name='fare_rules_for_zone_as_origin', to='pt_map.route'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-02 14:43
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pt_map', '0024_remove_farerule_contains_id_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='farelegrule',
|
||||||
|
name='network_id',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='pt_map.network'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='network',
|
||||||
|
name='network_name',
|
||||||
|
field=models.CharField(default='', max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='route',
|
||||||
|
name='network_id',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='pt_map.network'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-02 17:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pt_map', '0025_alter_farelegrule_network_id_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='contains_id',
|
||||||
|
field=models.ManyToManyField(blank=True, null=True, related_name='fare_rules_for_zone_contains', to='pt_map.stop'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='destination_id',
|
||||||
|
field=models.ManyToManyField(blank=True, null=True, related_name='fare_rules_for_zone_as_destination', to='pt_map.stop'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='origin_id',
|
||||||
|
field=models.ManyToManyField(blank=True, null=True, related_name='fare_rules_for_zone_as_origin', to='pt_map.stop'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-02 22:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pt_map', '0026_alter_farerule_contains_id_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='farelegrule',
|
||||||
|
name='from_timeframe_group_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='farelegrule',
|
||||||
|
name='to_timeframe_group_id',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='contains_id',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='fare_rules_for_zone_contains', to='pt_map.stop'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='destination_id',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='fare_rules_for_zone_as_destination', to='pt_map.stop'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='farerule',
|
||||||
|
name='origin_id',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='fare_rules_for_zone_as_origin', to='pt_map.stop'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stoptime',
|
||||||
|
name='drop_off_type',
|
||||||
|
field=models.IntegerField(blank=True, choices=[('Regularly scheduled drop off.', 0), ('No drop off available.', 1), ('Must phone agency to arrange drop off.', 2), ('Must coordinate with driver to arrange drop off.', 3)], null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stoptime',
|
||||||
|
name='pickup_type',
|
||||||
|
field=models.IntegerField(blank=True, choices=[('Regularly scheduled pickup.', 0), ('No pickup available.', 1), ('Must phone agency to arrange pickup.', 2), ('Must coordinate with driver to arrange pickup.', 3)], null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stoptime',
|
||||||
|
name='timepoint',
|
||||||
|
field=models.IntegerField(blank=True, choices=[('Times are considered approximate.', 0), ('Times are considered exact.', 1)], null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='farelegrule',
|
||||||
|
name='from_timeframe_group_id',
|
||||||
|
field=models.ManyToManyField(null=True, related_name='fare_leg_rules_from', to='pt_map.timeframe'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='farelegrule',
|
||||||
|
name='to_timeframe_group_id',
|
||||||
|
field=models.ManyToManyField(null=True, related_name='fare_leg_rules_to', to='pt_map.timeframe'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -206,8 +206,8 @@ field_requirements = \
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "network_id",
|
"name": "network_id",
|
||||||
"type": "mtm",
|
"type": "fk",
|
||||||
"references": Route,
|
"references": Network,
|
||||||
"required": "false",
|
"required": "false",
|
||||||
"forbidden_if": ["RouteNetwork", True]
|
"forbidden_if": ["RouteNetwork", True]
|
||||||
},
|
},
|
||||||
|
|
@ -252,8 +252,7 @@ field_requirements = \
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "block_id",
|
"name": "block_id",
|
||||||
"type": "mtm",
|
"type": "unique",
|
||||||
"references": Trip,
|
|
||||||
"required": "false",
|
"required": "false",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -277,6 +276,42 @@ field_requirements = \
|
||||||
],
|
],
|
||||||
"pk": "trip_id",
|
"pk": "trip_id",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"model": "Location",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "location_id",
|
||||||
|
"type": "pk",
|
||||||
|
"required": "true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stop_name",
|
||||||
|
"type": "str",
|
||||||
|
"required": "false",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stop_desc",
|
||||||
|
"type": "str",
|
||||||
|
"required": "false",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "geometry_type",
|
||||||
|
"type": "enum",
|
||||||
|
"allowed_values": ["Polygon", "MultiPolygon"],
|
||||||
|
"required": "true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "latitude",
|
||||||
|
"type": "lat",
|
||||||
|
"required": "true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "longitude",
|
||||||
|
"type": "lon",
|
||||||
|
"required": "true",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"model": "StopTime",
|
"model": "StopTime",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
|
@ -308,7 +343,7 @@ field_requirements = \
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "location_group_id",
|
"name": "location_group_id",
|
||||||
"type": "mtm",
|
"type": "fk",
|
||||||
"references": LocationGroup,
|
"references": LocationGroup,
|
||||||
"required": "false",
|
"required": "false",
|
||||||
"forbidden_if_not": [(["stop_id", None], ["location_id", None])],
|
"forbidden_if_not": [(["stop_id", None], ["location_id", None])],
|
||||||
|
|
@ -317,7 +352,7 @@ field_requirements = \
|
||||||
"name": "location_id",
|
"name": "location_id",
|
||||||
"type": "fk",
|
"type": "fk",
|
||||||
"required": "false",
|
"required": "false",
|
||||||
"references": LocationsGeojson,
|
"references": Location,
|
||||||
"forbidden_if_not": [(["stop_id", None], ["location_group_id", None])],
|
"forbidden_if_not": [(["stop_id", None], ["location_group_id", None])],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -658,7 +693,8 @@ field_requirements = \
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "network_id",
|
"name": "network_id",
|
||||||
"type": "str",
|
"type": "fk",
|
||||||
|
"references": Network,
|
||||||
"required": "false",
|
"required": "false",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Attributes
|
||||||
----------
|
----------
|
||||||
Classes
|
Classes
|
||||||
-------
|
-------
|
||||||
Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate, FareAttribute, FareRule, Shape, Frequency, Transfer, Pathway, Level, FeedInfo, LocationsGeojson, BookingRule, Translation, Attribution, LocationGroup, LocationGroupStop, RouteNetwork, Network, StopArea, Area, FareMedium, FareProduct, FareLegRule, FareTransferRule, Timeframe
|
Agency, Stop, Route, Trip, StopTime, Calendar, CalendarDate, FareAttribute, FareRule, Shape, Frequency, Transfer, Pathway, Level, FeedInfo, Location, BookingRule, Translation, Attribution, LocationGroup, LocationGroupStop, RouteNetwork, Network, StopArea, Area, FareMedium, FareProduct, FareLegRule, FareTransferRule, Timeframe
|
||||||
Different files as described in the GTFS Reference
|
Different files as described in the GTFS Reference
|
||||||
"""
|
"""
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
@ -72,6 +72,14 @@ class Stop(models.Model):
|
||||||
platform_code = models.CharField(max_length=50, blank=True, null=True)
|
platform_code = models.CharField(max_length=50, blank=True, null=True)
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Network(models.Model):
|
||||||
|
"""
|
||||||
|
Represents network.txt from the GTFS Reference.
|
||||||
|
"""
|
||||||
|
network_id = models.CharField(max_length=255, primary_key=True)
|
||||||
|
network_name = models.CharField(max_length=255, default="")
|
||||||
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class Route(models.Model):
|
class Route(models.Model):
|
||||||
"""
|
"""
|
||||||
Represents route.txt from the GTFS Reference.
|
Represents route.txt from the GTFS Reference.
|
||||||
|
|
@ -88,7 +96,7 @@ class Route(models.Model):
|
||||||
route_sort_order = models.IntegerField(blank=True, null=True)
|
route_sort_order = models.IntegerField(blank=True, null=True)
|
||||||
continuous_pickup = models.IntegerField(choices=[("Continous stopping pickup", 0), ("No continuous stopping pickup", 1), ("Must phone agency to arrange continuous stopping pickup off", 2), ("Must coordinate with driver to arrange continuous stopping pickup", 3)], blank=True, null=True)
|
continuous_pickup = models.IntegerField(choices=[("Continous stopping pickup", 0), ("No continuous stopping pickup", 1), ("Must phone agency to arrange continuous stopping pickup off", 2), ("Must coordinate with driver to arrange continuous stopping pickup", 3)], blank=True, null=True)
|
||||||
continuous_drop_off = models.IntegerField(choices=[("Continous stopping pickup", 0), ("No continuous stopping pickup", 1), ("Must phone agency to arrange continuous stopping pickup off", 2), ("Must coordinate with driver to arrange continuous stopping pickup", 3)], blank=True, null=True)
|
continuous_drop_off = models.IntegerField(choices=[("Continous stopping pickup", 0), ("No continuous stopping pickup", 1), ("Must phone agency to arrange continuous stopping pickup off", 2), ("Must coordinate with driver to arrange continuous stopping pickup", 3)], blank=True, null=True)
|
||||||
network_id = models.IntegerField(blank=True, null=True)
|
network_id = models.ForeignKey(Network, on_delete=models.CASCADE, null=True)
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class Shape(models.Model):
|
class Shape(models.Model):
|
||||||
|
|
@ -175,17 +183,16 @@ class LocationGroup(models.Model):
|
||||||
location_group_type = models.CharField(max_length=255)
|
location_group_type = models.CharField(max_length=255)
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class LocationsGeojson(models.Model):
|
class Location(models.Model):
|
||||||
"""
|
"""
|
||||||
Represents locations.geojson from the GTFS Reference.
|
Represents locations.geojson from the GTFS Reference.
|
||||||
"""
|
"""
|
||||||
location_id = models.CharField(max_length=255, primary_key=True)
|
location_id = models.CharField(max_length=255, primary_key=True)
|
||||||
location_name = models.CharField(max_length=255)
|
stop_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
location_lat = models.FloatField()
|
stop_desc = models.CharField(max_length=255, blank=True, null=True)
|
||||||
location_lon = models.FloatField()
|
latitude = models.FloatField()
|
||||||
location_type = models.CharField(max_length=255)
|
longitude = models.FloatField()
|
||||||
parent_location_id = models.CharField(max_length=255, blank=True, null=True)
|
geometry_type = models.CharField(max_length=255, choices=[("Polygon", "Polygon"), ("MultiPolygon", "MultiPolygon")])
|
||||||
wheelchair_boarding = models.BooleanField(blank=True, null=True)
|
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class BookingRule(models.Model):
|
class BookingRule(models.Model):
|
||||||
|
|
@ -219,13 +226,13 @@ class StopTime(models.Model):
|
||||||
departure_time = models.CharField(max_length=255, blank=True, null=True)
|
departure_time = models.CharField(max_length=255, blank=True, null=True)
|
||||||
stop_id = models.ForeignKey(Stop, null=True, on_delete=models.CASCADE)
|
stop_id = models.ForeignKey(Stop, null=True, on_delete=models.CASCADE)
|
||||||
location_group_id = models.ForeignKey(LocationGroup, on_delete=models.SET_NULL, blank=True, null=True)
|
location_group_id = models.ForeignKey(LocationGroup, on_delete=models.SET_NULL, blank=True, null=True)
|
||||||
location_id = models.ForeignKey(LocationsGeojson, on_delete=models.SET_NULL, blank=True, null=True)
|
location_id = models.ForeignKey(Location, on_delete=models.SET_NULL, blank=True, null=True)
|
||||||
stop_sequence = models.IntegerField()
|
stop_sequence = models.IntegerField()
|
||||||
stop_headsign = models.CharField(max_length=255, blank=True, null=True)
|
stop_headsign = models.CharField(max_length=255, blank=True, null=True)
|
||||||
pickup_type = models.IntegerField(blank=True, null=True)
|
pickup_type = models.IntegerField(blank=True, null=True, choices=[("Regularly scheduled pickup.", 0), ("No pickup available.", 1), ("Must phone agency to arrange pickup.", 2), ("Must coordinate with driver to arrange pickup.", 3)])
|
||||||
drop_off_type = models.IntegerField(blank=True, null=True)
|
drop_off_type = models.IntegerField(blank=True, null=True, choices=[("Regularly scheduled drop off.", 0), ("No drop off available.", 1), ("Must phone agency to arrange drop off.", 2), ("Must coordinate with driver to arrange drop off.", 3)])
|
||||||
shape_dist_traveled = models.FloatField(blank=True, null=True)
|
shape_dist_traveled = models.FloatField(blank=True, null=True)
|
||||||
timepoint = models.IntegerField(blank=True, null=True)
|
timepoint = models.IntegerField(blank=True, null=True, choices=[("Times are considered approximate.", 0), ("Times are considered exact.", 1)])
|
||||||
start_pickup_drop_off_window = models.CharField(max_length=255, blank=True)
|
start_pickup_drop_off_window = models.CharField(max_length=255, blank=True)
|
||||||
end_pickup_drop_off_window = models.CharField(max_length=255, blank=True)
|
end_pickup_drop_off_window = models.CharField(max_length=255, blank=True)
|
||||||
continuous_pickup = models.IntegerField(choices=[("Continous stopping pickup", 0), ("No continuous stopping pickup", 1), ("Must phone agency to arrange continuous stopping pickup off", 2), ("Must coordinate with driver to arrange continuous stopping pickup", 3)], null=True)
|
continuous_pickup = models.IntegerField(choices=[("Continous stopping pickup", 0), ("No continuous stopping pickup", 1), ("Must phone agency to arrange continuous stopping pickup off", 2), ("Must coordinate with driver to arrange continuous stopping pickup", 3)], null=True)
|
||||||
|
|
@ -257,9 +264,9 @@ class FareRule(models.Model):
|
||||||
fare_rule_id = models.BigAutoField(primary_key=True)
|
fare_rule_id = models.BigAutoField(primary_key=True)
|
||||||
fare_id = models.ForeignKey(FareAttribute, on_delete=models.CASCADE)
|
fare_id = models.ForeignKey(FareAttribute, on_delete=models.CASCADE)
|
||||||
route_id = models.ForeignKey(Route, on_delete=models.CASCADE, blank=True, null=True)
|
route_id = models.ForeignKey(Route, on_delete=models.CASCADE, blank=True, null=True)
|
||||||
origin_id = models.IntegerField(blank=True, null=True)
|
origin_id = models.ManyToManyField(Stop, related_name="fare_rules_for_zone_as_origin", blank=True)
|
||||||
destination_id = models.CharField(max_length=255, blank=True, null=True)
|
destination_id = models.ManyToManyField(Stop, related_name="fare_rules_for_zone_as_destination", blank=True)
|
||||||
contains_id = models.CharField(max_length=255, blank=True, null=True)
|
contains_id = models.ManyToManyField(Stop, related_name="fare_rules_for_zone_contains", blank=True)
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class Frequency(models.Model):
|
class Frequency(models.Model):
|
||||||
|
|
@ -351,14 +358,6 @@ class LocationGroupStop(models.Model):
|
||||||
stop_id = models.ForeignKey(Stop, on_delete=models.CASCADE)
|
stop_id = models.ForeignKey(Stop, on_delete=models.CASCADE)
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
||||||
class Network(models.Model):
|
|
||||||
"""
|
|
||||||
Represents network.txt from the GTFS Reference.
|
|
||||||
"""
|
|
||||||
network_id = models.CharField(max_length=255, primary_key=True)
|
|
||||||
network_name = models.CharField(max_length=255)
|
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
class RouteNetwork(models.Model):
|
class RouteNetwork(models.Model):
|
||||||
"""
|
"""
|
||||||
Represents route_network.txt from the GTFS Reference.
|
Represents route_network.txt from the GTFS Reference.
|
||||||
|
|
@ -431,11 +430,11 @@ class FareLegRule(models.Model):
|
||||||
fare_leg_rule_name = models.CharField(max_length=255)
|
fare_leg_rule_name = models.CharField(max_length=255)
|
||||||
fare_leg_rule_description = models.TextField(blank=True, null=True)
|
fare_leg_rule_description = models.TextField(blank=True, null=True)
|
||||||
leg_group_id = models.CharField(max_length=255, blank=True, null=True)
|
leg_group_id = models.CharField(max_length=255, blank=True, null=True)
|
||||||
network_id = models.CharField(max_length=255, blank=True, null=True)
|
network_id = models.ForeignKey(Network, on_delete=models.CASCADE, null=True)
|
||||||
from_area_id = models.ForeignKey(Area, blank=True, null=True, on_delete=models.SET_NULL, related_name='farelegrule_from_area')
|
from_area_id = models.ForeignKey(Area, blank=True, null=True, on_delete=models.SET_NULL, related_name='farelegrule_from_area')
|
||||||
to_area_id = models.ForeignKey(Area, blank=True, null=True, on_delete=models.SET_NULL, related_name='farelegrule_to_area')
|
to_area_id = models.ForeignKey(Area, blank=True, null=True, on_delete=models.SET_NULL, related_name='farelegrule_to_area')
|
||||||
from_timeframe_group_id = models.ForeignKey(Timeframe, blank=True, null=True, on_delete=models.SET_NULL, related_name='farelegrule_from_timeframe')
|
from_timeframe_group_id = models.ManyToManyField(Timeframe, related_name="fare_leg_rules_from", blank=True)
|
||||||
to_timeframe_group_id = models.ForeignKey(Timeframe, blank=True, null=True, on_delete=models.SET_NULL, related_name='farelegrule_to_timeframe')
|
to_timeframe_group_id = models.ManyToManyField(Timeframe, related_name="fare_leg_rules_to", blank=True)
|
||||||
fare_product_id = models.ForeignKey(FareProduct, on_delete=models.CASCADE)
|
fare_product_id = models.ForeignKey(FareProduct, on_delete=models.CASCADE)
|
||||||
rule_priority = models.IntegerField(blank=True, null=True)
|
rule_priority = models.IntegerField(blank=True, null=True)
|
||||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||||
|
|
|
||||||
52
transport_accessibility/pt_map/templates/base.html
Normal file
52
transport_accessibility/pt_map/templates/base.html
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
{% load static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>OpenStreetMap with GTFS Toolbar</title>
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<!-- Leaflet CSS -->
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw/dist/leaflet.draw.css" />
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body, html {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#map {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 250px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-right: 1px solid #dee2e6;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
margin-left: 250px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.modal-body {
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.route-list {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
<script type="text/javascript" id="cookiebanner" data-zindex="1000" src="https://cdn.jsdelivr.net/gh/dobarkod/cookie-banner@1.2.2/dist/cookiebanner.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,53 +1,6 @@
|
||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
{% load static %}
|
||||||
<head>
|
{% block content %}
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>OpenStreetMap with GTFS Toolbar</title>
|
|
||||||
<!-- Bootstrap CSS -->
|
|
||||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<!-- Leaflet CSS -->
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet-draw/dist/leaflet.draw.css" />
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.css" />
|
|
||||||
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body, html {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#map {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.sidebar {
|
|
||||||
height: 100%;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 250px;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-right: 1px solid #dee2e6;
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
margin-left: 250px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.modal-body {
|
|
||||||
max-height: 60vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
.route-list {
|
|
||||||
max-height: 400px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h5 class="mt-4">Options</h5>
|
<h5 class="mt-4">Options</h5>
|
||||||
|
|
@ -56,22 +9,22 @@
|
||||||
<button class="list-group-item list-group-item-action" onclick="document.getElementById('fileInput').click();">Load GTFS from computer</button>
|
<button class="list-group-item list-group-item-action" onclick="document.getElementById('fileInput').click();">Load GTFS from computer</button>
|
||||||
<button class="list-group-item list-group-item-action" onclick="importGTFS()">Import existing GTFS</button>
|
<button class="list-group-item list-group-item-action" onclick="importGTFS()">Import existing GTFS</button>
|
||||||
</div>
|
</div>
|
||||||
<h5 id="currentGTFS">
|
<div class="currentGTFS">
|
||||||
Current GTFS
|
<h5 id="currentGTFS">Current GTFS</h5>
|
||||||
<h6 id="newShape">
|
<h6 id="newShape">
|
||||||
<button class="list-group-item list-group-item-action" onclick="drawNewShape()">Draw New Shape</button>
|
<button class="list-group-item list-group-item-action" onclick="drawNewShape()">Draw New Shape</button>
|
||||||
<button class="list-group-item list-group-item-action" onclick="addNewShape()">Add New Shape</button>
|
<button class="list-group-item list-group-item-action" onclick="addNewShape()">Add New Shape</button>
|
||||||
<button class="list-group-item list-group-item-action" onclick="addNewStop()">Add New Stop</button>
|
<button class="list-group-item list-group-item-action" onclick="addNewStop()">Add New Stop</button>
|
||||||
</h6>
|
</h6>
|
||||||
<h6 id="chosenShape">
|
<h6 id="chosenShape">
|
||||||
Chosen Shape
|
Chosen Shape
|
||||||
<!-- Shape options will be inserted here -->
|
<!-- Shape options will be inserted here -->
|
||||||
</h6>
|
</h6>
|
||||||
<h6 id="currentRoutes">
|
<h6 id="currentRoutes">
|
||||||
Current GTFS
|
Current GTFS
|
||||||
<!-- Route IDs will be inserted here -->
|
<!-- Route IDs will be inserted here -->
|
||||||
</h6>
|
</h6>
|
||||||
</h5>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|
@ -205,5 +158,4 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
{% endblock %}
|
||||||
</html>
|
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
from django.test import TestCase
|
|
||||||
from pt_map.test_data import *
|
|
||||||
from pt_map.models import *
|
|
||||||
import unittest
|
|
||||||
from django.db import models
|
|
||||||
import random
|
|
||||||
define(`models', `Agency, Area, Attribution, BookingRule, Calendar, CalendarDate, FareAttribute, FareLegRule, FareMedium, FareProduct, FareRule, FareTransferRule, FeedInfo, Frequency, Level, LocationGroup, LocationGroupStop, LocationsGeojson, Network, Pathway, Route, RouteNetwork, Shape, Stop, StopArea, StopTime, Timeframe, Transfer, Translation, Trip')
|
|
||||||
define(`foreach', `ifelse(`$#', `1',``, `$1' `$2' `foreach(shift($@)', `$2'')')')
|
|
||||||
foreach(models, `echo(`class $1TestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.model_fields = [f.name for f in $1._meta.fields]
|
|
||||||
self.gtfs_fields = get_all_fields("$1")
|
|
||||||
|
|
||||||
def test_all_fields_present(self):
|
|
||||||
"""Make sure the model has properties for all fields - regardless if required - provided by the GTFS standard."""
|
|
||||||
for f in self.gtfs_fields:
|
|
||||||
with self.subTest(f=f):
|
|
||||||
self.assertIn(f["name"], self.model_fields)
|
|
||||||
|
|
||||||
def test_constructor_all_fields(self):
|
|
||||||
"""Make sure all of the models fields of the model are initializable"""
|
|
||||||
with self.subTest(name="fixed"):
|
|
||||||
"""Fixed subTest"""
|
|
||||||
d = data[0]
|
|
||||||
values = {f["name"]: d[f["type"]] for f in self.gtfs_fields}
|
|
||||||
obj = $1(**values)
|
|
||||||
self.assertIsNotNone(obj)
|
|
||||||
self.assertIsInstance(obj, models.Model)
|
|
||||||
|
|
||||||
with self.subTest(name="other"):
|
|
||||||
d = data[random.randint(0,len(data))]
|
|
||||||
values = {f["name"]: d[f["type"]] for f in self.gtfs_fields}
|
|
||||||
obj = $1(**values)
|
|
||||||
self.assertIsNotNone(obj)
|
|
||||||
self.assertIsInstance(obj, models.Model)')')
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,38 @@
|
||||||
#TODO: Test LocationsGeojson
|
"""
|
||||||
#TODO: Test MTM
|
Test GTFS Compliance
|
||||||
|
====================
|
||||||
|
|
||||||
|
Test suite meant to make sure the models do their best to enforce compliance of the database with the gtfs standard.
|
||||||
|
In particular we are testing:
|
||||||
|
1. All of the txt files the reference suggests have a model representation.
|
||||||
|
2. All of the fields described in each of the files is representable inside the corresponding model.
|
||||||
|
3. The fields can be set with standard data for the correct data type.
|
||||||
|
4. None of the optional fields are enforced to be set. (TODO)
|
||||||
|
5. All of the required fields are enforced to be set with a legal value. (TODO)
|
||||||
|
6. If set, the optional fields hold only legal values (TODO)
|
||||||
|
7. All conditional requirements and restrictions are enforced. (TODO)
|
||||||
|
8. Foreign keys and many to many sets are actually set within the database and are validated. (TODO)
|
||||||
|
|
||||||
|
Functions
|
||||||
|
---------
|
||||||
|
|
||||||
|
_get_test_data(f: function):
|
||||||
|
Decorator, wrapping instance methods to provide an extendable method to get data from the test data set based on the TestCase's requirements.
|
||||||
|
_test_constructor(f: function):
|
||||||
|
Decorator. Basic test to validate if the models are instantiable with the given set of fields.
|
||||||
|
|
||||||
|
Classes
|
||||||
|
-------
|
||||||
|
|
||||||
|
AllFieldsPresentTestCase(TestCase):
|
||||||
|
Test case making sure all files are represented with a complete set of fields. (Conditions 1+2 from the above list)
|
||||||
|
|
||||||
|
ConstructorAllFieldsTestCase(TestCase):
|
||||||
|
Test case making sure the models can be instantiated given valid values for all their fields. (3)
|
||||||
|
|
||||||
|
ConstructorRequiredFieldsOnlyTestCase(TestCase):
|
||||||
|
Test case making sure the model creation is fine with just the required fields. (4)
|
||||||
|
"""
|
||||||
|
|
||||||
from django.test import TestCase, TransactionTestCase
|
from django.test import TestCase, TransactionTestCase
|
||||||
from pt_map.test_data import *
|
from pt_map.test_data import *
|
||||||
|
|
@ -14,7 +47,8 @@ import datetime
|
||||||
|
|
||||||
def _get_test_data(f):
|
def _get_test_data(f):
|
||||||
"""Get test data for a field type."""
|
"""Get test data for a field type."""
|
||||||
def wrapper(self, field, model, d, *args, **kwargs):
|
def wrapper(self, field, model, d, i):
|
||||||
|
f(self, field, model, d, i)
|
||||||
if field["name"] == "service_id":
|
if field["name"] == "service_id":
|
||||||
self.add += 1
|
self.add += 1
|
||||||
return f"{d['pk']}{self.add}"
|
return f"{d['pk']}{self.add}"
|
||||||
|
|
@ -22,19 +56,38 @@ def _get_test_data(f):
|
||||||
case "fk":
|
case "fk":
|
||||||
if isinstance(field["references"], list):
|
if isinstance(field["references"], list):
|
||||||
field["references"] = random.choice(field["references"])
|
field["references"] = random.choice(field["references"])
|
||||||
if not field["references"] == model and field["references"] not in [LocationsGeojson]:
|
if field["references"].objects.all():
|
||||||
fk = field["references"].objects.create(**{**{f["name"]: self.get_test_data(f, field["references"], d) for f in self.gtfs_fields[field["references"]._meta.object_name] if not f["type"] == "mtm"}, "feed_info_id": self.feed_info})
|
return field["references"].objects.all()[0]
|
||||||
|
if not field["references"] == model and field["references"]:
|
||||||
|
fk = field["references"].objects.create(**{**{f["name"]: self.get_test_data(f, field["references"], d, i) for f in self.gtfs_fields[field["references"]._meta.object_name] if not f["type"] == "mtm"}, "feed_info_id": self.feed_info})
|
||||||
|
for n, v in {f["name"]: self.get_test_data(f, model, d, i) for f in self.gtfs_fields[field["references"]._meta.object_name] if f["type"] == "mtm"}.items():
|
||||||
|
getattr(fk, n).set(v)
|
||||||
return fk
|
return fk
|
||||||
return None
|
return None
|
||||||
case "unique":
|
case "unique":
|
||||||
return (d[field["pk"]], "unique")
|
return (d['pk'], "unique") #TODO
|
||||||
case "enum":
|
case "enum":
|
||||||
return random.choice(field["allowed_values"])
|
return random.choice(field["allowed_values"])
|
||||||
case "date":
|
case "date":
|
||||||
return datetime.datetime.fromisoformat(d["date"])
|
return datetime.datetime.fromisoformat(d["date"])
|
||||||
case "pk":
|
case "pk":
|
||||||
self.add += 1
|
return f"{d['pk']}{datetime.datetime.now().timestamp()}"
|
||||||
return f"{d['pk']}{self.add}"
|
case "lat":
|
||||||
|
return d["float"] #TODO
|
||||||
|
case "lon":
|
||||||
|
return d["float"] #TODO
|
||||||
|
case "mtm":
|
||||||
|
choices = [j for j in range(len(data)-1) if not j == i]
|
||||||
|
indexes = set([])
|
||||||
|
while len(indexes) < 3:
|
||||||
|
indexes.add(random.choice(choices))
|
||||||
|
indexes = list(indexes)
|
||||||
|
mtm_test_data = [data[j] for j in indexes if field["references"]._meta.pk.name in data[j].keys() and not field["references"].objects.filter(pk=data[j]['pk'])]
|
||||||
|
qs = [field["references"].objects.create(**{**{f["name"]: self.get_test_data(f, field["references"], mtm_test_data[j], i) for f in self.gtfs_fields[field["references"]._meta.object_name] if not f["type"] == "mtm"}, "feed_info_id": self.feed_info}) for j in range(len(mtm_test_data))]
|
||||||
|
for m in qs:
|
||||||
|
for n, v in {f["name"]: self.get_test_data(f, model, d, i) for f in self.gtfs_fields[field["references"]._meta.object_name] if f["type"] == "mtm"}.items():
|
||||||
|
getattr(m, n).set(v)
|
||||||
|
return field["references"].objects.all()
|
||||||
case _:
|
case _:
|
||||||
return d[field["type"]]
|
return d[field["type"]]
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
@ -42,11 +95,14 @@ def _get_test_data(f):
|
||||||
def _test_constructor(index):
|
def _test_constructor(index):
|
||||||
def decorate(f):
|
def decorate(f):
|
||||||
def wrapper(self, *args, **kwargs):
|
def wrapper(self, *args, **kwargs):
|
||||||
for name, model in [tpl for tpl in inspect.getmembers(pt_map.models, inspect.isclass) if tpl[1] not in [FeedInfo, LocationsGeojson]]:
|
f(self, *args, **kwargs)
|
||||||
|
for name, model in [tpl for tpl in inspect.getmembers(pt_map.models, inspect.isclass) if tpl[1] not in [FeedInfo,]]:
|
||||||
with self.subTest(name=name):
|
with self.subTest(name=name):
|
||||||
d = data[index]
|
d = data[index]
|
||||||
values = {**{f["name"]: self.get_test_data(f, model, d) for f in self.gtfs_fields[name] if not f["type"] == "mtm"}, "feed_info_id": self.feed_info}
|
values = {**{field["name"]: self.get_test_data(field, model, d, index) for field in self.gtfs_fields[name] if not field["type"] == "mtm"}, "feed_info_id": self.feed_info}
|
||||||
obj = model.objects.create(**values)
|
obj = model.objects.create(**values)
|
||||||
|
for n, v in {field["name"]: self.get_test_data(field, model, d, index) for field in self.gtfs_fields[name] if field["type"] == "mtm"}.items():
|
||||||
|
getattr(obj, n).set(v)
|
||||||
self.assertIsNotNone(obj)
|
self.assertIsNotNone(obj)
|
||||||
self.assertIsInstance(obj, models.Model)
|
self.assertIsInstance(obj, models.Model)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
@ -55,8 +111,8 @@ def _test_constructor(index):
|
||||||
class AllFieldsPresentTestCase(TestCase):
|
class AllFieldsPresentTestCase(TestCase):
|
||||||
"""Test for the presence of all the fields of all the models, the GTFS reference describes."""
|
"""Test for the presence of all the fields of all the models, the GTFS reference describes."""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.model_fields = {name: [*[f.name for f in model._meta.fields], *[f.name for f in model._meta.many_to_many]] for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if not model == LocationsGeojson}
|
self.model_fields = {name: [*[f.name for f in model._meta.fields], *[f.name for f in model._meta.many_to_many]] for name, model in inspect.getmembers(pt_map.models, inspect.isclass)}
|
||||||
self.gtfs_fields = {name: get_all_fields(name) for name,model in inspect.getmembers(pt_map.models, inspect.isclass) if not model == LocationsGeojson}
|
self.gtfs_fields = {name: get_all_fields(name) for name,model in inspect.getmembers(pt_map.models, inspect.isclass)}
|
||||||
|
|
||||||
def test_all_fields_present(self):
|
def test_all_fields_present(self):
|
||||||
"""Make sure the model has properties for all fields - regardless if required - provided by the GTFS standard."""
|
"""Make sure the model has properties for all fields - regardless if required - provided by the GTFS standard."""
|
||||||
|
|
@ -76,7 +132,7 @@ class ConstructorAllFieldsTestCase(TransactionTestCase):
|
||||||
self.add = 0
|
self.add = 0
|
||||||
|
|
||||||
@_get_test_data
|
@_get_test_data
|
||||||
def get_test_data(self, field, model, d):
|
def get_test_data(self, field, model, d, i):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@_test_constructor(0)
|
@_test_constructor(0)
|
||||||
|
|
@ -91,12 +147,12 @@ class ConstructorAllFieldsTestCase(TransactionTestCase):
|
||||||
|
|
||||||
class ConstructorRequiredFieldsOnlyTestCase(TransactionTestCase):
|
class ConstructorRequiredFieldsOnlyTestCase(TransactionTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.gtfs_fields = {name: get_required_fields(name) for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if model not in [FeedInfo, LocationsGeojson]}
|
self.gtfs_fields = {name: get_required_fields(name) for name, model in inspect.getmembers(pt_map.models, inspect.isclass) if model not in [FeedInfo]}
|
||||||
self.feed_info = FeedInfo.objects.create(**{f["name"]: data[0][f["type"]] for f in get_required_fields("FeedInfo")})
|
self.feed_info = FeedInfo.objects.create(**{f["name"]: data[0][f["type"]] for f in get_required_fields("FeedInfo")})
|
||||||
self.add = 0
|
self.add = 0
|
||||||
|
|
||||||
@_get_test_data
|
@_get_test_data
|
||||||
def get_test_data(self):
|
def get_test_data(self, field, model, d, i):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@_test_constructor(0)
|
@_test_constructor(0)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ index
|
||||||
"""
|
"""
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from . import query
|
from . import query
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
def setUp(self): self.model_fields = [f.name for f in Agency._meta.fields] self.gtfs_fields = get_all_fields("Agency") def test_all_fields_present(self): """Make sure the model has properties for all fields - regardless if required - provided by the GTFS standard.""" for f in self.gtfs_fields: with self.subTest(f=f): self.assertIn(f["name"], self.model_fields) def test_constructor_all_fields(self): """Make sure all of the models fields of the model are initializable""" with self.subTest(name="fixed"): """Fixed subTest""" d = data[0] values = {f["name"]: d[f["type"]] for f in self.gtfs_fields} obj = Agency(**values) self.assertIsNotNone(obj) self.assertIsInstance(obj, models.Model) with self.subTest(name="other"): d = data[random.randint(0,len(data))] values = {f["name"]: d[f["type"]] for f in self.gtfs_fields} obj = Agency(**values) self.assertIsNotNone(obj) self.assertIsInstance(obj, models.Model)
|
|
||||||
Loading…
Reference in New Issue
Block a user