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,
|
||||
"LocationGroup": pt_map.models.LocationGroup,
|
||||
"LocationGroupStop": pt_map.models.LocationGroupStop,
|
||||
"LocationsGeojson": pt_map.models.LocationsGeojson,
|
||||
"Location": pt_map.models.Location,
|
||||
"BookingRule": pt_map.models.BookingRule,
|
||||
"Translation": pt_map.models.Translation,
|
||||
"FeedInfo": pt_map.models.FeedInfo,
|
||||
|
|
@ -66,7 +66,7 @@ class_names = [
|
|||
"levels": pt_map.models.Level,
|
||||
"location_groups": pt_map.models.LocationGroup,
|
||||
"location_group_stops": pt_map.models.LocationGroupStop,
|
||||
"locations": pt_map.models.LocationsGeojson,
|
||||
"locations": pt_map.models.Location,
|
||||
"booking_rules": pt_map.models.BookingRule,
|
||||
"translations": pt_map.models.Translation,
|
||||
"feed_info": pt_map.models.FeedInfo,
|
||||
|
|
@ -98,7 +98,7 @@ class_names = [
|
|||
pt_map.models.Level: "Level",
|
||||
pt_map.models.LocationGroup: "LocationGroup",
|
||||
pt_map.models.LocationGroupStop: "LocationGroupStop",
|
||||
pt_map.models.LocationsGeojson: "LocationsGeojson",
|
||||
pt_map.models.Location: "Location",
|
||||
pt_map.models.BookingRule: "BookingRule",
|
||||
pt_map.models.Translation: "Translation",
|
||||
pt_map.models.FeedInfo: "FeedInfo",
|
||||
|
|
@ -130,7 +130,7 @@ pt_map.models.Shape: "shapes",
|
|||
pt_map.models.Level: "levels",
|
||||
pt_map.models.LocationGroup: "location_groups",
|
||||
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.Translation: "translations",
|
||||
pt_map.models.FeedInfo: "feed_info",
|
||||
|
|
@ -166,7 +166,7 @@ file_names = {
|
|||
pt_map.models.Level: "levels.txt",
|
||||
pt_map.models.LocationGroup: "location_groups.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.Translation: "translations.txt",
|
||||
pt_map.models.FeedInfo: "feed_info.txt",
|
||||
|
|
@ -199,7 +199,7 @@ reversed_file_mapping = {
|
|||
"Level": "levels",
|
||||
"LocationGroup": "location_groups",
|
||||
"LocationGroupStop": "location_group_stops",
|
||||
"LocationsGeojson": "locations_geojson",
|
||||
"Location": "locations_geojson",
|
||||
"BookingRule": "booking_rules",
|
||||
"Translation": "translations",
|
||||
"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 = {
|
||||
|
|
@ -221,7 +221,7 @@ primary_keys = {
|
|||
pt_map.models.CalendarDate: "calendar_date_id",
|
||||
pt_map.models.Trip: "trip_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.FareAttribute: "fare_id",
|
||||
pt_map.models.FareRule: "fare_rule_id",
|
||||
|
|
@ -255,7 +255,7 @@ classes_by_primary_keys = {
|
|||
'calendar_date_id': pt_map.models.CalendarDate,
|
||||
'trip_id': pt_map.models.Trip,
|
||||
'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,
|
||||
'fare_id': pt_map.models.FareAttribute,
|
||||
'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.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.LocationsGeojson, [(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.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.Location, 'location_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.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,
|
||||
'stop_id': pt_map.models.Stop,
|
||||
'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,
|
||||
'from_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",
|
||||
"type": "mtm",
|
||||
"references": Route,
|
||||
"type": "fk",
|
||||
"references": Network,
|
||||
"required": "false",
|
||||
"forbidden_if": ["RouteNetwork", True]
|
||||
},
|
||||
|
|
@ -252,8 +252,7 @@ field_requirements = \
|
|||
},
|
||||
{
|
||||
"name": "block_id",
|
||||
"type": "mtm",
|
||||
"references": Trip,
|
||||
"type": "unique",
|
||||
"required": "false",
|
||||
},
|
||||
{
|
||||
|
|
@ -277,6 +276,42 @@ field_requirements = \
|
|||
],
|
||||
"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",
|
||||
"fields": [
|
||||
|
|
@ -308,7 +343,7 @@ field_requirements = \
|
|||
},
|
||||
{
|
||||
"name": "location_group_id",
|
||||
"type": "mtm",
|
||||
"type": "fk",
|
||||
"references": LocationGroup,
|
||||
"required": "false",
|
||||
"forbidden_if_not": [(["stop_id", None], ["location_id", None])],
|
||||
|
|
@ -317,7 +352,7 @@ field_requirements = \
|
|||
"name": "location_id",
|
||||
"type": "fk",
|
||||
"required": "false",
|
||||
"references": LocationsGeojson,
|
||||
"references": Location,
|
||||
"forbidden_if_not": [(["stop_id", None], ["location_group_id", None])],
|
||||
},
|
||||
{
|
||||
|
|
@ -658,7 +693,8 @@ field_requirements = \
|
|||
},
|
||||
{
|
||||
"name": "network_id",
|
||||
"type": "str",
|
||||
"type": "fk",
|
||||
"references": Network,
|
||||
"required": "false",
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Attributes
|
|||
----------
|
||||
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
|
||||
"""
|
||||
from django.db import models
|
||||
|
|
@ -72,6 +72,14 @@ class Stop(models.Model):
|
|||
platform_code = models.CharField(max_length=50, blank=True, null=True)
|
||||
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):
|
||||
"""
|
||||
Represents route.txt from the GTFS Reference.
|
||||
|
|
@ -88,7 +96,7 @@ class Route(models.Model):
|
|||
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_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)
|
||||
|
||||
class Shape(models.Model):
|
||||
|
|
@ -175,17 +183,16 @@ class LocationGroup(models.Model):
|
|||
location_group_type = models.CharField(max_length=255)
|
||||
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.
|
||||
"""
|
||||
location_id = models.CharField(max_length=255, primary_key=True)
|
||||
location_name = models.CharField(max_length=255)
|
||||
location_lat = models.FloatField()
|
||||
location_lon = models.FloatField()
|
||||
location_type = models.CharField(max_length=255)
|
||||
parent_location_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
wheelchair_boarding = models.BooleanField(blank=True, null=True)
|
||||
stop_name = models.CharField(max_length=255, blank=True, null=True)
|
||||
stop_desc = models.CharField(max_length=255, blank=True, null=True)
|
||||
latitude = models.FloatField()
|
||||
longitude = models.FloatField()
|
||||
geometry_type = models.CharField(max_length=255, choices=[("Polygon", "Polygon"), ("MultiPolygon", "MultiPolygon")])
|
||||
feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE)
|
||||
|
||||
class BookingRule(models.Model):
|
||||
|
|
@ -219,13 +226,13 @@ class StopTime(models.Model):
|
|||
departure_time = models.CharField(max_length=255, blank=True, null=True)
|
||||
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_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_headsign = models.CharField(max_length=255, blank=True, null=True)
|
||||
pickup_type = models.IntegerField(blank=True, null=True)
|
||||
drop_off_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, 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)
|
||||
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)
|
||||
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)
|
||||
|
|
@ -257,9 +264,9 @@ class FareRule(models.Model):
|
|||
fare_rule_id = models.BigAutoField(primary_key=True)
|
||||
fare_id = models.ForeignKey(FareAttribute, on_delete=models.CASCADE)
|
||||
route_id = models.ForeignKey(Route, on_delete=models.CASCADE, blank=True, null=True)
|
||||
origin_id = models.IntegerField(blank=True, null=True)
|
||||
destination_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
contains_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
origin_id = models.ManyToManyField(Stop, related_name="fare_rules_for_zone_as_origin", blank=True)
|
||||
destination_id = models.ManyToManyField(Stop, related_name="fare_rules_for_zone_as_destination", blank=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)
|
||||
|
||||
class Frequency(models.Model):
|
||||
|
|
@ -351,14 +358,6 @@ class LocationGroupStop(models.Model):
|
|||
stop_id = models.ForeignKey(Stop, 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):
|
||||
"""
|
||||
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_description = models.TextField(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')
|
||||
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')
|
||||
to_timeframe_group_id = models.ForeignKey(Timeframe, blank=True, null=True, on_delete=models.SET_NULL, related_name='farelegrule_to_timeframe')
|
||||
from_timeframe_group_id = models.ManyToManyField(Timeframe, related_name="fare_leg_rules_from", blank=True)
|
||||
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)
|
||||
rule_priority = models.IntegerField(blank=True, null=True)
|
||||
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>
|
||||
<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" />
|
||||
|
||||
{% 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>
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="sidebar">
|
||||
<div class="container">
|
||||
<h5 class="mt-4">Options</h5>
|
||||
|
|
@ -56,8 +9,8 @@
|
|||
<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>
|
||||
</div>
|
||||
<h5 id="currentGTFS">
|
||||
Current GTFS
|
||||
<div class="currentGTFS">
|
||||
<h5 id="currentGTFS">Current GTFS</h5>
|
||||
<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="addNewShape()">Add New Shape</button>
|
||||
|
|
@ -71,7 +24,7 @@
|
|||
Current GTFS
|
||||
<!-- Route IDs will be inserted here -->
|
||||
</h6>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
|
|
@ -205,5 +158,4 @@
|
|||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -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 pt_map.test_data import *
|
||||
|
|
@ -14,7 +47,8 @@ import datetime
|
|||
|
||||
def _get_test_data(f):
|
||||
"""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":
|
||||
self.add += 1
|
||||
return f"{d['pk']}{self.add}"
|
||||
|
|
@ -22,19 +56,38 @@ def _get_test_data(f):
|
|||
case "fk":
|
||||
if isinstance(field["references"], list):
|
||||
field["references"] = random.choice(field["references"])
|
||||
if not field["references"] == model and field["references"] not in [LocationsGeojson]:
|
||||
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})
|
||||
if field["references"].objects.all():
|
||||
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 None
|
||||
case "unique":
|
||||
return (d[field["pk"]], "unique")
|
||||
return (d['pk'], "unique") #TODO
|
||||
case "enum":
|
||||
return random.choice(field["allowed_values"])
|
||||
case "date":
|
||||
return datetime.datetime.fromisoformat(d["date"])
|
||||
case "pk":
|
||||
self.add += 1
|
||||
return f"{d['pk']}{self.add}"
|
||||
return f"{d['pk']}{datetime.datetime.now().timestamp()}"
|
||||
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 _:
|
||||
return d[field["type"]]
|
||||
return wrapper
|
||||
|
|
@ -42,11 +95,14 @@ def _get_test_data(f):
|
|||
def _test_constructor(index):
|
||||
def decorate(f):
|
||||
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):
|
||||
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)
|
||||
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.assertIsInstance(obj, models.Model)
|
||||
return wrapper
|
||||
|
|
@ -55,8 +111,8 @@ def _test_constructor(index):
|
|||
class AllFieldsPresentTestCase(TestCase):
|
||||
"""Test for the presence of all the fields of all the models, the GTFS reference describes."""
|
||||
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.gtfs_fields = {name: get_all_fields(name) 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)}
|
||||
|
||||
def test_all_fields_present(self):
|
||||
"""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
|
||||
|
||||
@_get_test_data
|
||||
def get_test_data(self, field, model, d):
|
||||
def get_test_data(self, field, model, d, i):
|
||||
pass
|
||||
|
||||
@_test_constructor(0)
|
||||
|
|
@ -91,12 +147,12 @@ class ConstructorAllFieldsTestCase(TransactionTestCase):
|
|||
|
||||
class ConstructorRequiredFieldsOnlyTestCase(TransactionTestCase):
|
||||
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.add = 0
|
||||
|
||||
@_get_test_data
|
||||
def get_test_data(self):
|
||||
def get_test_data(self, field, model, d, i):
|
||||
pass
|
||||
|
||||
@_test_constructor(0)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ index
|
|||
"""
|
||||
from django.shortcuts import render
|
||||
from . import query
|
||||
import json
|
||||
|
||||
|
||||
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