def test_registration_details_form(self): """Verify that forms listed in KSP_LOGIN_PROFILE_FORMS work. """ response = self.social_testing_login() # A registration form is displayed to the user. self.assertRedirects(response, '/account/register/') # The registration form includes additional fields from the # UserProfileForm defined in this testing app. self.assertContains( response, b'<input type="text" name="birthday" id="id_birthday" />', html=True, ) # The type of an NumberInput has changed in 1.6, which means we # need to render it manually here. expected = IntegerField().widget.render('shoe_size', None, {'id': 'id_shoe_size'}) self.assertContains( response, expected.encode('utf-8'), html=True, ) # Submit the registration form... data = { 'username': '******', 'email': '*****@*****.**', 'first_name': 'Colleague', 'last_name': 'Knuk', 'birthday': '2014-01-10', 'shoe_size': 47, } response = self.client.post('/account/register/', data, follow=True) # The account settings page should also contain the additional # form, pre-filled with previously submitted values. response = self.client.get('/account/') self.assertContains( response, b'<input type="text" value="2014-01-10" name="birthday" id="id_birthday" />', html=True, ) expected = IntegerField().widget.render('shoe_size', 47, {'id': 'id_shoe_size'}) self.assertContains( response, expected.encode('utf-8'), html=True, )
class PollFormLineCreateForm(_PollFormLineForm): type = TypedChoiceField( label=_('Type'), choices=PollLineType.choices(), coerce=int, initial=PollLineType.STRING, ) lower_bound = IntegerField( label=_('Lower bound'), required=False, help_text=_('For integer type only.'), ) upper_bound = IntegerField( label=_('Upper bound'), required=False, help_text=_('For integer type only.'), ) choices = CharField( widget=Textarea(), label=_('Available choices'), required=False, help_text=_('Give the possible choices (one per line) ' 'if you choose the type "Choice list".'), ) def __init__(self, section=None, *args, **kwargs): super().__init__(*args, **kwargs) self.section = section self.section_lines = section_lines = [ ] # Lines which are in the section where we create our line self.next_lines = next_lines = [ ] # The lines after the one we create (but not in the same section): # their order have to be incremented self.empty_section_order = 1 # Order of the last line before our section (used if our section is empty) nodes = [*SectionTree(self.pform)] section_id = section.id if section else None # Filling of 'section_lines' & 'next_lines' node_it = reversed(nodes) try: while True: node = next(node_it) if not node.is_section: if node.section_id == section_id: section_lines.append(node) else: next_lines.append(node) elif node.id == section_id: previous_line = find_first( node_it, (lambda node: not node.is_section), None) if previous_line: self.empty_section_order = previous_line.order + 1 break except StopIteration: pass if section_lines: section_lines.reverse() msg_fmt = gettext('Before: «{question}» (#{number})' ).format # TODO: cached_gettext ?? choices = [ (0, gettext('Start of section')), *((i, msg_fmt(question=node.question, number=node.number)) for i, node in enumerate(section_lines[1:], start=1)), (len(section_lines), gettext('End of section')) ] self.fields['index'] = TypedChoiceField( label=gettext('Order'), coerce=int, choices=choices, initial=len(choices) - 1, ) def clean(self): cleaned_data = super().clean() if not self._errors: get_data = cleaned_data.get self.type_args = PollLineType.build_serialized_args( ptype=cleaned_data['type'], lower_bound=get_data('lower_bound'), upper_bound=get_data('upper_bound'), choices=[ *enumerate( filter(None, (choice.strip() for choice in get_data( 'choices', '').split('\n'))), start=1, ) ], ) # Can raise Validation errors return cleaned_data def save(self, *args, **kwargs): cdata = self.cleaned_data section_lines = self.section_lines if not section_lines: index = 0 order = self.empty_section_order else: index = cdata['index'] if index < len(section_lines): order = section_lines[index].order else: order = section_lines[-1].order + 1 instance = self.instance instance.pform = self.pform instance.section = self.section instance.order = order instance.type = cdata['type'] instance.type_args = self.type_args for line in chain(section_lines[index:], self.next_lines): line.order += 1 line.save() return super().save(*args, **kwargs)
class SomewhatConfigurablePlugin(Plugin): fields = {"strength": IntegerField(min_value=0, max_value=100, initial=33)}
class UCForm(Form): video_url = CharField() period = IntegerField()
class DomainInternalForm(forms.Form, SubAreaMixin): sf_contract_id = CharField(label=ugettext_noop("Salesforce Contract ID"), required=False) sf_account_id = CharField(label=ugettext_noop("Salesforce Account ID"), required=False) commcare_edition = ChoiceField( label=ugettext_noop("CommCare Plan"), initial="community", required=False, choices=tuple([ (p, p) for p in ["community", "standard", "pro", "advanced", "enterprise"] ])) services = ChoiceField(label=ugettext_noop("Services"), required=False, choices=tuple_of_copies( ["basic", "plus", "full", "custom"])) initiative = forms.MultipleChoiceField( label=ugettext_noop("Initiative"), widget=forms.CheckboxSelectMultiple(), choices=tuple_of_copies(DATA_DICT["initiatives"], blank=False), required=False) workshop_region = CharField( label=ugettext_noop("Workshop Region"), required=False, help_text=ugettext_noop( "e.g. US, LAC, SA, Sub-Saharan Africa, Southeast Asia, etc.")) project_state = ChoiceField(label=ugettext_noop("Project State"), required=False, choices=tuple_of_copies( ["POC", "transition", "at-scale"])) self_started = ChoiceField(label=ugettext_noop("Self Started?"), choices=tf_choices('Yes', 'No'), required=False) area = ChoiceField(label=ugettext_noop("Sector"), required=False, choices=tuple_of_copies(AREA_CHOICES)) sub_area = ChoiceField(label=ugettext_noop("Sub-Sector"), required=False, choices=tuple_of_copies(SUB_AREA_CHOICES)) using_adm = ChoiceField(label=ugettext_noop("Using ADM?"), choices=tf_choices('Yes', 'No'), required=False) using_call_center = ChoiceField(label=ugettext_noop("Using Call Center?"), choices=tf_choices('Yes', 'No'), required=False) custom_eula = ChoiceField(label=ugettext_noop("Custom Eula?"), choices=tf_choices('Yes', 'No'), required=False) can_use_data = ChoiceField(label=ugettext_noop("Data Usage?"), choices=tf_choices('Yes', 'No'), required=False) organization_name = CharField(label=ugettext_noop("Organization Name"), required=False) notes = CharField(label=ugettext_noop("Notes"), required=False, widget=forms.Textarea) platform = forms.MultipleChoiceField(label=ugettext_noop("Platform"), widget=forms.CheckboxSelectMultiple(), choices=tuple_of_copies( ["java", "android", "cloudcare"], blank=False), required=False) phone_model = CharField(label=ugettext_noop("Phone Model"), required=False) project_manager = CharField(label=ugettext_noop("Project Manager's Email"), required=False) goal_time_period = IntegerField( label=ugettext_noop("Goal time period (in days)"), required=False) goal_followup_rate = DecimalField(label=ugettext_noop( "Goal followup rate (percentage in decimal format. e.g. 70% is .7)"), required=False) def save(self, domain): kw = { "workshop_region": self.cleaned_data["workshop_region"] } if self.cleaned_data["workshop_region"] else {} domain.update_internal( sf_contract_id=self.cleaned_data['sf_contract_id'], sf_account_id=self.cleaned_data['sf_account_id'], commcare_edition=self.cleaned_data['commcare_edition'], services=self.cleaned_data['services'], initiative=self.cleaned_data['initiative'], project_state=self.cleaned_data['project_state'], self_started=self.cleaned_data['self_started'] == 'true', area=self.cleaned_data['area'], sub_area=self.cleaned_data['sub_area'], using_adm=self.cleaned_data['using_adm'] == 'true', using_call_center=self.cleaned_data['using_call_center'] == 'true', custom_eula=self.cleaned_data['custom_eula'] == 'true', can_use_data=self.cleaned_data['can_use_data'] == 'true', organization_name=self.cleaned_data['organization_name'], notes=self.cleaned_data['notes'], platform=self.cleaned_data['platform'], project_manager=self.cleaned_data['project_manager'], phone_model=self.cleaned_data['phone_model'], goal_time_period=self.cleaned_data['goal_time_period'], goal_followup_rate=self.cleaned_data['goal_followup_rate'], **kw)
class CustomAuthenticationForm(AuthenticationForm): username = IntegerField()
class SettingsForm(Form): # General Settings use_default_sms_response = ChoiceField( required=False, label=ugettext_noop("Default SMS Response"), choices=ENABLED_DISABLED_CHOICES, ) default_sms_response = TrimmedCharField( required=False, label="", ) use_restricted_sms_times = ChoiceField( required=False, label=ugettext_noop("Send SMS on..."), choices=( (DISABLED, ugettext_noop("any day, at any time")), (ENABLED, ugettext_noop("only specific days and times")), ), ) restricted_sms_times_json = CharField( required=False, widget=forms.HiddenInput, ) sms_survey_date_format = ChoiceField( required=False, label=ugettext_lazy("SMS Survey Date Format"), choices=((df.human_readable_format, ugettext_lazy(df.human_readable_format)) for df in ALLOWED_SURVEY_DATE_FORMATS), ) # Chat Settings use_custom_case_username = ChoiceField( required=False, choices=DEFAULT_CUSTOM_CHOICES, ) custom_case_username = TrimmedCharField( required=False, label=ugettext_noop("Enter a Case Property"), ) use_custom_message_count_threshold = ChoiceField( required=False, choices=MESSAGE_COUNTER_CHOICES, ) custom_message_count_threshold = IntegerField( required=False, label=ugettext_noop("Enter a Number"), ) use_sms_conversation_times = ChoiceField( required=False, label=ugettext_noop("Delay Automated SMS"), choices=ENABLED_DISABLED_CHOICES, widget=SelectToggle(choices=ENABLED_DISABLED_CHOICES, attrs={"ko_value": "use_sms_conversation_times"}), ) sms_conversation_times_json = CharField( required=False, widget=forms.HiddenInput, ) sms_conversation_length = ChoiceField( required=False, label=ugettext_noop("Conversation Duration"), choices=SMS_CONVERSATION_LENGTH_CHOICES, ) survey_traffic_option = ChoiceField( required=False, label=ugettext_noop("Survey Traffic"), choices=( (SHOW_ALL, ugettext_noop("Show all survey traffic")), (SHOW_INVALID, ugettext_noop("Hide all survey traffic except " "invalid responses")), (HIDE_ALL, ugettext_noop("Hide all survey traffic")), ), ) count_messages_as_read_by_anyone = ChoiceField( required=False, label=ugettext_noop("A Message is Read..."), choices=( (ENABLED, ugettext_noop("when it is read by anyone")), (DISABLED, ugettext_noop("only for the user that reads it")), ), ) use_custom_chat_template = ChoiceField( required=False, choices=DEFAULT_CUSTOM_CHOICES, ) custom_chat_template = TrimmedCharField( required=False, label=ugettext_noop("Enter Chat Template Identifier"), ) # Registration settings sms_case_registration_enabled = ChoiceField( required=False, choices=ENABLED_DISABLED_CHOICES, label=ugettext_noop("Case Self-Registration"), ) sms_case_registration_type = TrimmedCharField( required=False, label=ugettext_noop("Default Case Type"), ) sms_case_registration_owner_id = CharField( required=False, label=ugettext_noop("Default Case Owner"), widget=forms.Select(choices=[]), ) sms_case_registration_user_id = CharField( required=False, label=ugettext_noop("Registration Submitter"), widget=forms.Select(choices=[]), ) sms_mobile_worker_registration_enabled = ChoiceField( required=False, choices=ENABLED_DISABLED_CHOICES, label=ugettext_noop("SMS Mobile Worker Registration"), ) registration_welcome_message = ChoiceField( choices=WELCOME_RECIPIENT_CHOICES, label=ugettext_lazy("Send registration welcome message to"), ) language_fallback = ChoiceField( choices=LANGUAGE_FALLBACK_CHOICES, label=ugettext_lazy("Backup behavior for missing translations"), ) twilio_whatsapp_phone_number = CharField(required=False, ) # Internal settings override_daily_outbound_sms_limit = ChoiceField( required=False, choices=ENABLED_DISABLED_CHOICES, label=ugettext_lazy("Override Daily Outbound SMS Limit"), ) custom_daily_outbound_sms_limit = IntegerField( required=False, label=ugettext_noop("Daily Outbound SMS Limit"), min_value=1000, ) @property def section_general(self): fields = [ hqcrispy.B3MultiField( _("Default SMS Response"), crispy.Div(InlineField( "use_default_sms_response", data_bind="value: use_default_sms_response", ), css_class='col-sm-4'), crispy.Div(InlineField( "default_sms_response", css_class="input-xxlarge", placeholder=_("Enter Default Response"), data_bind="visible: showDefaultSMSResponse", ), css_class='col-sm-8'), help_bubble_text=_( "Enable this option to provide a " "default response when a user's incoming SMS does not " "answer an open survey or match a known keyword."), css_id="default-sms-response-group", field_class='col-sm-6 col-md-9 col-lg-9'), hqcrispy.FieldWithHelpBubble( "use_restricted_sms_times", data_bind="value: use_restricted_sms_times", help_bubble_text=_( "Use this option to limit the times " "that SMS messages can be sent to users. Messages that " "are sent outside these windows will remained queued " "and will go out as soon as another window opens up."), ), hqcrispy.B3MultiField( "", hqcrispy.HiddenFieldWithErrors( "restricted_sms_times_json", data_bind="value: restricted_sms_times_json"), crispy.Div(data_bind="template: {" " name: 'ko-template-restricted-sms-times', " " data: $data" "}", ), data_bind="visible: showRestrictedSMSTimes", ), hqcrispy.FieldWithHelpBubble( 'sms_survey_date_format', help_bubble_text=_("Choose the format in which date questions " "should be answered in SMS surveys."), ), ] return crispy.Fieldset(_("General Settings"), *fields) @property def section_registration(self): fields = [ hqcrispy.FieldWithHelpBubble( "sms_case_registration_enabled", help_bubble_text=_( "When this option is enabled, a person " "can send an SMS into the system saying 'join " "[project]', where [project] is your project " "space name, and the system will automatically " "create a case tied to that person's phone number."), data_bind="value: sms_case_registration_enabled", ), crispy.Div( hqcrispy.FieldWithHelpBubble( "sms_case_registration_type", placeholder=_("Enter a Case Type"), help_bubble_text=_("Cases that self-register over SMS " "will be given this case type."), ), hqcrispy.FieldWithHelpBubble( "sms_case_registration_owner_id", help_bubble_text=_( "Cases that self-register over SMS " "will be owned by this user or user group."), ), hqcrispy.FieldWithHelpBubble( "sms_case_registration_user_id", help_bubble_text=_( "The form submission for a " "self-registration will belong to this user."), ), data_bind="visible: showRegistrationOptions", ), hqcrispy.FieldWithHelpBubble( "sms_mobile_worker_registration_enabled", help_bubble_text=_( "When this option is enabled, a person " "can send an SMS into the system saying 'join " "[project] worker [username]' (where [project] is your " " project space and [username] is an optional username)" ", and the system will add them as a mobile worker."), ), hqcrispy.FieldWithHelpBubble( 'registration_welcome_message', help_bubble_text=_( "Choose whether to send an automatic " "welcome message to cases, mobile workers, or both, " "after they self-register. The welcome message can be " "configured in the SMS languages and translations page " "(Messaging -> Languages -> Messaging Translations)."), ), hqcrispy.FieldWithHelpBubble( 'language_fallback', help_bubble_text=_(""" Choose what should happen when a broadcast or alert should be sent to a recipient but no translations exists in the user's preferred language. You may choose not to send a message in that case, or to try one of several backups.<br><br>The first backup uses the broadcast or alert's default language. If that translation is also unavailable, the second backup is text in the project's default SMS language. If that translation is also unavailable, you may choose to use untranslated text, if there is any. """), ), ] if toggles.WHATSAPP_MESSAGING.enabled(self.domain): fields.append( hqcrispy.FieldWithHelpBubble( 'twilio_whatsapp_phone_number', help_bubble_text=_(""" Whatsapp-enabled phone number for use with Twilio. This should be formatted as a full-length, numeric-only phone number, e.g., 16173481000. """), )) return crispy.Fieldset(_("Registration Settings"), *fields) @property def section_chat(self): fields = [ hqcrispy.B3MultiField( _("Case Name Display"), crispy.Div(InlineField( "use_custom_case_username", data_bind="value: use_custom_case_username", ), css_class='col-sm-4'), crispy.Div(InlineField( "custom_case_username", css_class="input-large", data_bind="visible: showCustomCaseUsername", ), css_class='col-sm-8'), help_bubble_text=_( "By default, when chatting with a case, " "the chat window will use the case's \"name\" case " "property when displaying the case's name. To use a " "different case property, specify it here."), css_id="custom-case-username-group", field_class='col-sm-6 col-md-9 col-lg-9'), hqcrispy.B3MultiField( _("Message Counter"), crispy.Div(InlineField( "use_custom_message_count_threshold", data_bind="value: use_custom_message_count_threshold", ), css_class='col-sm-4'), crispy.Div(InlineField( "custom_message_count_threshold", css_class="input-large", data_bind="visible: showCustomMessageCountThreshold", ), css_class='col-sm-8'), help_bubble_text=_( "The chat window can use a counter to keep " "track of how many messages are being sent and received " "and highlight that number after a certain threshold is " "reached. By default, the counter is disabled. To enable " "it, enter the desired threshold here."), css_id="custom-message-count-threshold-group", field_class='col-sm-6 col-md-9 col-lg-9'), hqcrispy.FieldWithHelpBubble( "use_sms_conversation_times", help_bubble_text=_( "When this option is enabled, the system " "will not send automated SMS to chat recipients when " "those recipients are in the middle of a conversation."), ), hqcrispy.B3MultiField( "", hqcrispy.HiddenFieldWithErrors( "sms_conversation_times_json", data_bind="value: sms_conversation_times_json"), crispy.Div(data_bind="template: {" " name: 'ko-template-sms-conversation-times', " " data: $data" "}", ), data_bind="visible: showSMSConversationTimes", label_class='hide', field_class='col-md-12 col-lg-10'), crispy.Div( hqcrispy.FieldWithHelpBubble( "sms_conversation_length", help_bubble_text=_( "The number of minutes to wait " "after receiving an incoming SMS from a chat " "recipient before resuming automated SMS to that " "recipient."), ), data_bind="visible: showSMSConversationTimes", ), hqcrispy.FieldWithHelpBubble( "survey_traffic_option", help_bubble_text=_( "This option allows you to hide a chat " "recipient's survey questions and responses from chat " "windows. There is also the option to show only invalid " "responses to questions in the chat window, which could " "be attempts to converse."), ), hqcrispy.FieldWithHelpBubble( "count_messages_as_read_by_anyone", help_bubble_text=_( "The chat window will mark unread " "messages to the user viewing them. Use this option to " "control whether a message counts as being read if it " "is read by anyone, or if it counts as being read only " "to the user who reads it."), ), ] return crispy.Fieldset(_("Chat Settings"), *fields) @property def section_internal(self): return crispy.Fieldset( _("Internal Settings (Dimagi Only)"), hqcrispy.B3MultiField( _("Override Daily Outbound SMS Limit"), crispy.Div(InlineField( 'override_daily_outbound_sms_limit', data_bind='value: override_daily_outbound_sms_limit', ), css_class='col-sm-4'), crispy.Div( InlineField('custom_daily_outbound_sms_limit'), data_bind= "visible: override_daily_outbound_sms_limit() === '%s'" % ENABLED, css_class='col-sm-8'), ), hqcrispy.B3MultiField( _("Chat Template"), crispy.Div(InlineField( "use_custom_chat_template", data_bind="value: use_custom_chat_template", ), css_class='col-sm-4'), crispy.Div(InlineField( "custom_chat_template", data_bind="visible: showCustomChatTemplate", ), css_class='col-sm-8'), help_bubble_text=_("To use a custom template to render the " "chat window, enter it here."), css_id="custom-chat-template-group", ), ) @property def sections(self): result = [ self.section_general, self.section_registration, self.section_chat, ] if self.is_previewer: result.append(self.section_internal) result.append( hqcrispy.FormActions( twbscrispy.StrictButton( _("Save"), type="submit", css_class="btn-primary", ), ), ) return result def __init__(self, data=None, domain=None, is_previewer=False, *args, **kwargs): self.domain = domain self.is_previewer = is_previewer super(SettingsForm, self).__init__(data, *args, **kwargs) self.helper = HQFormHelper() self.helper.layout = crispy.Layout(*self.sections) self.restricted_sms_times_widget_context = { "template_name": "ko-template-restricted-sms-times", "explanation_text": _("SMS will only be sent when any of the following is true:"), "ko_array_name": "restricted_sms_times", "remove_window_method": "$parent.removeRestrictedSMSTime", "add_window_method": "addRestrictedSMSTime", } self.sms_conversation_times_widget_context = { "template_name": "ko-template-sms-conversation-times", "explanation_text": _("Automated SMS will be suppressed during " "chat conversations when any of the following " "is true:"), "ko_array_name": "sms_conversation_times", "remove_window_method": "$parent.removeSMSConversationTime", "add_window_method": "addSMSConversationTime", } @property def enable_registration_welcome_sms_for_case(self): return (self.cleaned_data.get('registration_welcome_message') in (WELCOME_RECIPIENT_CASE, WELCOME_RECIPIENT_ALL)) @property def enable_registration_welcome_sms_for_mobile_worker(self): return (self.cleaned_data.get('registration_welcome_message') in (WELCOME_RECIPIENT_MOBILE_WORKER, WELCOME_RECIPIENT_ALL)) @property def current_values(self): current_values = {} for field_name in self.fields.keys(): value = self[field_name].value() if field_name in [ "restricted_sms_times_json", "sms_conversation_times_json" ]: if isinstance(value, str): current_values[field_name] = json.loads(value) else: current_values[field_name] = value elif field_name in [ 'sms_case_registration_owner_id', 'sms_case_registration_user_id' ]: if value: obj = self.get_user_group_or_location(value) if isinstance(obj, SQLLocation): current_values[field_name] = { 'id': value, 'text': _("Organization: {}").format(obj.name) } elif isinstance(obj, Group): current_values[field_name] = { 'id': value, 'text': _("User Group: {}").format(obj.name) } elif isinstance(obj, CommCareUser): current_values[field_name] = { 'id': value, 'text': _("User: {}").format(obj.raw_username) } else: current_values[field_name] = value return current_values def _clean_dependent_field(self, bool_field, field): if self.cleaned_data.get(bool_field): value = self.cleaned_data.get(field, None) if not value: raise ValidationError(_("This field is required.")) return value else: return None def clean_use_default_sms_response(self): return self.cleaned_data.get("use_default_sms_response") == ENABLED def clean_default_sms_response(self): return self._clean_dependent_field("use_default_sms_response", "default_sms_response") def clean_use_custom_case_username(self): return self.cleaned_data.get("use_custom_case_username") == CUSTOM def clean_custom_case_username(self): return self._clean_dependent_field("use_custom_case_username", "custom_case_username") def clean_use_custom_message_count_threshold(self): return (self.cleaned_data.get("use_custom_message_count_threshold") == CUSTOM) def clean_custom_message_count_threshold(self): value = self._clean_dependent_field( "use_custom_message_count_threshold", "custom_message_count_threshold") if value is not None and value <= 0: raise ValidationError(_("Please enter a positive number")) return value def clean_use_custom_chat_template(self): if not self.is_previewer: return None return self.cleaned_data.get("use_custom_chat_template") == CUSTOM def clean_custom_chat_template(self): if not self.is_previewer: return None value = self._clean_dependent_field("use_custom_chat_template", "custom_chat_template") if value is not None and value not in settings.CUSTOM_CHAT_TEMPLATES: raise ValidationError(_("Unknown custom template identifier.")) return value def _clean_time_window_json(self, field_name): try: time_window_json = json.loads(self.cleaned_data.get(field_name)) except ValueError: raise ValidationError( _("An error has occurred. Please try again, " "and if the problem persists, please report an issue.")) result = [] for window in time_window_json: day = window.get("day") start_time = window.get("start_time") end_time = window.get("end_time") time_input_relationship = window.get("time_input_relationship") try: day = int(day) assert day >= -1 and day <= 6 except (ValueError, AssertionError): raise ValidationError(_("Invalid day chosen.")) if time_input_relationship == TIME_BEFORE: end_time = validate_time(end_time) result.append( DayTimeWindow( day=day, start_time=None, end_time=end_time, )) elif time_input_relationship == TIME_AFTER: start_time = validate_time(start_time) result.append( DayTimeWindow( day=day, start_time=start_time, end_time=None, )) else: start_time = validate_time(start_time) end_time = validate_time(end_time) if start_time >= end_time: raise ValidationError( _("End time must come after start " "time.")) result.append( DayTimeWindow( day=day, start_time=start_time, end_time=end_time, )) return result def clean_use_restricted_sms_times(self): return self.cleaned_data.get("use_restricted_sms_times") == ENABLED def clean_restricted_sms_times_json(self): if self.cleaned_data.get("use_restricted_sms_times"): return self._clean_time_window_json("restricted_sms_times_json") else: return [] def clean_use_sms_conversation_times(self): return self.cleaned_data.get("use_sms_conversation_times") == ENABLED def clean_sms_conversation_times_json(self): if self.cleaned_data.get("use_sms_conversation_times"): return self._clean_time_window_json("sms_conversation_times_json") else: return [] def clean_count_messages_as_read_by_anyone(self): return (self.cleaned_data.get("count_messages_as_read_by_anyone") == ENABLED) def clean_sms_case_registration_enabled(self): return ( self.cleaned_data.get("sms_case_registration_enabled") == ENABLED) def clean_sms_case_registration_type(self): return self._clean_dependent_field("sms_case_registration_enabled", "sms_case_registration_type") def get_user_group_or_location(self, object_id): try: return SQLLocation.active_objects.get( domain=self.domain, location_id=object_id, location_type__shares_cases=True, ) except SQLLocation.DoesNotExist: pass try: group = Group.get(object_id) if group.doc_type == 'Group' and group.domain == self.domain and group.case_sharing: return group elif group.is_deleted: return None except ResourceNotFound: pass return self.get_user(object_id) def get_user(self, object_id): try: user = CommCareUser.get(object_id) if user.doc_type == 'CommCareUser' and user.domain == self.domain: return user except ResourceNotFound: pass return None def clean_sms_case_registration_owner_id(self): if not self.cleaned_data.get("sms_case_registration_enabled"): return None value = self.cleaned_data.get("sms_case_registration_owner_id") if not value: raise ValidationError(_("This field is required.")) obj = self.get_user_group_or_location(value) if not isinstance(obj, (CommCareUser, Group, SQLLocation)): raise ValidationError(_("Please select again")) return value def clean_sms_case_registration_user_id(self): if not self.cleaned_data.get("sms_case_registration_enabled"): return None value = self.cleaned_data.get("sms_case_registration_user_id") if not value: raise ValidationError(_("This field is required.")) obj = self.get_user(value) if not isinstance(obj, CommCareUser): raise ValidationError(_("Please select again")) return value def clean_sms_mobile_worker_registration_enabled(self): return (self.cleaned_data.get("sms_mobile_worker_registration_enabled") == ENABLED) def clean_sms_conversation_length(self): # Just cast to int, the ChoiceField will validate that it is an integer return int(self.cleaned_data.get("sms_conversation_length")) def clean_custom_daily_outbound_sms_limit(self): if not self.is_previewer: return None if self.cleaned_data.get( 'override_daily_outbound_sms_limit') != ENABLED: return None value = self.cleaned_data.get("custom_daily_outbound_sms_limit") if not value: raise ValidationError(_("This field is required")) return value
class AssetCreateForm(forms.ModelForm): class Meta: model = EAsset fields = ( "product_ass_id", "model_name", "purchase_date", "serial_number", ) product_ass_id = forms.ModelChoiceField(EProduct.objects, label='品名', to_field_name='product_id', initial=0) purchase_date = forms.DateField( label='購入日', widget=forms.DateInput(attrs={'type': 'date'})) # field_order = ["product_ass_id","model_name","purchase_date","serial_number"] asset_id = IntegerField(initial=0) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['asset_id'].widget = forms.HiddenInput() self.fields['asset_id'].required = False #self.fields['asset_id'] = forms.CharField(label='資産番号', initial="", ) #self.fields['product_ass_id'].widget.attrs['maxlength'] = '100' self.fields['product_ass_id'].required = True #品名inita=0追加 #self.fields['product_ass_id']. self.fields['product_ass_id'].error_messages = { 'required': '品名を選択してください。', 'maxlength': '50桁以内を入力してください。' } self.fields['model_name'].widget.attrs['maxlength'] = '50' self.fields['model_name'].required = True #self.fields['model_name'].widget.attrs['placeholder'] = 'HP' self.fields['model_name'].error_messages = { 'required': 'モデル名を入力してください。', 'maxlength': '100桁以内を入力してください。' } self.fields['purchase_date'].required = True self.fields['purchase_date'].error_messages = { 'required': '購入日を選択してください。', } self.fields['serial_number'].widget.attrs['maxlength'] = '100' self.fields['serial_number'].required = True self.fields['serial_number'].error_messages = { 'required': '識別番号を入力してください。', 'maxlength': '100桁以内を入力してください。' } for field in self.fields.values(): if field.required: field.error_messages = { 'required': '「' + str(field.label) + '」を入力してください。' } def clean_model_name(self): model_name = self.data.get('model_name') if len(model_name) > 50: raise forms.ValidationError("50桁以内を入力してください。") return self.cleaned_data["model_name"] def clean_product_ass_id(self): product_ass_id = self.data.get('product_ass_id') print("これは品名" + product_ass_id) return product_ass_id # def clean_purchase_date(self): # purchase_date = self.data.get('purchase_date') # asset_id = self.data.get('asset_id') # return self.cleaned_data["purchase_date"] def clean_serial_number(self): serial_number = self.data.get('serial_number') print("これは" + serial_number) asset_id = self.data.get('asset_id') if len(serial_number) > 100: raise forms.ValidationError("100桁以内を入力してください。") if serial_number and EAsset.objects.filter( serial_number=serial_number).exclude( asset_id=asset_id).count(): raise forms.ValidationError("識別番号が既に存在しました。") return self.cleaned_data["serial_number"]
class TabForm(ManageChildrenFormMixin, ModelForm): num_children = IntegerField(min_value=1, initial=1, widget=NumberInputWidget(attrs={'size': '3', 'style': 'width: 5em !important;'}), label=_("Tabs"), help_text=_("Number of tabs."))
class TournamentForm(ModelForm): class Meta: model = Tournament fields = ('name', 'short_name', 'slug') num_prelim_rounds = IntegerField(min_value=1, label=_("Number of preliminary rounds")) break_size = IntegerField( min_value=2, required=False, label=_("Number of teams in the open break"), help_text=_("Leave blank if there are no break rounds.")) def add_default_feedback_questions(self, tournament): agree = AdjudicatorFeedbackQuestion( tournament=tournament, seq=2, required=True, text="Did you agree with their decision?", name="Agree?", reference="agree", from_adj=True, from_team=True, answer_type=AdjudicatorFeedbackQuestion.ANSWER_TYPE_BOOLEAN_SELECT) agree.save() comments = AdjudicatorFeedbackQuestion( tournament=tournament, seq=3, required=False, text="Any further comments?", name="Comments?", reference="comments", from_adj=True, from_team=True, answer_type=AdjudicatorFeedbackQuestion.ANSWER_TYPE_LONGTEXT) comments.save() def save(self): tournament = super(TournamentForm, self).save() auto_make_rounds(tournament, self.cleaned_data["num_prelim_rounds"]) break_size = self.cleaned_data["break_size"] if break_size: open_break = BreakCategory( tournament=tournament, # Translators: This is the name given to the 'Open Break'. name=_("Open"), slug="open", seq=1, break_size=break_size, is_general=True, priority=100) open_break.full_clean() open_break.save() num_break_rounds = math.ceil(math.log2(break_size)) auto_make_break_rounds(tournament, num_break_rounds, open_break) self.add_default_feedback_questions(tournament) tournament.current_round = tournament.round_set.first() tournament.save() return tournament
def __init__(self, *args, **kwargs): self.base_fields['CONTENT_TYPE'] = IntegerField(widget=HiddenInput) self.base_fields['OBJECT_ID'] = IntegerField(widget=HiddenInput, required=False) super().__init__(*args, **kwargs)
class AccordionForm(ManageChildrenFormMixin, ModelForm): num_children = IntegerField(min_value=1, initial=1, widget=NumberInputWidget(attrs={'size': '3', 'style': 'width: 5em !important;'}), label=_("Panels"), help_text=_("Number of panels for this panel group."))
def __init__(self, path, user, *args, **kwargs): super(DynForm, self).__init__(*args, **kwargs) pathComplete = str(path) elements = pathComplete.split("/") studyName = elements[2] stageName = elements[3] for study in Study.objects.filter(studyName=str(studyName)): tempEntity = [] for entity in Patient.objects.filter( studyId__idStudy=study.idStudy, userOwner=user): tempLabel = str(entity).split(" ") patientLabel = tempLabel[0] + ". ID: " + tempLabel[1] tempEntity.append((patientLabel, patientLabel)) choiceEnt = tuple(tempEntity) self.fields['Paciente'] = ChoiceField( tempEntity, initial=tempEntity[len(tempEntity) - 1]) self.fields['Paciente'].widget.attrs['class'] = 'form-control' for stage in Stage.objects.filter(studyId=study.idStudy): if stage.stageType == str(stageName): questionList = [] for questionGroups in Question_Groups.objects.filter( groupStage__idStage=stage.idStage).order_by( 'order'): for question in questionGroups.idQuestions.all(): questionList.append(question) for question in questionList: if question.questionsType == 'Char': self.fields['%s' % question] = CharField( max_length=255, required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control' if question.questionsType == 'Int': self.fields['%s' % question] = IntegerField( widget=forms.NumberInput(), required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control' self.fields['%s' % question].widget.attrs[ 'min'] = question.questionMin self.fields['%s' % question].widget.attrs[ 'max'] = question.questionMax self.fields['%s' % question].widget.attrs['step'] = 1 if question.questionsType == 'Real': self.fields['%s' % question] = FloatField( widget=forms.NumberInput(), required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control' self.fields['%s' % question].widget.attrs[ 'min'] = question.questionMin self.fields['%s' % question].widget.attrs[ 'max'] = question.questionMax self.fields[ '%s' % question].widget.attrs['step'] = 0.1 if question.questionsType == 'Date': self.fields['%s' % question] = DateField( widget=forms.DateInput(), required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control' if question.questionsType == 'Time': self.fields['%s' % question] = TimeField( widget=forms.TimeInput(), required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control' if question.questionsType == 'Bool': self.fields[ '%s' % question] = NullBooleanField( widget=forms.NullBooleanSelect(), required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs.update({ 'onclick': "toggle_id_%s()" % question, }) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control' if question.questionsType == 'Img': self.fields['%s' % question] = FileField( required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control' if question.questionsType == 'Enum': choices = Choices.objects.filter( questionId__questionsId=question. questionsId) list_of_choices = [] for choice in choices: list_of_choices.append((choice, choice)) tuple_of_choices = tuple(list_of_choices) self.fields['%s' % question] = ChoiceField( widget=forms.Select(), choices=tuple_of_choices, required=False) self.fields['%s' % question].label = str( question.questionsLabel) self.fields['%s' % question].help_text = str( question.questionHelp) self.fields['%s' % question].widget.attrs.update({ 'onchange': "toggle_id_%s()" % question, }) self.fields['%s' % question].widget.attrs[ 'class'] = 'form-control'
class MetaInlineForm(modelforms.ModelForm): _export_stack = dict() position_id = HiddenIntegerField(required=False) position_from = DateTimeField(label=_('Visible From'), widget=widgets.DateTimeWidget) position_to = DateTimeField(label=_('Visible To'), widget=widgets.DateTimeWidget, required=False) position = IntegerField(required=False) export = fields.AdminSuggestField( models.ExportPosition._meta.get_field('export'), required=True, label=_('Export'), model=models.Export, lookup=( 'title', 'slug', ), ) # override base_fields and include all the other declared fields declared_fields = SortedDict( (('title', HiddenIntegerField(label=u'', required=False)), ('position_id', HiddenIntegerField(label=u'', required=False)), ('position_from', DateTimeField(label=_('Visible From'), widget=widgets.DateTimeWidget)), ('position_to', DateTimeField(label=_('Visible To'), widget=widgets.DateTimeWidget, required=False)), ('position', IntegerField(required=False)), ('export', fields.AdminSuggestField( models.ExportPosition._meta.get_field('export'), required=True, label=_('Export'), model=models.Export, lookup=( 'title', 'slug', ), )))) def __init__(self, *args, **kwargs): super(MetaInlineForm, self).__init__(*args, **kwargs) self.show_edit_url = False # shows edit button if set to True core_signals.request_finished.connect( receiver=MetaInlineForm.reset_export_enumerator) existing_object = False new_object = False id_initial = None from_initial = to_initial = '' export_initial = None position_initial = None #export_qs = models.Export.objects.all() if 'instance' in kwargs and 'data' not in kwargs: existing_object = True instance = kwargs['instance'] if instance: initial = self.get_initial_data(instance) id_initial = initial['pk'] from_initial = initial['visible_from'] to_initial = initial['visible_to'] export_initial = initial['export_pk'] position_initial = initial['position'] elif 'data' not in kwargs: new_object = True self.assign_init_field( 'position_id', HiddenIntegerField(initial=id_initial, label=u'', required=False)) self.assign_init_field( 'position_from', DateTimeField(initial=from_initial, label=_('Visible From'), widget=widgets.DateTimeWidget)) self.assign_init_field( 'position_to', DateTimeField(initial=to_initial, label=_('Visible To'), widget=widgets.DateTimeWidget, required=False)) self.assign_init_field( 'position', IntegerField(initial=position_initial, label=_('Position'), required=False)) export_field = fields.AdminSuggestField( models.ExportPosition._meta.get_field('export'), required=True, label=_('Export'), model=models.Export, lookup=( 'title', 'slug', ), initial=export_initial) #modelforms.ModelChoiceField(export_qs, initial=export_initial, label=_('Export'), show_hidden_initial=True) self.assign_init_field('export', export_field) def assign_init_field(self, field_name, value): self.fields[field_name] = self.base_fields[field_name] = value def get_initial_data(self, instance): " @return dict (visible_from, visible_to, export_initial, position) " positions = models.ExportPosition.objects.filter(object=instance) out = { 'pk': '', 'visible_from': '', 'visible_to': None, 'export_pk': None, 'position': '' } if not positions: return out pcount = positions.count() if pcount > 1 and not MetaInlineForm._export_stack.get( instance, False): MetaInlineForm._export_stack[instance] = list() map(lambda p: MetaInlineForm._export_stack[instance].insert(0, p), positions) if pcount == 1: pos = positions[0] elif pcount > 1: pos = MetaInlineForm._export_stack[instance].pop() out.update({ 'pk': pos.pk, 'visible_from': pos.visible_from, 'visible_to': pos.visible_to, 'export_pk': pos.export.pk, 'position': pos.position }) return out @staticmethod def reset_export_enumerator(*args, **kwargs): " Clears _export_stack at the end of HTTP request. " core_signals.request_finished.disconnect( receiver=MetaInlineForm.reset_export_enumerator) MetaInlineForm._export_stack.clear() def get_date_field_key(self, field): return '%s-%s' % (self.prefix, field) def clean(self): """ if not self.is_valid() or not self.cleaned_data or not self.instance: return self.cleaned_data """ self.cleaned_data['position_id'] = self.data[self.get_date_field_key( 'position_id')] self.cleaned_data['position_from'] = self.data[self.get_date_field_key( 'position_from')] self.cleaned_data['position'] = self.data[self.get_date_field_key( 'position')] data_position_to = self.data[self.get_date_field_key('position_to')] if data_position_to: self.cleaned_data['position_to'] = data_position_to self.cleaned_data['export'] = self.data[self.get_date_field_key( 'export')] return self.cleaned_data def save(self, commit=True): out = super(MetaInlineForm, self).save(commit=commit) def save_them(): export = models.Export.objects.get( pk=int(self.cleaned_data['export'])) positions = models.ExportPosition.objects.filter( object=self.instance, export=export) if not self.cleaned_data['position_id']: position = models.ExportPosition(object=self.instance, ) else: pos_id = int(self.cleaned_data['position_id']) position = models.ExportPosition.objects.get(pk=pos_id) position.export = export position.visible_from = self.cleaned_data['position_from'] position.visible_to = self.cleaned_data['position_to'] if self.cleaned_data['position'].isdigit(): position.position = int(self.cleaned_data['position']) position.save() if commit: save_them() else: save_m2m = getattr(self, 'save_m2m', None) def save_all(): if save_m2m: save_m2m() save_them() self.save_m2m = save_all return out
class BillItemForm(ModelForm): count = IntegerField(min_value=1, max_value=100) class Meta: model = BillItem fields = ['count']
class CarouselSlidesForm(ManageChildrenFormMixin, ModelForm): num_children = IntegerField(min_value=1, initial=1, widget=NumberInputWidget(attrs={'size': '3', 'style': 'width: 5em !important;'}), label=_('Slides'), help_text=_('Number of slides for this carousel.'), )
class NewForm(forms.Form): task=CharField(label="New Task ") priority=IntegerField(label="Priority :",min_value=2,max_value=5)
class ProcessBarForm(ManageChildrenFormMixin, ModelForm): num_children = IntegerField(min_value=1, initial=1, widget=NumberInputWidget(attrs={'size': '3', 'style': 'width: 5em;'}), label=_("Steps"), help_text=_("Number of steps for this proceed bar."))
def __init__(self, action, *args, **kwargs): # build the forms from the action attributes try: self.action_item = Action.objects.get(name=action) except ObjectDoesNotExist: self.action_item = Action(name=action, ) attributes = self.action_item.attributes.all() from django.forms.models import fields_for_model model_fields = fields_for_model(Translation) model_fields = {} #for field in model_fields_list: # print(field) # model_fields[ field ] = model_fields_list[field] #for attr in attributes: # if attr.datatype in model_fields: # self.Meta.fields.append(attr.datatype) #if self.action_item.target_type: # if not 'target' in self.Meta.fields: # self.Meta.fields.append('target') super(BaseActionForm, self).__init__(*args, **kwargs) # build fields from attributes attributes = self.action_item.attributes.all() for attr in attributes: if attr.datatype == 'target': qs = Item.objects.filter(id__in=list( get_targets(self.instance, self.action_item.target_type))) att_field = TargetModelChoiceField(queryset=qs, ) elif attr.datatype == 'query': qs = Item.objects.filter(id__in=list( get_targets(self.instance, self.action_item.target_type))) att_field = TargetQueryField(queryset=qs, initial=None) elif attr.datatype == 'string': att_field = CharField(max_length=1024) elif attr.datatype == 'markdown': att_field = CharField(max_length=25600, widget=Textarea) elif attr.datatype == 'description': att_field = CharField(max_length=25600000, widget=Textarea) elif attr.datatype == 'boolean': att_field = BooleanField() elif attr.datatype == 'integer': att_field = IntegerField() elif attr.datatype == 'number': att_field = FloatField() elif attr.datatype == 'email': att_field = EmailField() elif attr.datatype == 'slug': att_field = SlugField() elif attr.datatype == 'url': att_field = URLField() #elif attr.datatype in model_fields: # att_field = model_fields[ attr.datatype ] elif attr.datatype == 'image': att_field = MediaUploadField() else: #continue att_field = CharField(max_length=1024) att_field.initial = attr.default att_field.required = attr.required att_field.label = attr.label att_field.help_text = attr.help self.fields[attr.name] = att_field if attr.hidden: self.fields[attr.name].widget = forms.HiddenInput() if attr.regexp: validator = RegexValidator(attr.regexp, message=attr.regexp_error) if not att_field.validators: att_field.validators = [] att_field.validators.append(validator) self.set_form_control_class()
def formfield(self, initial): return IntegerField(min_value=0, max_value=23, initial=initial)
def _formfield(self, initial): get_arg = self._args.get return IntegerField(min_value=get_arg('lower_bound'), max_value=get_arg('upper_bound'), initial=initial, )
def __init__(self, *args, **kwargs): self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput) self.base_fields[INITIAL_FORM_COUNT] = IntegerField(widget=HiddenInput) self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(required=False, widget=HiddenInput) super(ManagementForm, self).__init__(*args, **kwargs)
class EntryForm(BaseForm): id = IntegerField(required=False, widget=HiddenInput) key = CharField(required=False, widget=HiddenInput) value = value_field def save_m2m(self): pass
class UtterlyConfigurablePluginWithExceptionallyImportantFieldOrder(Plugin): fields = [ ("one", IntegerField()), ("two", IntegerField()), ("three", IntegerField()), ]
class TeslaReturnFilterForm(Form): purchase_date = DateField(required=True) purchase_quantity = IntegerField(required=True, min_value=1) start_date = DateField(required=False) end_date = DateField(required=False) max_return = None min_return = None def clean(self): cleaned_data = super(TeslaReturnFilterForm, self).clean() start_date = cleaned_data.get('start_date') end_date = cleaned_data.get('end_date') purchase_date = cleaned_data.get('purchase_date') todays_date = date_today() if purchase_date <= TSLA_START_DATE: raise ValidationError('Purchase date cannot be before %s.' % date_us_short_fmt(TSLA_START_DATE)) if start_date and start_date <= TSLA_START_DATE: raise ValidationError('Start date cannot be before %s.' % date_us_short_fmt(TSLA_START_DATE)) if end_date and end_date > todays_date: raise ValidationError('End date cannot be in the future.') if start_date and start_date > todays_date: raise ValidationError('Start date cannot be in the future.') if start_date and end_date and end_date < start_date: raise ValidationError('Start date must be before end date.') if purchase_date >= todays_date: raise ValidationError('Purchase date must be before today.') if start_date and purchase_date > start_date: raise ValidationError('Start date must be after purchase date.') if end_date and purchase_date >= end_date: raise ValidationError('End date must be after purchase date.') return cleaned_data def filter(self): # Defaults start_date = date_weeks_ago(DEFAULT_WEEKS_DELTA) end_date = date_today() purchase_date = start_date purchase_quantity = DEFAULT_PURCHASE_QUANTITY if self.is_valid(): purchase_date = self.cleaned_data['purchase_date'] purchase_quantity = self.cleaned_data['purchase_quantity'] # Both start and end date inputs provided if self.cleaned_data['start_date'] and self.cleaned_data[ 'end_date']: start_date = self.cleaned_data['start_date'] end_date = self.cleaned_data['end_date'] # Only start date input provided elif self.cleaned_data[ 'start_date'] and not self.cleaned_data['end_date']: start_date = self.cleaned_data['start_date'] end_date = min( date_weeks_from_now(DEFAULT_WEEKS_DELTA, date_in=start_date), date_today()) # Only end date input provided elif self.cleaned_data[ 'end_date'] and not self.cleaned_data['start_date']: end_date = self.cleaned_data['end_date'] start_date = max( date_weeks_ago(DEFAULT_WEEKS_DELTA, date_in=end_date), purchase_date) # Convert dates to yahoo finance strings start_date_str = date_yahoo_finance_fmt(start_date) end_date_str = date_yahoo_finance_fmt(end_date) purchase_date_str = date_yahoo_finance_fmt(purchase_date) # Pull down data from API tsla = Share(TSLA_SYMBOL) purchase_data = tsla.get_historical(purchase_date_str, purchase_date_str) historical_data = tsla.get_historical(start_date_str, end_date_str) # Reverse historical data so that it is ordered by date ascending historical_data = historical_data[::-1] purchase_close = Decimal(purchase_data[0]['Close']) returns_data = list() # Extract required historical data for data in historical_data: # Calculate return for given day day_return = (Decimal(data['Close']) - purchase_close) * purchase_quantity day_data = (day_return, data['Date']) returns_data.append(day_data) # Set max return if not self.max_return or day_data[0] > self.max_return[0]: self.max_return = day_data # Set min return if not self.min_return or day_data[0] < self.min_return[0]: self.min_return = day_data return returns_data def get_purchase_params(self): assert self.is_valid(), 'Form must be valid to get purchase params' return { 'purchase_date': self.cleaned_data['purchase_date'], 'purchase_quantity': self.cleaned_data['purchase_quantity'] }