Brak opisu

forms.py 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. from __future__ import annotations
  2. from django import forms
  3. from django.contrib.auth import get_user_model
  4. from django.core.exceptions import ValidationError
  5. from crispy_forms.helper import FormHelper
  6. from crispy_forms.layout import Layout, Field
  7. from .models import Organization, UserProfile
  8. from api.models import Profile as ApiProfile
  9. class OrganizationForm(forms.ModelForm):
  10. class Meta:
  11. model = Organization
  12. fields = ["name", "code", "timezone", "currency_code"]
  13. ## ProvidedService moved to recycle_core app; form now lives in recycle_core.forms
  14. class UserSelfForm(forms.ModelForm):
  15. class Meta:
  16. model = get_user_model()
  17. fields = ["first_name", "last_name", "email"]
  18. def __init__(self, *args, **kwargs):
  19. super().__init__(*args, **kwargs)
  20. self.helper = FormHelper()
  21. self.helper.form_tag = False
  22. self.helper.layout = Layout(
  23. Field("first_name"),
  24. Field("last_name"),
  25. Field("email"),
  26. )
  27. class ProfileSelfForm(forms.ModelForm):
  28. tags = forms.CharField(label="Tags", required=False, help_text="Comma-separated")
  29. class Meta:
  30. model = ApiProfile
  31. fields = ["bio", "interests", "industry"]
  32. def __init__(self, *args, **kwargs):
  33. super().__init__(*args, **kwargs)
  34. self.helper = FormHelper()
  35. self.helper.form_tag = False
  36. self.helper.layout = Layout(
  37. Field("bio"),
  38. Field("interests"),
  39. Field("industry"),
  40. Field("tags"),
  41. )
  42. if self.instance and getattr(self.instance, "pk", None):
  43. try:
  44. names = list(self.instance.tags.names())
  45. self.fields["tags"].initial = ", ".join(names)
  46. except Exception:
  47. self.fields["tags"].initial = ""
  48. def save(self, commit: bool = True):
  49. profile = super().save(commit)
  50. tags = [t.strip() for t in self.cleaned_data.get("tags", "").split(",") if t.strip()]
  51. try:
  52. if commit and hasattr(profile, "tags"):
  53. profile.tags.set(tags)
  54. except Exception:
  55. pass
  56. return profile
  57. class UserProfilePhotoForm(forms.ModelForm):
  58. remove_photo = forms.BooleanField(label="Remove current photo", required=False)
  59. class Meta:
  60. model = UserProfile
  61. fields = ["my_photo", "remove_photo"]
  62. def __init__(self, *args, **kwargs):
  63. super().__init__(*args, **kwargs)
  64. # Friendlier widget: accept images only, keep input visually hidden (we trigger via button)
  65. self.fields["my_photo"].widget = forms.ClearableFileInput(attrs={
  66. "accept": "image/*",
  67. "class": "hidden",
  68. "id": "id_my_photo",
  69. })
  70. self.helper = FormHelper()
  71. self.helper.form_tag = False
  72. self.helper.layout = Layout(
  73. Field("my_photo"),
  74. Field("remove_photo"),
  75. )
  76. def clean_my_photo(self):
  77. f = self.cleaned_data.get("my_photo")
  78. if not f:
  79. return f
  80. # Basic size/type validation (max ~5MB)
  81. try:
  82. content_type = getattr(f, "content_type", "")
  83. if content_type and not content_type.startswith("image/"):
  84. raise ValidationError("Please upload an image file.")
  85. except Exception:
  86. # If storage/file doesn't provide content_type, best-effort skip
  87. pass
  88. max_bytes = 5 * 1024 * 1024
  89. if getattr(f, "size", 0) and f.size > max_bytes:
  90. raise ValidationError("Image too large (max 5MB).")
  91. return f
  92. def save(self, commit: bool = True):
  93. instance: UserProfile = super().save(commit=False)
  94. remove = self.cleaned_data.get("remove_photo", False)
  95. new_file = self.cleaned_data.get("my_photo")
  96. if remove and not new_file:
  97. # Clear current photo
  98. try:
  99. if instance.my_photo:
  100. instance.my_photo.delete(save=False)
  101. except Exception:
  102. pass
  103. instance.my_photo = None
  104. if commit:
  105. instance.save()
  106. return instance