ebird-api-data 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,927 @@
1
+ # Generated by Django 5.1.6 on 2025-07-10 08:50
2
+
3
+ import django.core.validators
4
+ import django.db.models.deletion
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+ initial = True
10
+
11
+ dependencies = []
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name="Country",
16
+ fields=[
17
+ (
18
+ "id",
19
+ models.AutoField(
20
+ auto_created=True,
21
+ primary_key=True,
22
+ serialize=False,
23
+ verbose_name="ID",
24
+ ),
25
+ ),
26
+ (
27
+ "code",
28
+ models.CharField(
29
+ db_index=True,
30
+ help_text="The code used to identify the country.",
31
+ max_length=2,
32
+ verbose_name="code",
33
+ ),
34
+ ),
35
+ (
36
+ "name",
37
+ models.TextField(
38
+ help_text="The name of the country.", verbose_name="name"
39
+ ),
40
+ ),
41
+ (
42
+ "place",
43
+ models.TextField(
44
+ help_text="The hierarchical name of the country.",
45
+ verbose_name="place",
46
+ ),
47
+ ),
48
+ ],
49
+ options={
50
+ "verbose_name": "country",
51
+ "verbose_name_plural": "countries",
52
+ },
53
+ ),
54
+ migrations.CreateModel(
55
+ name="County",
56
+ fields=[
57
+ (
58
+ "id",
59
+ models.AutoField(
60
+ auto_created=True,
61
+ primary_key=True,
62
+ serialize=False,
63
+ verbose_name="ID",
64
+ ),
65
+ ),
66
+ (
67
+ "code",
68
+ models.CharField(
69
+ db_index=True,
70
+ help_text="The code used to identify the county.",
71
+ max_length=10,
72
+ verbose_name="code",
73
+ ),
74
+ ),
75
+ (
76
+ "name",
77
+ models.TextField(
78
+ help_text="The name of the county.", verbose_name="name"
79
+ ),
80
+ ),
81
+ (
82
+ "place",
83
+ models.TextField(
84
+ help_text="The hierarchical name of the county.",
85
+ verbose_name="place",
86
+ ),
87
+ ),
88
+ ],
89
+ options={
90
+ "verbose_name": "county",
91
+ "verbose_name_plural": "counties",
92
+ },
93
+ ),
94
+ migrations.CreateModel(
95
+ name="Observer",
96
+ fields=[
97
+ (
98
+ "id",
99
+ models.AutoField(
100
+ auto_created=True,
101
+ primary_key=True,
102
+ serialize=False,
103
+ verbose_name="ID",
104
+ ),
105
+ ),
106
+ (
107
+ "identifier",
108
+ models.TextField(
109
+ help_text="The code for the person submitted the checklist.",
110
+ verbose_name="identifier",
111
+ ),
112
+ ),
113
+ (
114
+ "original",
115
+ models.TextField(
116
+ help_text="The original name of the observer from eBird.",
117
+ verbose_name="original name",
118
+ ),
119
+ ),
120
+ (
121
+ "name",
122
+ models.TextField(
123
+ help_text="The display name of the observer.",
124
+ verbose_name="name",
125
+ ),
126
+ ),
127
+ (
128
+ "multiple",
129
+ models.BooleanField(
130
+ default=False,
131
+ help_text="Is the name used by more than one eBird account.",
132
+ verbose_name="Multiple accounts",
133
+ ),
134
+ ),
135
+ (
136
+ "enabled",
137
+ models.BooleanField(
138
+ default=True,
139
+ help_text="Load checklists from the eBird observer.",
140
+ verbose_name="Enabled",
141
+ ),
142
+ ),
143
+ (
144
+ "data",
145
+ models.JSONField(
146
+ blank=True,
147
+ default=dict,
148
+ help_text="Data describing an Observer.",
149
+ verbose_name="Data",
150
+ ),
151
+ ),
152
+ ],
153
+ options={
154
+ "verbose_name": "observer",
155
+ "verbose_name_plural": "observers",
156
+ },
157
+ ),
158
+ migrations.CreateModel(
159
+ name="Species",
160
+ fields=[
161
+ (
162
+ "id",
163
+ models.AutoField(
164
+ auto_created=True,
165
+ primary_key=True,
166
+ serialize=False,
167
+ verbose_name="ID",
168
+ ),
169
+ ),
170
+ (
171
+ "taxon_order",
172
+ models.IntegerField(
173
+ blank=True,
174
+ help_text="The position in the eBird/Clements taxonomic order.",
175
+ null=True,
176
+ verbose_name="taxonomy order",
177
+ ),
178
+ ),
179
+ (
180
+ "order",
181
+ models.TextField(
182
+ blank=True,
183
+ help_text="The order, e.g. Struthioniformes, from the eBird/Clements taxonomy.",
184
+ verbose_name="order",
185
+ ),
186
+ ),
187
+ (
188
+ "category",
189
+ models.TextField(
190
+ blank=True,
191
+ choices=[
192
+ ("", "All categories"),
193
+ ("species", "Species"),
194
+ ("issf", "Subspecies"),
195
+ ("domestic", "Domestic"),
196
+ ("hybrid", "Hybrid"),
197
+ ],
198
+ help_text="The category from the eBird/Clements taxonomy.",
199
+ verbose_name="category",
200
+ ),
201
+ ),
202
+ (
203
+ "species_code",
204
+ models.TextField(
205
+ blank=True,
206
+ help_text="The species code, e.g. ostric2, used in the eBird API.",
207
+ verbose_name="species code",
208
+ ),
209
+ ),
210
+ (
211
+ "family_code",
212
+ models.TextField(
213
+ blank=True,
214
+ help_text="The family code, e.g. struth1, used in the eBird API.",
215
+ verbose_name="family code",
216
+ ),
217
+ ),
218
+ (
219
+ "common_name",
220
+ models.TextField(
221
+ help_text="The species common name in the eBird/Clements taxonomy.",
222
+ verbose_name="common name",
223
+ ),
224
+ ),
225
+ (
226
+ "scientific_name",
227
+ models.TextField(
228
+ help_text="The species scientific name in the eBird/Clements taxonomy.",
229
+ verbose_name="scientific name",
230
+ ),
231
+ ),
232
+ (
233
+ "family_common_name",
234
+ models.TextField(
235
+ blank=True,
236
+ help_text="The common name for the species family in the eBird/Clements taxonomy.",
237
+ verbose_name="family common name",
238
+ ),
239
+ ),
240
+ (
241
+ "family_scientific_name",
242
+ models.TextField(
243
+ blank=True,
244
+ help_text="The scientific name for the species family in the eBird/Clements taxonomy.",
245
+ verbose_name="family scientific name",
246
+ ),
247
+ ),
248
+ (
249
+ "data",
250
+ models.JSONField(
251
+ blank=True,
252
+ default=dict,
253
+ help_text="Data describing a Species.",
254
+ verbose_name="Data",
255
+ ),
256
+ ),
257
+ ],
258
+ options={
259
+ "verbose_name": "species",
260
+ "verbose_name_plural": "species",
261
+ },
262
+ ),
263
+ migrations.CreateModel(
264
+ name="State",
265
+ fields=[
266
+ (
267
+ "id",
268
+ models.AutoField(
269
+ auto_created=True,
270
+ primary_key=True,
271
+ serialize=False,
272
+ verbose_name="ID",
273
+ ),
274
+ ),
275
+ (
276
+ "code",
277
+ models.CharField(
278
+ db_index=True,
279
+ help_text="The code used to identify the state.",
280
+ max_length=10,
281
+ verbose_name="code",
282
+ ),
283
+ ),
284
+ (
285
+ "name",
286
+ models.TextField(
287
+ help_text="The name of the state.", verbose_name="name"
288
+ ),
289
+ ),
290
+ (
291
+ "place",
292
+ models.TextField(
293
+ help_text="The hierarchical name of the state.",
294
+ verbose_name="place",
295
+ ),
296
+ ),
297
+ ],
298
+ options={
299
+ "verbose_name": "state",
300
+ "verbose_name_plural": "states",
301
+ },
302
+ ),
303
+ migrations.CreateModel(
304
+ name="Location",
305
+ fields=[
306
+ (
307
+ "id",
308
+ models.AutoField(
309
+ auto_created=True,
310
+ primary_key=True,
311
+ serialize=False,
312
+ verbose_name="ID",
313
+ ),
314
+ ),
315
+ (
316
+ "identifier",
317
+ models.TextField(
318
+ help_text="The unique identifier for the location.",
319
+ unique=True,
320
+ verbose_name="identifier",
321
+ ),
322
+ ),
323
+ (
324
+ "original",
325
+ models.TextField(
326
+ help_text="The original name of the location from eBird.",
327
+ verbose_name="original name",
328
+ ),
329
+ ),
330
+ (
331
+ "name",
332
+ models.TextField(
333
+ help_text="The display name of the location.",
334
+ verbose_name="name",
335
+ ),
336
+ ),
337
+ (
338
+ "latitude",
339
+ models.DecimalField(
340
+ blank=True,
341
+ decimal_places=7,
342
+ help_text="The decimal latitude of the location, relative to the equator.",
343
+ max_digits=9,
344
+ null=True,
345
+ verbose_name="latitude",
346
+ ),
347
+ ),
348
+ (
349
+ "longitude",
350
+ models.DecimalField(
351
+ blank=True,
352
+ decimal_places=7,
353
+ help_text="The decimal longitude of the location, relative to the prime meridian.",
354
+ max_digits=10,
355
+ null=True,
356
+ verbose_name="longitude",
357
+ ),
358
+ ),
359
+ (
360
+ "url",
361
+ models.URLField(
362
+ blank=True,
363
+ help_text="URL of the location page on eBird.",
364
+ verbose_name="url",
365
+ ),
366
+ ),
367
+ (
368
+ "hotspot",
369
+ models.BooleanField(
370
+ blank=True,
371
+ help_text="Is the location a hotspot.",
372
+ null=True,
373
+ verbose_name="is hotspot",
374
+ ),
375
+ ),
376
+ (
377
+ "data",
378
+ models.JSONField(
379
+ blank=True,
380
+ default=dict,
381
+ help_text="Data describing a Location.",
382
+ verbose_name="Data",
383
+ ),
384
+ ),
385
+ (
386
+ "country",
387
+ models.ForeignKey(
388
+ help_text="The country for the location.",
389
+ on_delete=django.db.models.deletion.PROTECT,
390
+ related_name="locations",
391
+ to="data.country",
392
+ verbose_name="country",
393
+ ),
394
+ ),
395
+ (
396
+ "county",
397
+ models.ForeignKey(
398
+ blank=True,
399
+ help_text="The county for the location.",
400
+ null=True,
401
+ on_delete=django.db.models.deletion.PROTECT,
402
+ related_name="locations",
403
+ to="data.county",
404
+ verbose_name="county",
405
+ ),
406
+ ),
407
+ (
408
+ "state",
409
+ models.ForeignKey(
410
+ help_text="The state for the location.",
411
+ on_delete=django.db.models.deletion.PROTECT,
412
+ related_name="locations",
413
+ to="data.state",
414
+ verbose_name="state",
415
+ ),
416
+ ),
417
+ ],
418
+ options={
419
+ "verbose_name": "location",
420
+ "verbose_name_plural": "locations",
421
+ },
422
+ ),
423
+ migrations.CreateModel(
424
+ name="Checklist",
425
+ fields=[
426
+ (
427
+ "id",
428
+ models.AutoField(
429
+ auto_created=True,
430
+ primary_key=True,
431
+ serialize=False,
432
+ verbose_name="ID",
433
+ ),
434
+ ),
435
+ (
436
+ "created",
437
+ models.DateTimeField(
438
+ blank=True,
439
+ help_text="The date and time the checklist was added to eBird.",
440
+ null=True,
441
+ verbose_name="created",
442
+ ),
443
+ ),
444
+ (
445
+ "edited",
446
+ models.DateTimeField(
447
+ blank=True,
448
+ help_text="The date and time the eBird checklist was last edited.",
449
+ null=True,
450
+ verbose_name="edited",
451
+ ),
452
+ ),
453
+ (
454
+ "published",
455
+ models.BooleanField(
456
+ help_text="Is the checklist published?",
457
+ verbose_name="published",
458
+ ),
459
+ ),
460
+ (
461
+ "identifier",
462
+ models.TextField(
463
+ help_text="The unique identifier for the checklist.",
464
+ unique=True,
465
+ verbose_name="identifier",
466
+ ),
467
+ ),
468
+ (
469
+ "observer_count",
470
+ models.IntegerField(
471
+ blank=True,
472
+ help_text="The total number of observers.",
473
+ null=True,
474
+ verbose_name="observer count",
475
+ ),
476
+ ),
477
+ (
478
+ "species_count",
479
+ models.IntegerField(
480
+ blank=True,
481
+ help_text="The number of species reported.",
482
+ null=True,
483
+ verbose_name="species count",
484
+ ),
485
+ ),
486
+ (
487
+ "date",
488
+ models.DateField(
489
+ db_index=True,
490
+ help_text="The date the checklist was started.",
491
+ verbose_name="date",
492
+ ),
493
+ ),
494
+ (
495
+ "time",
496
+ models.TimeField(
497
+ blank=True,
498
+ help_text="The time the checklist was started.",
499
+ null=True,
500
+ verbose_name="time",
501
+ ),
502
+ ),
503
+ (
504
+ "started",
505
+ models.DateTimeField(
506
+ blank=True,
507
+ db_index=True,
508
+ help_text="The date and time the checklist was started.",
509
+ null=True,
510
+ verbose_name="date & time",
511
+ ),
512
+ ),
513
+ (
514
+ "protocol_code",
515
+ models.TextField(
516
+ blank=True,
517
+ help_text="The code used to identify the protocol.",
518
+ verbose_name="protocol code",
519
+ ),
520
+ ),
521
+ (
522
+ "project_code",
523
+ models.TextField(
524
+ blank=True,
525
+ help_text="The code used to identify the project (portal).",
526
+ verbose_name="project code",
527
+ ),
528
+ ),
529
+ (
530
+ "duration",
531
+ models.IntegerField(
532
+ blank=True,
533
+ help_text="The number of minutes spent counting.",
534
+ null=True,
535
+ verbose_name="duration",
536
+ ),
537
+ ),
538
+ (
539
+ "distance",
540
+ models.DecimalField(
541
+ blank=True,
542
+ decimal_places=3,
543
+ help_text="The distance, in metres, covered while travelling.",
544
+ max_digits=6,
545
+ null=True,
546
+ verbose_name="distance",
547
+ ),
548
+ ),
549
+ (
550
+ "area",
551
+ models.DecimalField(
552
+ blank=True,
553
+ decimal_places=3,
554
+ help_text="The area covered, in hectares.",
555
+ max_digits=6,
556
+ null=True,
557
+ verbose_name="area",
558
+ ),
559
+ ),
560
+ (
561
+ "complete",
562
+ models.BooleanField(
563
+ default=False,
564
+ help_text="All species seen are reported.",
565
+ verbose_name="complete",
566
+ ),
567
+ ),
568
+ (
569
+ "comments",
570
+ models.TextField(
571
+ blank=True,
572
+ help_text="Any comments about the checklist.",
573
+ verbose_name="comments",
574
+ ),
575
+ ),
576
+ (
577
+ "url",
578
+ models.URLField(
579
+ blank=True,
580
+ help_text="URL where the original checklist can be viewed.",
581
+ verbose_name="url",
582
+ ),
583
+ ),
584
+ (
585
+ "data",
586
+ models.JSONField(
587
+ blank=True,
588
+ default=dict,
589
+ help_text="Data describing a Checklist.",
590
+ verbose_name="Data",
591
+ ),
592
+ ),
593
+ (
594
+ "country",
595
+ models.ForeignKey(
596
+ help_text="The country where the checklist was made.",
597
+ on_delete=django.db.models.deletion.PROTECT,
598
+ related_name="checklists",
599
+ to="data.country",
600
+ verbose_name="country",
601
+ ),
602
+ ),
603
+ (
604
+ "county",
605
+ models.ForeignKey(
606
+ blank=True,
607
+ help_text="The county where the checklist was made.",
608
+ null=True,
609
+ on_delete=django.db.models.deletion.PROTECT,
610
+ related_name="checklists",
611
+ to="data.county",
612
+ verbose_name="county",
613
+ ),
614
+ ),
615
+ (
616
+ "location",
617
+ models.ForeignKey(
618
+ help_text="The location where checklist was made.",
619
+ on_delete=django.db.models.deletion.PROTECT,
620
+ related_name="checklists",
621
+ to="data.location",
622
+ verbose_name="location",
623
+ ),
624
+ ),
625
+ (
626
+ "observer",
627
+ models.ForeignKey(
628
+ help_text="The person who submitted the checklist.",
629
+ on_delete=django.db.models.deletion.PROTECT,
630
+ related_name="checklists",
631
+ to="data.observer",
632
+ verbose_name="observer",
633
+ ),
634
+ ),
635
+ (
636
+ "state",
637
+ models.ForeignKey(
638
+ help_text="The state where the checklist was made.",
639
+ on_delete=django.db.models.deletion.PROTECT,
640
+ related_name="checklists",
641
+ to="data.state",
642
+ verbose_name="state",
643
+ ),
644
+ ),
645
+ ],
646
+ options={
647
+ "verbose_name": "checklist",
648
+ "verbose_name_plural": "checklists",
649
+ },
650
+ ),
651
+ migrations.CreateModel(
652
+ name="Filter",
653
+ fields=[
654
+ (
655
+ "id",
656
+ models.AutoField(
657
+ auto_created=True,
658
+ primary_key=True,
659
+ serialize=False,
660
+ verbose_name="ID",
661
+ ),
662
+ ),
663
+ (
664
+ "enabled",
665
+ models.BooleanField(
666
+ help_text="Is the filter active?", verbose_name="enabled"
667
+ ),
668
+ ),
669
+ (
670
+ "name",
671
+ models.TextField(
672
+ help_text="The name of the filter.", verbose_name="name"
673
+ ),
674
+ ),
675
+ (
676
+ "location",
677
+ models.ForeignKey(
678
+ blank=True,
679
+ help_text="The location used to find matching Observations.",
680
+ null=True,
681
+ on_delete=django.db.models.deletion.CASCADE,
682
+ related_name="filtered_on",
683
+ to="data.location",
684
+ verbose_name="location",
685
+ ),
686
+ ),
687
+ (
688
+ "species",
689
+ models.ForeignKey(
690
+ help_text="The species used to find matching Observations.",
691
+ on_delete=django.db.models.deletion.CASCADE,
692
+ related_name="filtered_on",
693
+ to="data.species",
694
+ verbose_name="species",
695
+ ),
696
+ ),
697
+ (
698
+ "update_species",
699
+ models.ForeignKey(
700
+ help_text="Matching Observations are updated to this species.",
701
+ on_delete=django.db.models.deletion.CASCADE,
702
+ related_name="filtered_by",
703
+ to="data.species",
704
+ verbose_name="update species",
705
+ ),
706
+ ),
707
+ ],
708
+ options={
709
+ "verbose_name": "filter",
710
+ "verbose_name_plural": "filters",
711
+ },
712
+ ),
713
+ migrations.CreateModel(
714
+ name="Observation",
715
+ fields=[
716
+ (
717
+ "id",
718
+ models.AutoField(
719
+ auto_created=True,
720
+ primary_key=True,
721
+ serialize=False,
722
+ verbose_name="ID",
723
+ ),
724
+ ),
725
+ (
726
+ "edited",
727
+ models.DateTimeField(
728
+ blank=True,
729
+ help_text="The date and time the eBird checklist was last edited.",
730
+ null=True,
731
+ verbose_name="edited",
732
+ ),
733
+ ),
734
+ (
735
+ "published",
736
+ models.BooleanField(
737
+ help_text="Is the observation published?",
738
+ verbose_name="published",
739
+ ),
740
+ ),
741
+ (
742
+ "identifier",
743
+ models.TextField(
744
+ help_text="A global unique identifier for the observation.",
745
+ unique=True,
746
+ verbose_name="identifier",
747
+ ),
748
+ ),
749
+ (
750
+ "date",
751
+ models.DateField(
752
+ db_index=True,
753
+ help_text="The date the observation was made.",
754
+ verbose_name="date",
755
+ ),
756
+ ),
757
+ (
758
+ "time",
759
+ models.TimeField(
760
+ blank=True,
761
+ help_text="The time the observation was made.",
762
+ null=True,
763
+ verbose_name="time",
764
+ ),
765
+ ),
766
+ (
767
+ "started",
768
+ models.DateTimeField(
769
+ blank=True,
770
+ db_index=True,
771
+ help_text="The date and time the observation was made.",
772
+ null=True,
773
+ verbose_name="date & time",
774
+ ),
775
+ ),
776
+ (
777
+ "count",
778
+ models.IntegerField(
779
+ help_text="The number of birds seen.",
780
+ validators=[django.core.validators.MinValueValidator(0)],
781
+ verbose_name="count",
782
+ ),
783
+ ),
784
+ (
785
+ "audio",
786
+ models.BooleanField(
787
+ default=False,
788
+ help_text="Have audio recordings been uploaded to the Macaulay library.",
789
+ verbose_name="has audio",
790
+ ),
791
+ ),
792
+ (
793
+ "photo",
794
+ models.BooleanField(
795
+ default=False,
796
+ help_text="Have photos been uploaded to the Macaulay library.",
797
+ verbose_name="has photos",
798
+ ),
799
+ ),
800
+ (
801
+ "video",
802
+ models.BooleanField(
803
+ default=False,
804
+ help_text="Have video recordings been uploaded to the Macaulay library.",
805
+ verbose_name="has video",
806
+ ),
807
+ ),
808
+ (
809
+ "approved",
810
+ models.BooleanField(
811
+ default=True,
812
+ help_text="Has the observation been accepted.",
813
+ verbose_name="Approved",
814
+ ),
815
+ ),
816
+ (
817
+ "reason",
818
+ models.TextField(
819
+ blank=True,
820
+ help_text="The reason given for the observation to be marked as not approved.",
821
+ verbose_name="Reason",
822
+ ),
823
+ ),
824
+ (
825
+ "comments",
826
+ models.TextField(
827
+ blank=True,
828
+ help_text="Any comments about the observation.",
829
+ verbose_name="comments",
830
+ ),
831
+ ),
832
+ (
833
+ "urn",
834
+ models.TextField(
835
+ blank=True,
836
+ help_text="The globally unique identifier for the observation.",
837
+ verbose_name="URN",
838
+ ),
839
+ ),
840
+ (
841
+ "data",
842
+ models.JSONField(
843
+ blank=True,
844
+ default=dict,
845
+ help_text="Data describing an Observation.",
846
+ verbose_name="Data",
847
+ ),
848
+ ),
849
+ (
850
+ "checklist",
851
+ models.ForeignKey(
852
+ help_text="The checklist this observation belongs to.",
853
+ on_delete=django.db.models.deletion.CASCADE,
854
+ related_name="observations",
855
+ to="data.checklist",
856
+ verbose_name="checklist",
857
+ ),
858
+ ),
859
+ (
860
+ "country",
861
+ models.ForeignKey(
862
+ help_text="The country where the observation was made.",
863
+ on_delete=django.db.models.deletion.PROTECT,
864
+ related_name="observations",
865
+ to="data.country",
866
+ verbose_name="country",
867
+ ),
868
+ ),
869
+ (
870
+ "county",
871
+ models.ForeignKey(
872
+ blank=True,
873
+ help_text="The county where the observation was made.",
874
+ null=True,
875
+ on_delete=django.db.models.deletion.PROTECT,
876
+ related_name="observations",
877
+ to="data.county",
878
+ verbose_name="county",
879
+ ),
880
+ ),
881
+ (
882
+ "location",
883
+ models.ForeignKey(
884
+ help_text="The location where the observation was made.",
885
+ on_delete=django.db.models.deletion.PROTECT,
886
+ related_name="observations",
887
+ to="data.location",
888
+ verbose_name="location",
889
+ ),
890
+ ),
891
+ (
892
+ "observer",
893
+ models.ForeignKey(
894
+ help_text="The person who made the observation.",
895
+ on_delete=django.db.models.deletion.PROTECT,
896
+ related_name="observations",
897
+ to="data.observer",
898
+ verbose_name="observer",
899
+ ),
900
+ ),
901
+ (
902
+ "species",
903
+ models.ForeignKey(
904
+ help_text="The identified species.",
905
+ on_delete=django.db.models.deletion.PROTECT,
906
+ related_name="observations",
907
+ to="data.species",
908
+ verbose_name="species",
909
+ ),
910
+ ),
911
+ (
912
+ "state",
913
+ models.ForeignKey(
914
+ help_text="The state where the observation was made.",
915
+ on_delete=django.db.models.deletion.PROTECT,
916
+ related_name="observations",
917
+ to="data.state",
918
+ verbose_name="state",
919
+ ),
920
+ ),
921
+ ],
922
+ options={
923
+ "verbose_name": "observation",
924
+ "verbose_name_plural": "observations",
925
+ },
926
+ ),
927
+ ]