-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathforms.py
More file actions
1100 lines (765 loc) · 44.4 KB
/
forms.py
File metadata and controls
1100 lines (765 loc) · 44.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
from __future__ import unicode_literals
'''
Copyright 2010-2016 Jonathan Morgan
This file is part of http://github.com/jonathanmorgan/context_text.
context_text is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
context_text is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with http://github.com/jonathanmorgan/context_text. If not, see http://www.gnu.org/licenses/.
'''
'''
How to add a value to one of these context_text forms and then get that value
properly passed through to all the things that might use it:
- 1) If your form input will have a set of values from which the user will
choose, figure out what those values will be and make variables to hold the
specific values and to hold a dictionary that maps values to display names
in the appropriate class in context_text. For example:
- add parameters related to network output to the class NetworkOutput in
file /export/network_output.py (though if those parameters will also be
used by NetworkDataOutput, you should declare them there, then just
reference them in NetworkOutput).
- add parameters related to automated coding of articles to the class
ArticleCoding, in file /article_coding/article_coding.py.
Example - adding person query type values to NetworkDataOutput:
# Person Query Types
PERSON_QUERY_TYPE_ALL = "all"
PERSON_QUERY_TYPE_ARTICLES = "articles"
PERSON_QUERY_TYPE_CUSTOM = "custom"
PERSON_QUERY_TYPE_CHOICES_LIST = [
( PERSON_QUERY_TYPE_ALL, "All persons" ),
( PERSON_QUERY_TYPE_ARTICLES, "From selected articles" ),
( PERSON_QUERY_TYPE_CUSTOM, "Custom, defined below" ),
]
And then referencing them from NetworkOutput:
# Person Query Types
PERSON_QUERY_TYPE_ALL = NetworkDataOutput.PERSON_QUERY_TYPE_ALL
PERSON_QUERY_TYPE_ARTICLES = NetworkDataOutput.PERSON_QUERY_TYPE_ARTICLES
PERSON_QUERY_TYPE_CUSTOM = NetworkDataOutput.PERSON_QUERY_TYPE_CUSTOM
PERSON_QUERY_TYPE_CHOICES_LIST = NetworkDataOutput.PERSON_QUERY_TYPE_CHOICES_LIST
- 2) Add a PARAM_* constant that contains the input name you'll use to reference
the new field in the form, and then subsequently whenever the associated
value is needed throughout the application. Example - adding a person query
type to tell network outputter how to figure out which people to include in
the network, first to NetworkDataOutput:
PARAM_PERSON_QUERY_TYPE = "person_query_type"
Then, referring to it in NetworkOutput:
PARAM_PERSON_QUERY_TYPE = NetworkDataOutput.PARAM_PERSON_QUERY_TYPE
- 3) Add that parameter to PARAM_NAME_TO_TYPE_MAP in NetworkOutput or
ArticleCoding, with the parameter name mapped to the appropriate type from
the ParamContainer class in python_utilities. Example, adding our string
person query type to NetworkOutput's PARAM_NAME_TO_TYPE_MAP:
PARAM_PERSON_QUERY_TYPE : ParamContainer.PARAM_TYPE_STRING,
- 4) Add the value to the appropriate form below, using the same name as was in
your PARAM_* constant. Example - adding a person query type select box to
the person select form, referencing the choices list defined above:
person_query_type = forms.ChoiceField( required = False, choices = NetworkOutput.PERSON_QUERY_TYPE_CHOICES_LIST )
- 5) Into what function or method do I then update processing to include the
new field?:
- For network output, method that creates QuerySets from form parameters is
create_query_set(), in context_text/export/network_output.py,
NetworkOutput.create_query_set(). This method is called by both
create_person_query_set() and create_network_query_set(). If you add
a parameter to the article select and the person select, make sure
make the name of the person input the same as the article one, but
preceded by "person_". That will make the single method able to
process values for either the article or person form. For example, the
coder_type_filter_type, from NetworkDataOutput class:
PARAM_CODER_TYPE_FILTER_TYPE = "coder_type_filter_type"
PARAM_PERSON_CODER_TYPE_FILTER_TYPE = "person_" + PARAM_CODER_TYPE_FILTER_TYPE
'''
# import six for Python 2 and 3 compatibility.
import six
# import django form object.
from django import forms
# import django user authentication User object, for limiting to certain users.
from django.contrib.auth.models import User
from django.db.models.query import QuerySet
# django-autocomplete-light imports
from dal import autocomplete
# python_utilities
from python_utilities.django_utils.django_form_helper import DjangoFormHelper
from python_utilities.django_utils.django_form_helper import FormParent
from python_utilities.django_utils.django_form_helper import ModelFormParent
from python_utilities.lists.list_helper import ListHelper
from python_utilities.logging.logging_helper import LoggingHelper
# context imports
from context.shared.person_details import PersonDetails
# import stuff from context_text
#from mysite.context_text.export.network_output import NetworkOutput
from context_text.export.csv_article_output import CsvArticleOutput
from context_text.export.network_output import NetworkOutput
#from context_text.export.network_data_output import NetworkDataOutput
from context_text.models import Article
from context_text.models import Article_Data
from context_text.models import Article_Subject
from context_text.models import Newspaper
from context_text.models import Person
from context_text.models import Topic
#===============================================================================
# ! ==> Parent classes imported from python_utilities.django_utils.django_form_helper
#===============================================================================
#===============================================================================
# ! ==> Classes
#===============================================================================
class Article_DataLookupForm( forms.Form ):
'''
create a form to let a user lookup an article to view its Article_Data.
'''
# Article_Data ID
article_data_id = forms.IntegerField( required = True, label = "Article Data ID" )
#-- END Form class ArticleLookupForm --#
class Article_DataSelectForm( forms.Form ):
'''
create a form to let a user select from Article_Data related to an article
passed in to the form's __init__() method.
'''
def __init__( self, *args, **kwargs ):
# declare variables
article_IN = None
article_data_qs = None
article_data_count = -1
article_data_choice_list = []
article_data_instance = None
ad_id = -1
ad_coder = None
ad_coder_type = ""
ad_display_string = ""
# retrieve article passed in.
article_id_IN = kwargs.pop( 'article_id' )
# call parent __init__() method.
super( Article_DataSelectForm, self ).__init__(*args, **kwargs)
# got an article?
if ( ( article_id_IN is not None ) and ( article_id_IN > 0 ) ):
# got any Article_Data instances?
article_data_qs = Article_Data.objects.filter( article_id = article_id_IN )
article_data_count = article_data_qs.count()
if ( article_data_count > 0 ):
# yes. Loop, building a list of 2-tuples for each option,
# ( <actual_value>, <display_string> ).
for article_data_instance in article_data_qs:
# get ID, coder, and coder type
ad_id = article_data_instance.id
ad_coder = article_data_instance.coder
ad_coder_type = article_data_instance.coder_type
# create display string
ad_display_string = str( ad_id ) + " - " + str( ad_coder ) + " ( " + str( ad_coder_type ) + " )"
# add tuple to list
article_data_choice_list.append( ( ad_id, ad_display_string ) )
#-- END loop over choices. --#
# add a form field to allow user to select Article_Data
# instances to display.
self.fields[ 'article_data_id_select' ] = forms.MultipleChoiceField( required = False, choices = article_data_choice_list )
#-- END - check to see how many Article_Data --#
#-- END - check to see if article present. --#
#-- END overridden/extended function __init__() --#
#-- END Form class ArticleLookupForm --#
class ArticleCodingArticleFilterForm( forms.Form ):
# constants-ish
IAMEMPTY = "IAMEMPTY"
'''
create a form to let a user specify the criteria used to limit the articles
that are used to create output.
'''
# what fields do I want?
# start date
start_date = forms.DateField( required = False, label = "Start Date (YYYY-MM-DD)" )
# end date
end_date = forms.DateField( required = False, label = "End Date (YYYY-MM-DD)" )
# date range - text date range field that can parse out date ranges -
# double-pipe delimited, " to " between dates that bound a range, could
# add more later.
# Ex.: "YYY1-M1-D1 to YYY2-M2-D2||YYY3-M3-D3 to YYY4-M4-D4", etc.
date_range = forms.CharField( required = False, label = "* Fancy date range" )
# publication
publications = forms.ModelMultipleChoiceField( required = False, queryset = Newspaper.objects.all() )
# list of unique identifiers to limit to.
tags_list = forms.CharField( required = False, label = "Article Tag List (comma-delimited)" )
# list of unique identifiers to limit to.
unique_identifiers = forms.CharField( required = False, label = "Unique Identifier List (comma-delimited)" )
# list of unique identifiers to limit to.
article_id_list = forms.CharField( required = False, label = "Article ID IN List (comma-delimited)" )
# list of unique identifiers to limit to.
section_list = forms.CharField( required = False, label = "String Section Name IN List (comma-delimited)" )
#--------------------------------------------------------------------------#
# methods
#--------------------------------------------------------------------------#
def am_i_empty( self, *args, **kwargs ):
'''
Goes through the fields in the form and checks to see if any has been
populated. If not, returns True (it is empty!). If there is a
value in any of them, returns False (not empty).
'''
# return reference
is_empty_OUT = True
# declare variables
me = "am_i_empty"
my_logger_name = "context_text.forms.ArticleCodingArticleFilterForm"
debug_message = ""
# use DjangoFormHelper method
is_empty_OUT = DjangoFormHelper.is_form_empty( self )
return is_empty_OUT
#-- END method am_i_empty() --#
#-- END Form class ArticleCodingArticleFilterForm --#
class ArticleCodingForm( forms.ModelForm ):
'''
Create a form to let a user look up the source.
'''
class Meta:
model = Article_Subject
fields = [ "person", ]
#exclude = [ 'article_data', 'original_person', 'match_confidence_level', 'match_status', 'capture_method', 'create_date', 'last_modified', 'source_type', 'subject_type', 'name', 'verbatim_name', 'lookup_name', 'title', 'more_title', 'organization', 'document', 'topics', 'source_contact_type', 'source_capacity', 'localness', 'notes', 'organization_string', 'more_organization' ]
# AJAX lookup for person.
person = forms.ModelChoiceField(
queryset = Person.objects.all(),
widget = autocomplete.ModelSelect2( url = 'autocomplete-person' )
)
#-- END ModelForm class ArticleCodingForm --#
class ArticleCodingListForm( forms.Form ):
'''
form to hold lookup criteria for articles that need to be coded. To start,
just includes list of tags.
'''
# list of unique tags to limit to.
tags_in_list = forms.CharField( required = True, label = "Article Tag List (comma-delimited)" )
#-- END Form class ArticleLookupForm --#
class ArticleCodingPersonAmbiguityForm( forms.Form ):
'''
form to hold lookup criteria for articles that need to be coded. To start,
just includes list of tags.
'''
# list of unique tags to limit to.
article_tags_in_list = forms.CharField( required = False, label = "Article Tag List (comma-delimited)" )
#-- END Form class ArticleCodingPersonAmbiguityForm --#
class ArticleCodingSubmitForm( forms.Form ):
'''
form to hold coding details for a given article.
'''
# PersonStore JSON
data_store_json = forms.CharField( required = False, widget = forms.HiddenInput() )
article_data_id = forms.IntegerField( required = False, widget = forms.HiddenInput() )
#-- END Form class ArticleLookupForm --#
class ArticleDataFilterForm( FormParent ):
'''
create a form to let a user specify the criteria used to filter
Article_Data records.
'''
# what fields do I want?
# coders to include
coders = forms.ModelMultipleChoiceField( required = False, queryset = User.objects.all() )
# type of filtering on Article_Data coder_type identifiers we want to do.
coder_type_filter_type = forms.ChoiceField( required = False,
choices = NetworkOutput.CODER_TYPE_FILTER_TYPE_CHOICES_LIST,
initial = NetworkOutput.CODER_TYPE_FILTER_TYPE_DEFAULT,
label = "Article_Data coder_type Filter Type" )
# list of Article_Data coder_type identifiers to limit to.
coder_types_list = forms.CharField( required = False, label = "coder_type 'Value In' List (comma-delimited)" )
# list of unique identifiers to limit to.
tags_in_list_IN = forms.CharField( required = False, label = "Article Tag List (comma-delimited)" )
# article_id_list - list of Article IDs whose coding we want to see.
article_id_list = forms.CharField( required = False, label = "IDs of Articles whose coding you want (,)" )
#-- END Form class ArticleDataFilterForm --#
class ArticleDataProcessingForm( forms.Form ):
'''
allows user to specify list of tags they would like to be applied to
some taggable entity.
'''
# action choices
ACTION_CHOICES = (
( "match_summary", "Match Summary" ),
( "view_matches", "View Matches" ),
)
action = forms.ChoiceField( required = True, choices = ACTION_CHOICES )
#-- END Form class ArticleDataProcessingForm --#
class ArticleLookupForm( forms.Form ):
'''
create a form to let a user lookup an article to view its contents.
'''
# Article ID
article_id = forms.IntegerField( required = True, label = "Article ID" )
#-- Form class END ArticleLookupForm --#
class ArticleOutputTypeSelectForm( forms.Form ):
'''
form inputs to let a user specify the criteria used to limit the articles
that are used to create output.
'''
# just contains the output type field for outputting network data.
output_type = forms.ChoiceField( label = "Output Type", choices = CsvArticleOutput.OUTPUT_TYPE_CHOICES_LIST )
# and a place to specify the text you want pre-pended to each column header.
header_prefix = forms.CharField( required = False, label = "Column Header Prefix" )
#-- END Form class ArticleOutputTypeSelectForm --#
class ArticleSelectForm( forms.Form ):
'''
create a form to let a user specify the criteria used to limit the articles
that are used to create output.
'''
# what fields do I want?
# start date
start_date = forms.DateField( required = False, label = "Start Date (YYYY-MM-DD)" )
# end date
end_date = forms.DateField( required = False, label = "End Date (YYYY-MM-DD)" )
# date range - text date range field that can parse out date ranges -
# double-pipe delimited, " to " between dates that bound a range, could
# add more later.
# Ex.: "YYY1-M1-D1 to YYY2-M2-D2||YYY3-M3-D3 to YYY4-M4-D4", etc.
date_range = forms.CharField( required = False, label = "* Fancy date range" )
# publication
publications = forms.ModelMultipleChoiceField( required = False, queryset = Newspaper.objects.all() )
# coders to include
coders = forms.ModelMultipleChoiceField( required = False, queryset = User.objects.all() )
coder_id_priority_list = forms.CharField( required = False, label = "Coder IDs to include, in order of highest to lowest priority" )
# type of filtering on Article_Data coder_type identifiers we want to do.
coder_type_filter_type = forms.ChoiceField( required = False,
choices = NetworkOutput.CODER_TYPE_FILTER_TYPE_CHOICES_LIST,
initial = NetworkOutput.CODER_TYPE_FILTER_TYPE_DEFAULT,
label = "Article_Data coder_type Filter Type" )
# list of Article_Data coder_type identifiers to limit to.
coder_types_list = forms.CharField( required = False, label = "coder_type 'Value In' List (comma-delimited)" )
# topics to include
topics = forms.ModelMultipleChoiceField( required = False, queryset = Topic.objects.all() )
# list of tag values Articles to be included must have one or more of.
tags_list = forms.CharField( required = False, label = "Include Articles With Tags In List (comma-delimited)" )
# list of unique Article identifiers to limit to.
unique_identifiers = forms.CharField( required = False, label = "Include Articles With unique_identifier In List (comma-delimited)" )
# allow duplicate articles?
allow_duplicate_articles = forms.ChoiceField( required = False, choices = NetworkOutput.CHOICES_YES_OR_NO_LIST )
#-- END Form class ArticleSelectForm --#
class NetworkOutputForm( forms.Form ):
'''
NetworkOutputForm lets user specify details about the format and structure
of the output that will capture network data - can specify file format,
for example, whether to include render details/debug, and other details
of the data that will result from examining Article_Data.
'''
# do we want to download result as file?
network_download_as_file = forms.ChoiceField( required = False, label = "Download As File?", choices = NetworkOutput.CHOICES_YES_OR_NO_LIST )
# include render details?
network_include_render_details = forms.ChoiceField( required = False, label = "Include Render Details?", choices = NetworkOutput.CHOICES_YES_OR_NO_LIST )
# just contains the format you want the network data outputted as.
output_type = forms.ChoiceField( label = "Data Format", choices = NetworkOutput.NETWORK_OUTPUT_TYPE_CHOICES_LIST, initial = NetworkOutput.NETWORK_OUTPUT_TYPE_DEFAULT )
# data to output - either just network, just node attributes, both with attributes in columns, or both with attributes in rows.
network_data_output_type = forms.ChoiceField( label = "Data Output Type", choices = NetworkOutput.NETWORK_DATA_OUTPUT_TYPE_CHOICES_LIST, initial = NetworkOutput.NETWORK_DATA_OUTPUT_TYPE_DEFAULT )
# do we want a label at the top of the network file?
network_label = forms.CharField( required = False, label = "Network Label" )
# do we want to output row and column headers?
network_include_headers = forms.ChoiceField( required = False, label = "Include headers?", choices = NetworkOutput.CHOICES_YES_OR_NO_LIST )
# do we want to store the network data output in database?
database_output = forms.ChoiceField( required = False, label = "DB - Store output in database?", choices = NetworkOutput.CHOICES_YES_OR_NO_LIST, initial = NetworkOutput.CHOICE_NO )
db_add_timestamp_to_label = forms.ChoiceField( required = False, label = "DB - Add timestamp to label?", choices = NetworkOutput.CHOICES_YES_OR_NO_LIST, initial = NetworkOutput.CHOICE_YES )
db_save_data_in_database = forms.ChoiceField( required = False, label = "DB - Save data in database?", choices = NetworkOutput.CHOICES_YES_OR_NO_LIST, initial = NetworkOutput.CHOICE_YES )
save_data_in_folder = forms.CharField( required = False, label = "FS - Save data in folder (path)" )
#-- END Form class NetworkOutputForm --#
class PersonLookupTypeForm( FormParent ):
'''
allows user to specify list of tags they would like to be applied to
some taggable entity.
'''
PERSON_LOOKUP_TYPE_GENERAL_QUERY = "general_query"
PERSON_LOOKUP_TYPE_EXACT_QUERY = "exact_query"
# action choices
PERSON_LOOKUP_TYPE_CHOICES = (
( PERSON_LOOKUP_TYPE_GENERAL_QUERY, "General Query (match what is entered, ignore anything not entered)" ),
( PERSON_LOOKUP_TYPE_EXACT_QUERY, "Exact Query (match exactly what is entered, even empty fields)" ),
)
lookup_type = forms.ChoiceField( required = True, choices = PERSON_LOOKUP_TYPE_CHOICES )
#-- END Form class PersonLookupTypeForm --#
class PersonLookupByIDForm( FormParent ):
'''
Form that holds ways of finding and retrieving persons with certain IDs. To
start includes a list of IDs, or the ID of either an Article_Subject or
Article_Author instance that might contain references to multiple
people amongst which there is some ambiguity.
'''
person_id_in_list = forms.CharField( required = False, label = "Person ID List (comma-delimited)" )
article_author_id = forms.CharField( required = False, label = "Article_Author ID" )
article_subject_id = forms.CharField( required = False, label = "Article_Subject ID" )
#--------------------------------------------------------------------------#
# class methods
#--------------------------------------------------------------------------#
@classmethod
def lookup_person_by_id( cls, request_inputs_IN, person_qs_IN = None, response_dictionary_IN = None, *args, **kwargs ):
'''
Accepts request inputs we'd expect to contain the fields defined for
this form. Uses this information to lookup Persons and returns the
QuerySet that contains the results of the lookup. If error, returns None.
'''
# return reference
qs_OUT = None
# declare variables
me = "lookup_person_by_id"
my_logger_name = "context_text.forms.PersonLookupByIDForm"
debug_message = ""
request_inputs = None
person_qs = None
person_id_in_list_string = ""
person_id_in_list = []
article_author_id = -1
article_subject_id = -1
article_author = None
article_subject = None
temp_list = []
# first, make sure we have request inputs.
if ( request_inputs_IN is not None ):
# store off the inputs.
request_inputs = request_inputs_IN
# got a person qs?
if ( person_qs_IN is not None ):
person_qs = person_qs_IN
#-- END check to see if person_qs --#
# get values from form
person_id_in_list_string = request_inputs.get( "person_id_in_list", None )
# convert string to list
if ( ( person_id_in_list_string is not None ) and ( person_id_in_list_string != "" ) ):
# got something. Try to coerce it into a python list.
person_id_in_list = ListHelper.get_value_as_list( person_id_in_list_string, delimiter_IN = "," )
debug_message = "found person ID list - using it."
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
else:
# no ID list passed in. Make an empty list.
person_id_in_list = []
debug_message = "no straight up list of person IDs passed in - creating empty list,"
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
#-- END check to see if person ID list passed in --#
# see if there are Article_Subject or Article_Author IDs.
article_author_id = request_inputs.get( "article_author_id", None )
article_subject_id = request_inputs.get( "article_subject_id", None )
debug_message = "article_author_id: " + str( article_author_id )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
debug_message = "article_subject_id: " + str( article_subject_id )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# Article_Author?
if ( ( article_author_id is not None )
and ( article_author_id != "" )
and ( int( article_author_id ) > 0 ) ):
try:
# Got one. Look up instance based on ID.
article_author = Article_Author.objects.get( pk = article_author_id )
debug_message = "found Article_Author: " + str( article_author )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# see if any associated Persons.
temp_list = article_author.get_associated_person_id_list()
if ( ( temp_list is not None )
and ( isinstance( temp_list, list ) == True )
and ( len( temp_list ) > 0 ) ):
# got something in list. Append it to the end of
# the person_id_in_list.
person_id_in_list.extend( temp_list )
#-- END check to see if associated Persons. --#
except Article_Author.DoesNotExist as dne:
debug_message = "No Article_Author found for ID " + str( article_author_id )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
if ( response_dictionary_IN is not None ):
response_dictionary_IN[ 'output_string' ] = debug_message
#-- END check to see if response dictionary. --#
#-- END try/except lookup for Article_Author --#
#-- END check to see if article_author_id --#
# Article_Subject?
if ( ( article_subject_id is not None )
and ( article_subject_id != "" )
and ( int( article_subject_id ) > 0 ) ):
try:
# Got one. Look up instance based on ID.
article_subject = Article_Subject.objects.get( pk = article_subject_id )
debug_message = "found Article_Subject: " + str( article_subject )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# see if any associated Persons.
temp_list = article_subject.get_associated_person_id_list()
debug_message = "Associated Person IDs in Article_Subject: " + str( article_subject ) + ", ID list = " + str( temp_list )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
if ( ( temp_list is not None )
and ( isinstance( temp_list, list ) == True )
and ( len( temp_list ) > 0 ) ):
# got something in list. Append it to the end of
# the person_id_in_list.
person_id_in_list.extend( temp_list )
#-- END check to see if associated Persons. --#
except Article_Subject.DoesNotExist as dne:
debug_message = "No Article_Subject found for ID " + str( article_subject_id )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
if ( response_dictionary_IN is not None ):
response_dictionary_IN[ 'output_string' ] = debug_message
#-- END check to see if response dictionary. --#
#-- END try/except lookup for Article_Author --#
#-- END check to see if article_subject_id --#
debug_message = "Before filtering: person_id_in_list = " + str( person_id_in_list ) + "; person_qs = " + str( person_qs )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# anything in person_id_in_list?
if ( ( person_id_in_list is not None )
and ( isinstance( person_id_in_list, list ) == True )
and ( len( person_id_in_list ) > 0 ) ):
# there are IDs to look for. Do we have a QuerySet
# already?
if ( person_qs is None ):
# no. Initialize to all()
person_qs = Person.objects.all()
#-- END check to see if Person QuerySet --#
# filter.
person_qs = person_qs.filter( pk__in = person_id_in_list )
#-- END check to see if anything in ID list. --#
else:
debug_message = "no request_inputs_IN, so no query - returning None."
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
person_qs = None
#-- END check to see if request_inputs_IN --#
# return person_qs
qs_OUT = person_qs
return qs_OUT
#-- END class method lookup_person_by_id() --#
#--------------------------------------------------------------------------#
# instance methods
#--------------------------------------------------------------------------#
#-- END Form class PersonLookupByIDForm --#
class PersonLookupByNameForm( ModelFormParent ):
# constants-ish
IAMEMPTY = "IAMEMPTY"
'''
PersonNameLookupForm lets user specify full name or parts of a name to use
to lookup one or more matching Person records.
'''
class Meta:
model = Person
fields = [ "full_name_string", "first_name", "middle_name", "last_name", "name_prefix", "name_suffix", "nickname" ]
'''
# name string - will be parsed as when a Person is created automatically
# from a name string.
full_name_string = models.CharField( max_length = 255, blank = True, null = True )
# name parts
first_name = models.CharField( max_length = 255, blank = True, null = True )
middle_name = models.CharField( max_length = 255, blank = True, null = True )
last_name = models.CharField( max_length = 255, blank = True, null = True )
name_prefix = models.CharField( max_length = 255, blank = True, null = True )
name_suffix = models.CharField( max_length = 255, blank = True, null = True )
nickname = models.CharField( max_length = 255, blank = True, null = True )
'''
#--------------------------------------------------------------------------#
# class methods
#--------------------------------------------------------------------------#
@classmethod
def lookup_person_by_name( cls, request_inputs_IN, lookup_type_IN = None, person_qs_IN = None, *args, **kwargs ):
'''
Accepts request inputs we'd expect to contain the fields defined for
this form and a lookup type that is one of those in the form class
PersonLookupTypeForm defined above. Uses this information to lookup
a person and returns the QuerySet that contains the results of the
lookup. If error, returns None.
'''
# return reference
qs_OUT = None
# declare variables
me = "lookup_person_by_name"
my_logger_name = "context_text.forms.PersonLookupByNameForm"
debug_message = ""
request_inputs = None
lookup_type = ""
person_qs = None
my_person_details = None
human_name = None
name_string = None
do_strict_match = False
do_partial_match = False
# first, make sure we have request inputs.
if ( request_inputs_IN is not None ):
# store off the inputs.
request_inputs = request_inputs_IN
# and the lookup type.
lookup_type = lookup_type_IN
debug_message = "lookup_type = " + str( lookup_type )
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# got a person qs?
if ( person_qs_IN is not None ):
person_qs = person_qs_IN
#-- END check to see if person_qs --#
# retrieve Person records specified by the input parameters,
# ordered by Last Name, then First Name. Then, create HTML
# output of list of articles. For each, output (to start):
# - Person string
# populate PersonDetails from request_inputs:
my_person_details = PersonDetails.get_instance( request_inputs )
# get HumanName instance...
human_name = my_person_details.to_HumanName()
name_string = str( human_name )
# do lookup based on lookup_type
if ( lookup_type == PersonLookupTypeForm.PERSON_LOOKUP_TYPE_GENERAL_QUERY ):
debug_message = "performing general query"
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# not strict
do_strict_match = False
do_partial_match = True
person_qs = Person.look_up_person_from_name( name_IN = name_string,
parsed_name_IN = human_name,
do_strict_match_IN = do_strict_match,
do_partial_match_IN = do_partial_match,
qs_IN = person_qs )
elif ( lookup_type == PersonLookupTypeForm.PERSON_LOOKUP_TYPE_EXACT_QUERY ):
debug_message = "performing exact query"
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# strict
do_strict_match = True
do_partial_match = False
person_qs = Person.look_up_person_from_name( name_IN = name_string,
parsed_name_IN = human_name,
do_strict_match_IN = do_strict_match,
do_partial_match_IN = do_partial_match,
qs_IN = person_qs )
else:
debug_message = "no lookup_type, so doing general query"
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
# default to not strict
do_strict_match = False
do_partial_match = True
person_qs = Person.look_up_person_from_name( name_IN = name_string,
parsed_name_IN = human_name,
do_strict_match_IN = do_strict_match,
do_partial_match_IN = do_partial_match,
qs_IN = person_qs )
#-- END decide how to lookup based on lookup_type --#
else:
debug_message = "no request_inputs_IN, so no query - returning None."
LoggingHelper.output_debug( debug_message, method_IN = me, logger_name_IN = my_logger_name )
person_qs = None
#-- END check to see if request_inputs_IN --#
# return person_qs
qs_OUT = person_qs
return qs_OUT
#-- END class method lookup_person() --#
#--------------------------------------------------------------------------#
# instance methods
#--------------------------------------------------------------------------#
#-- END ModelForm class PersonLookupByNameForm --#
class Person_LookupResultViewForm( FormParent ):
'''
allows user to specify list of tags they would like to be applied to
some taggable entity.
'''
# action choices
PERSON_RESULT_VIEW_CHOICES = (
( "match_summary", "Match Summary" ),
( "view_matches", "View Matches" ),
#( "merge", "Merge Person records" ),
)
lookup_action = forms.ChoiceField( required = True, choices = PERSON_RESULT_VIEW_CHOICES )
# apply_tags_list (comma-delimited)
#apply_tags_list = forms.CharField( required = False, label = "If 'Apply Tags', list of tags to apply (comma-delimited)" )
#-- END Form class Person_ProcessSelectedForm --#
class Person_MergeActionForm( FormParent ):
'''
Allows user to select from different types of merges to perform. To start,
just merge coding.
'''
#===========================================================================
# ! ==> CONSTANTS-ISH
#===========================================================================
# merge_action choices
PERSON_MERGE_ACTION_LOOKUP = "lookup"
PERSON_MERGE_ACTION_MERGE_CODING = "merge_coding"
PERSON_MERGE_ACTION_UN_MERGE_CODING = "un_merge_coding"
PERSON_MERGE_ACTION_MERGE_ALL = "merge_all"
PERSON_MERGE_ACTION_CHOICES = (
( PERSON_MERGE_ACTION_LOOKUP, "Lookup (no changes)" ),
( PERSON_MERGE_ACTION_MERGE_CODING, "Merge Coding --> FROM 1 / INTO 1" ),
( PERSON_MERGE_ACTION_UN_MERGE_CODING, "Un-Merge Coding --> FROM = person we want coding to once again refer to; INTO (optional) = only undo records updated to refer to this person." ),
#( PERSON_MERGE_ACTION_MERGE_ALL, "Merge All Person Data" ),
)
# other constants
INPUT_NAME_MERGE_FROM_PREFIX = "merge_from_person_id_"
INPUT_NAME_MERGE_INTO_PREFIX = "merge_into_person_id_"
#===========================================================================
# ! ==> fields
#===========================================================================
merge_action = forms.ChoiceField( required = False, choices = PERSON_MERGE_ACTION_CHOICES )
#-- END Form class Person_MergeActionForm --#
# create a form to let a user specify the criteria used to limit the output form
class PersonSelectForm( forms.Form ):
'''
PersonSelectForm lets user specify additional filter criteria for selecting
the people who will be included in a given network. This should be used
to broaden the set of people included in a given network so that networks
over time will include the same set of people, even if some aren't
present in a given time slice.
'''
# people to include?
# first, have a field that lets the user choose the overall strategy for
# choosing the people who will make up the rows and columns of the
# resulting attribution network. Three choices:
# - all - just gets all the people in the database.
# - articles - limits to people found in selected articles.
# - custom - pulls in people based on the filter criteria below.
person_query_type = forms.ChoiceField( required = False, choices = NetworkOutput.PERSON_QUERY_TYPE_CHOICES_LIST, initial = NetworkOutput.PERSON_QUERY_TYPE_DEFAULT )
# criteria for pulling in people, so we can include a broader set of people
# in a given network, so it can be compared to other networks with
# criteria that might make them more broad. Across invocations, a list
# of the same sources will sort the same, so networks that include a set
# of people are comparable even if the network data is generated at
# different times.
person_start_date = forms.DateField( required = False, label = "People from (YYYY-MM-DD)" )