1use crate::Widget;
4use crate::field::{FieldError, FieldResult, FormField};
5use crate::model_form::FormModel;
6use serde_json::Value;
7use std::collections::HashMap;
8use std::marker::PhantomData;
9
10pub struct ModelChoiceField<T: FormModel> {
14 pub name: String,
15 pub required: bool,
16 pub error_messages: HashMap<String, String>,
17 pub widget: Widget,
18 pub help_text: String,
19 pub initial: Option<Value>,
20 pub queryset: Vec<T>,
21 pub empty_label: Option<String>,
22 _phantom: PhantomData<T>,
23}
24
25impl<T: FormModel> ModelChoiceField<T> {
26 pub fn new(name: impl Into<String>, queryset: Vec<T>) -> Self {
76 let mut error_messages = HashMap::new();
77 error_messages.insert(
78 "required".to_string(),
79 "This field is required.".to_string(),
80 );
81 error_messages.insert(
82 "invalid_choice".to_string(),
83 "Select a valid choice.".to_string(),
84 );
85
86 Self {
87 name: name.into(),
88 required: true,
89 error_messages,
90 widget: Widget::Select {
91 choices: Vec::new(),
92 },
93 help_text: String::new(),
94 initial: None,
95 queryset,
96 empty_label: Some("--------".to_string()),
97 _phantom: PhantomData,
98 }
99 }
100 pub fn required(mut self, required: bool) -> Self {
101 self.required = required;
102 self
103 }
104 pub fn help_text(mut self, text: impl Into<String>) -> Self {
105 self.help_text = text.into();
106 self
107 }
108 pub fn initial(mut self, value: Value) -> Self {
109 self.initial = Some(value);
110 self
111 }
112 pub fn empty_label(mut self, label: Option<String>) -> Self {
113 self.empty_label = label;
114 self
115 }
116 pub fn error_message(
117 mut self,
118 error_type: impl Into<String>,
119 message: impl Into<String>,
120 ) -> Self {
121 self.error_messages
122 .insert(error_type.into(), message.into());
123 self
124 }
125
126 #[allow(dead_code)]
129 fn get_choices(&self) -> Vec<(String, String)> {
130 let mut choices = Vec::new();
131
132 if !self.required && self.empty_label.is_some() {
133 choices.push(("".to_string(), self.empty_label.clone().unwrap()));
134 }
135
136 for instance in &self.queryset {
138 let value = instance.to_choice_value();
139 let label = instance.to_choice_label();
140 choices.push((value, label));
141 }
142
143 choices
144 }
145}
146
147impl<T: FormModel> FormField for ModelChoiceField<T> {
148 fn name(&self) -> &str {
149 &self.name
150 }
151
152 fn label(&self) -> Option<&str> {
153 None
154 }
155
156 fn widget(&self) -> &Widget {
157 &self.widget
158 }
159
160 fn required(&self) -> bool {
161 self.required
162 }
163
164 fn initial(&self) -> Option<&Value> {
165 self.initial.as_ref()
166 }
167
168 fn help_text(&self) -> Option<&str> {
169 if self.help_text.is_empty() {
170 None
171 } else {
172 Some(&self.help_text)
173 }
174 }
175
176 fn clean(&self, value: Option<&Value>) -> FieldResult<Value> {
177 if value.is_none() || value == Some(&Value::Null) {
178 if self.required {
179 let error_msg = self
180 .error_messages
181 .get("required")
182 .cloned()
183 .unwrap_or_else(|| "This field is required.".to_string());
184 return Err(FieldError::validation(None, &error_msg));
185 }
186 return Ok(Value::Null);
187 }
188
189 let s = match value.unwrap() {
190 Value::String(s) => s.as_str(),
191 Value::Number(n) => {
192 &n.to_string()
194 }
195 _ => {
196 let error_msg = self
197 .error_messages
198 .get("invalid_choice")
199 .cloned()
200 .unwrap_or_else(|| "Select a valid choice.".to_string());
201 return Err(FieldError::validation(None, &error_msg));
202 }
203 };
204
205 if s.is_empty() {
206 if self.required {
207 let error_msg = self
208 .error_messages
209 .get("required")
210 .cloned()
211 .unwrap_or_else(|| "This field is required.".to_string());
212 return Err(FieldError::validation(None, &error_msg));
213 }
214 return Ok(Value::Null);
215 }
216
217 let choice_exists = self
219 .queryset
220 .iter()
221 .any(|instance| instance.to_choice_value() == s);
222
223 if !choice_exists {
224 let error_msg = self
225 .error_messages
226 .get("invalid_choice")
227 .cloned()
228 .unwrap_or_else(|| "Select a valid choice.".to_string());
229 return Err(FieldError::validation(None, &error_msg));
230 }
231
232 Ok(Value::String(s.to_string()))
233 }
234
235 fn has_changed(&self, initial: Option<&Value>, data: Option<&Value>) -> bool {
236 match (initial, data) {
237 (None, None) => false,
238 (Some(_), None) | (None, Some(_)) => true,
239 (Some(a), Some(b)) => a != b,
240 }
241 }
242}
243
244pub struct ModelMultipleChoiceField<T: FormModel> {
248 pub name: String,
249 pub required: bool,
250 pub error_messages: HashMap<String, String>,
251 pub widget: Widget,
252 pub help_text: String,
253 pub initial: Option<Value>,
254 pub queryset: Vec<T>,
255 _phantom: PhantomData<T>,
256}
257
258impl<T: FormModel> ModelMultipleChoiceField<T> {
259 pub fn new(name: impl Into<String>, queryset: Vec<T>) -> Self {
314 let mut error_messages = HashMap::new();
315 error_messages.insert(
316 "required".to_string(),
317 "This field is required.".to_string(),
318 );
319 error_messages.insert(
320 "invalid_choice".to_string(),
321 "Select a valid choice.".to_string(),
322 );
323 error_messages.insert(
324 "invalid_list".to_string(),
325 "Enter a list of values.".to_string(),
326 );
327
328 Self {
329 name: name.into(),
330 required: true,
331 error_messages,
332 widget: Widget::Select {
333 choices: Vec::new(),
334 },
335 help_text: String::new(),
336 initial: None,
337 queryset,
338 _phantom: PhantomData,
339 }
340 }
341 pub fn required(mut self, required: bool) -> Self {
342 self.required = required;
343 self
344 }
345 pub fn help_text(mut self, text: impl Into<String>) -> Self {
346 self.help_text = text.into();
347 self
348 }
349 pub fn initial(mut self, value: Value) -> Self {
350 self.initial = Some(value);
351 self
352 }
353 pub fn error_message(
354 mut self,
355 error_type: impl Into<String>,
356 message: impl Into<String>,
357 ) -> Self {
358 self.error_messages
359 .insert(error_type.into(), message.into());
360 self
361 }
362
363 #[allow(dead_code)]
365 fn get_choices(&self) -> Vec<(String, String)> {
366 let mut choices = Vec::new();
367
368 for instance in &self.queryset {
370 let value = instance.to_choice_value();
371 let label = instance.to_choice_label();
372 choices.push((value, label));
373 }
374
375 choices
376 }
377}
378
379impl<T: FormModel> FormField for ModelMultipleChoiceField<T> {
380 fn name(&self) -> &str {
381 &self.name
382 }
383
384 fn label(&self) -> Option<&str> {
385 None
386 }
387
388 fn widget(&self) -> &Widget {
389 &self.widget
390 }
391
392 fn required(&self) -> bool {
393 self.required
394 }
395
396 fn initial(&self) -> Option<&Value> {
397 self.initial.as_ref()
398 }
399
400 fn help_text(&self) -> Option<&str> {
401 if self.help_text.is_empty() {
402 None
403 } else {
404 Some(&self.help_text)
405 }
406 }
407
408 fn clean(&self, value: Option<&Value>) -> FieldResult<Value> {
409 if value.is_none() || value == Some(&Value::Null) {
410 if self.required {
411 let error_msg = self
412 .error_messages
413 .get("required")
414 .cloned()
415 .unwrap_or_else(|| "This field is required.".to_string());
416 return Err(FieldError::validation(None, &error_msg));
417 }
418 return Ok(Value::Array(Vec::new()));
419 }
420
421 let values = match value.unwrap() {
422 Value::Array(arr) => arr.clone(),
423 Value::String(s) if s.is_empty() => {
424 if self.required {
425 let error_msg = self
426 .error_messages
427 .get("required")
428 .cloned()
429 .unwrap_or_else(|| "This field is required.".to_string());
430 return Err(FieldError::validation(None, &error_msg));
431 }
432 return Ok(Value::Array(Vec::new()));
433 }
434 Value::String(s) => {
435 s.split(',')
437 .map(|v| Value::String(v.trim().to_string()))
438 .collect()
439 }
440 _ => {
441 let error_msg = self
442 .error_messages
443 .get("invalid_list")
444 .cloned()
445 .unwrap_or_else(|| "Enter a list of values.".to_string());
446 return Err(FieldError::validation(None, &error_msg));
447 }
448 };
449
450 if values.is_empty() && self.required {
451 let error_msg = self
452 .error_messages
453 .get("required")
454 .cloned()
455 .unwrap_or_else(|| "This field is required.".to_string());
456 return Err(FieldError::validation(None, &error_msg));
457 }
458
459 for value in &values {
461 if let Some(value_str) = value.as_str() {
462 let choice_exists = self
463 .queryset
464 .iter()
465 .any(|instance| instance.to_choice_value() == value_str);
466
467 if !choice_exists {
468 let error_msg = self
469 .error_messages
470 .get("invalid_choice")
471 .cloned()
472 .unwrap_or_else(|| format!("'{}' is not a valid choice.", value_str));
473 return Err(FieldError::validation(None, &error_msg));
474 }
475 }
476 }
477
478 Ok(Value::Array(values))
479 }
480
481 fn has_changed(&self, initial: Option<&Value>, data: Option<&Value>) -> bool {
482 match (initial, data) {
483 (None, None) => false,
484 (Some(_), None) | (None, Some(_)) => true,
485 (Some(Value::Array(a)), Some(Value::Array(b))) => {
486 if a.len() != b.len() {
487 return true;
488 }
489 a.iter().zip(b.iter()).any(|(x, y)| x != y)
490 }
491 (Some(a), Some(b)) => a != b,
492 }
493 }
494}
495
496#[cfg(test)]
497mod tests {
498 use super::*;
499 use crate::FormField;
500 use serde_json::json;
501
502 struct TestModel {
504 id: i32,
505 name: String,
506 }
507
508 impl FormModel for TestModel {
509 fn field_names() -> Vec<String> {
510 vec!["id".to_string(), "name".to_string()]
511 }
512
513 fn get_field(&self, name: &str) -> Option<Value> {
514 match name {
515 "id" => Some(Value::Number(self.id.into())),
516 "name" => Some(Value::String(self.name.clone())),
517 _ => None,
518 }
519 }
520
521 fn set_field(&mut self, _name: &str, _value: Value) -> Result<(), String> {
522 Ok(())
523 }
524
525 fn save(&mut self) -> Result<(), String> {
526 Ok(())
527 }
528 }
529
530 #[test]
531 fn test_model_choice_field_basic() {
532 let queryset = vec![
533 TestModel {
534 id: 1,
535 name: "Option 1".to_string(),
536 },
537 TestModel {
538 id: 2,
539 name: "Option 2".to_string(),
540 },
541 ];
542
543 let field = ModelChoiceField::new("choice", queryset);
544
545 assert_eq!(field.name(), "choice");
546 assert!(FormField::required(&field));
547 }
548
549 #[test]
550 fn test_model_choice_field_required() {
551 let field = ModelChoiceField::new("choice", Vec::<TestModel>::new());
552
553 let result = field.clean(None);
554 assert!(result.is_err());
555 }
556
557 #[test]
558 fn test_model_choice_field_not_required() {
559 let field = ModelChoiceField::new("choice", Vec::<TestModel>::new()).required(false);
560
561 let result = field.clean(None);
562 assert!(result.is_ok());
563 assert_eq!(result.unwrap(), Value::Null);
564 }
565
566 #[test]
567 fn test_model_multiple_choice_field_basic() {
568 let queryset = vec![
569 TestModel {
570 id: 1,
571 name: "Option 1".to_string(),
572 },
573 TestModel {
574 id: 2,
575 name: "Option 2".to_string(),
576 },
577 ];
578
579 let field = ModelMultipleChoiceField::new("choices", queryset);
580
581 assert_eq!(field.name(), "choices");
582 assert!(FormField::required(&field));
583 }
584
585 #[test]
586 fn test_model_multiple_choice_field_array() {
587 let queryset = vec![
588 TestModel {
589 id: 1,
590 name: "Option 1".to_string(),
591 },
592 TestModel {
593 id: 2,
594 name: "Option 2".to_string(),
595 },
596 TestModel {
597 id: 3,
598 name: "Option 3".to_string(),
599 },
600 ];
601
602 let field = ModelMultipleChoiceField::new("choices", queryset).required(false);
603
604 let result = field.clean(Some(&json!(["1", "2"])));
605 assert!(result.is_ok());
606
607 if let Value::Array(arr) = result.unwrap() {
608 assert_eq!(arr.len(), 2);
609 } else {
610 panic!("Expected array");
611 }
612 }
613
614 #[test]
615 fn test_model_multiple_choice_field_comma_separated() {
616 let queryset = vec![
617 TestModel {
618 id: 1,
619 name: "Option 1".to_string(),
620 },
621 TestModel {
622 id: 2,
623 name: "Option 2".to_string(),
624 },
625 TestModel {
626 id: 3,
627 name: "Option 3".to_string(),
628 },
629 ];
630
631 let field = ModelMultipleChoiceField::new("choices", queryset).required(false);
632
633 let result = field.clean(Some(&json!("1,2,3")));
634 assert!(result.is_ok());
635
636 if let Value::Array(arr) = result.unwrap() {
637 assert_eq!(arr.len(), 3);
638 } else {
639 panic!("Expected array");
640 }
641 }
642}