maquinaweb-shared-auth 0.2.30__py3-none-any.whl → 0.2.32__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of maquinaweb-shared-auth might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maquinaweb-shared-auth
3
- Version: 0.2.30
3
+ Version: 0.2.32
4
4
  Summary: Models read-only para autenticação compartilhada entre projetos Django.
5
5
  Author-email: Seu Nome <seuemail@dominio.com>
6
6
  License: MIT
@@ -743,7 +743,7 @@ SharedOrganization.objects.main_organizations() # QuerySet (is_branch=False)
743
743
  SharedOrganization.objects.by_cnpj('12.345.678/0001-90') # Org | None
744
744
  ```
745
745
 
746
- #### SharedUserManager
746
+ #### UserManager
747
747
 
748
748
  ```python
749
749
  from shared_auth.models import User
@@ -5,17 +5,17 @@ shared_auth/conf.py,sha256=WlSXQB7p3BfE3BL6WR6EDYpCHQEjDlxQlyf8dTfClsk,621
5
5
  shared_auth/decorators.py,sha256=RT-Qfi7oGBo6PvWJRR1dqJUQdU6ZOf9p-8mV3rZmqQ0,3237
6
6
  shared_auth/exceptions.py,sha256=VKamHjBl2yjXG2RsMrLrXru1_Q9IJXmy4xmDcXlpWsU,627
7
7
  shared_auth/fields.py,sha256=RAcmFh1D_nkbai_7t_OrPZhfhAipesy5kKnEj4LUvvM,1254
8
- shared_auth/managers.py,sha256=A9y-X4ixVXhsNxgr3YD4DtuN4ufrX7LbM_JPwJ0Y3aA,9176
8
+ shared_auth/managers.py,sha256=NpIDMY7BWl1pKZKCepuNDxz7eekEUhKkOUYsWGbwyos,6715
9
9
  shared_auth/middleware.py,sha256=72GF8kGijbhw98v2Q-1sXBXk-7Bamfyvypm9h8xLX_I,6112
10
- shared_auth/mixins.py,sha256=9TJk07hlHXnTYu0tPNr7VAXd7VL9fyXayMaFERifLLY,7389
11
- shared_auth/models.py,sha256=vCyssDwKfWRE3ofl6LK_CB1-y5O-_6uvJyGZGoCnb44,6574
10
+ shared_auth/mixins.py,sha256=BSYNTWYjLRGuxfy7x-uAaNZmrTMsm67ogAQzjrU2DoQ,7388
11
+ shared_auth/models.py,sha256=QMY_Oyr4x7AtSNAFV3UfoJY0YBZwFKePvfVNWt-vQTc,6562
12
12
  shared_auth/permissions.py,sha256=FNIp12ePOUlXVp26zNMAyEtzX9kwyP7RuNIgaaCXtPA,2671
13
13
  shared_auth/router.py,sha256=zYidJ7j40lQLrhkCtAQAp-rQLhua_UF0X7SDzYRcV5w,668
14
- shared_auth/serializers.py,sha256=VmajFqnAHB5wyxsdd5_WVegAQygi0KNOMk7vScCPHiQ,7385
14
+ shared_auth/serializers.py,sha256=5jmyoyAAMCeMqxuVyw-tGPI8MCLfPslG94cdRL19B3Y,13374
15
15
  shared_auth/storage_backend.py,sha256=Eqkjz8aF5UrOpRwYl-J0Td95IObfxnJ8eLQDJVFM3Io,184
16
16
  shared_auth/urls.py,sha256=591wWEWJPaHEGkcOZ8yvfgxddRyOcZLgOc0vNtF7XRI,289
17
17
  shared_auth/views.py,sha256=2hyLnYSWUscfq-jVcskt-ukzDt4vg6IXeKjRDRu9RXk,1519
18
- maquinaweb_shared_auth-0.2.30.dist-info/METADATA,sha256=bIuaOJDn7kPoK8tE16uQWf3qgqPO3RixJpJ9HiYYXUk,26331
19
- maquinaweb_shared_auth-0.2.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
- maquinaweb_shared_auth-0.2.30.dist-info/top_level.txt,sha256=msyYRy02ZV7zz7GR1raUI5LXGFIFn2TIkgkeKZqKufE,12
21
- maquinaweb_shared_auth-0.2.30.dist-info/RECORD,,
18
+ maquinaweb_shared_auth-0.2.32.dist-info/METADATA,sha256=lIGuKuLhYkiFs9jDv-Kr6vlxW0N6tTciSdoZngCwRvA,26325
19
+ maquinaweb_shared_auth-0.2.32.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
+ maquinaweb_shared_auth-0.2.32.dist-info/top_level.txt,sha256=msyYRy02ZV7zz7GR1raUI5LXGFIFn2TIkgkeKZqKufE,12
21
+ maquinaweb_shared_auth-0.2.32.dist-info/RECORD,,
shared_auth/managers.py CHANGED
@@ -45,8 +45,8 @@ class SharedOrganizationManager(models.Manager):
45
45
  return self.filter(cnpj__contains=clean_cnpj).first()
46
46
 
47
47
 
48
- class SharedUserManager(UserManager):
49
- """Manager para SharedUser"""
48
+ class UserManager(UserManager):
49
+ """Manager para User"""
50
50
 
51
51
  def get_or_fail(self, user_id):
52
52
  """Busca usuário ou lança exceção"""
@@ -89,38 +89,16 @@ class OrganizationQuerySetMixin:
89
89
 
90
90
  def with_organization_data(self):
91
91
  """
92
- Pré-carrega dados de organizações (evita N+1 queries)
93
-
94
- Faz uma única query bulk para buscar todas as organizações necessárias
95
- e cacheia nos objetos usando _cached_organization.
96
-
97
- IMPORTANTE: Este método força a avaliação do QuerySet e aplica cache.
98
- Para manter a chain de QuerySet, chame este método por último.
99
-
100
- Usage:
101
- # Sem otimização (N+1 queries)
102
- rascunhos = Rascunho.objects.all()
103
- for r in rascunhos:
104
- print(r.organization.name) # Query individual para cada
105
-
106
- # Com otimização (2 queries total)
107
- rascunhos = Rascunho.objects.all().with_organization_data()
108
- for r in rascunhos:
109
- print(r.organization.name) # Usa cache, sem queries extras
92
+ Pré-carrega dados de organizações (evita N+1)
110
93
 
111
94
  Returns:
112
- Self (QuerySet) com _prefetch_done=True e objetos cacheados
95
+ Lista de objetos com _cached_organization
113
96
  """
114
- # Marcar que o prefetch foi feito
115
- self._prefetch_done = True
116
-
117
- # Forçar avaliação do queryset
118
- objects = list(self)
97
+ objects = list(self.all())
98
+ from .models import SharedOrganization
119
99
 
120
100
  if not objects:
121
- return self
122
-
123
- from .models import SharedOrganization
101
+ return objects
124
102
 
125
103
  # Coletar IDs únicos
126
104
  org_ids = set(obj.organization_id for obj in objects)
@@ -134,10 +112,7 @@ class OrganizationQuerySetMixin:
134
112
  for obj in objects:
135
113
  obj._cached_organization = organizations.get(obj.organization_id)
136
114
 
137
- # Armazenar os objetos cacheados no queryset
138
- self._result_cache = objects
139
-
140
- return self
115
+ return objects
141
116
 
142
117
 
143
118
  class UserQuerySetMixin:
@@ -153,27 +128,14 @@ class UserQuerySetMixin:
153
128
 
154
129
  def with_user_data(self):
155
130
  """
156
- Pré-carrega dados de usuários (evita N+1 queries)
157
-
158
- Usage:
159
- # Com otimização (2 queries total)
160
- rascunhos = Rascunho.objects.all().with_user_data()
161
- for r in rascunhos:
162
- print(r.user.email) # Usa cache, sem queries extras
163
-
164
- Returns:
165
- Self (QuerySet) com objetos cacheados
131
+ Pré-carrega dados de usuários (evita N+1)
166
132
  """
167
133
  from .models import User
168
134
 
169
- # Marcar que o prefetch foi feito
170
- self._prefetch_done = True
171
-
172
- # Forçar avaliação do queryset
173
- objects = list(self)
135
+ objects = list(self.all())
174
136
 
175
137
  if not objects:
176
- return self
138
+ return objects
177
139
 
178
140
  user_ids = set(obj.user_id for obj in objects)
179
141
 
@@ -182,10 +144,7 @@ class UserQuerySetMixin:
182
144
  for obj in objects:
183
145
  obj._cached_user = users.get(obj.user_id)
184
146
 
185
- # Armazenar os objetos cacheados no queryset
186
- self._result_cache = objects
187
-
188
- return self
147
+ return objects
189
148
 
190
149
 
191
150
  class OrganizationUserQuerySetMixin(OrganizationQuerySetMixin, UserQuerySetMixin):
@@ -193,39 +152,14 @@ class OrganizationUserQuerySetMixin(OrganizationQuerySetMixin, UserQuerySetMixin
193
152
 
194
153
  def with_auth_data(self):
195
154
  """
196
- Pré-carrega dados de organizações E usuários (evita N+1 queries)
197
-
198
- Faz apenas 3 queries no total, independente da quantidade de objetos:
199
- 1. Query dos objetos principais
200
- 2. Query bulk das organizações
201
- 3. Query bulk dos usuários
202
-
203
- Usage:
204
- # Sem otimização (1 + N + N queries)
205
- rascunhos = Rascunho.objects.all() # 1 query
206
- for r in rascunhos:
207
- print(r.organization.name) # N queries
208
- print(r.user.email) # N queries
209
-
210
- # Com otimização (3 queries total)
211
- rascunhos = Rascunho.objects.all().with_auth_data()
212
- for r in rascunhos:
213
- print(r.organization.name) # Cache
214
- print(r.user.email) # Cache
215
-
216
- Returns:
217
- Self (QuerySet) com objetos cacheados
155
+ Pré-carrega dados de organizações E usuários (evita N+1)
218
156
  """
219
157
  from .models import SharedOrganization, User
220
158
 
221
- # Marcar que o prefetch foi feito
222
- self._prefetch_done = True
223
-
224
- # Forçar avaliação do queryset
225
- objects = list(self)
159
+ objects = list(self.all())
226
160
 
227
161
  if not objects:
228
- return self
162
+ return objects
229
163
 
230
164
  # Coletar IDs
231
165
  org_ids = set(obj.organization_id for obj in objects)
@@ -243,10 +177,7 @@ class OrganizationUserQuerySetMixin(OrganizationQuerySetMixin, UserQuerySetMixin
243
177
  obj._cached_organization = organizations.get(obj.organization_id)
244
178
  obj._cached_user = users.get(obj.user_id)
245
179
 
246
- # Armazenar os objetos cacheados no queryset
247
- self._result_cache = objects
248
-
249
- return self
180
+ return objects
250
181
 
251
182
  def create_with_validation(self, organization_id, user_id, **kwargs):
252
183
  """
shared_auth/mixins.py CHANGED
@@ -227,7 +227,6 @@ class LoggedOrganizationMixin(viewsets.ModelViewSet):
227
227
  return queryset.none()
228
228
 
229
229
  organization_id = self.get_organization_id()
230
-
231
230
  if hasattr(queryset.model, "organization_id"):
232
231
  return queryset.filter(organization_id=organization_id)
233
232
  elif hasattr(queryset.model, "organization"):
shared_auth/models.py CHANGED
@@ -10,7 +10,7 @@ from django.db import models
10
10
 
11
11
  from .conf import MEMBER_TABLE, ORGANIZATION_TABLE, TOKEN_TABLE, USER_TABLE
12
12
  from .exceptions import OrganizationNotFoundError
13
- from .managers import SharedMemberManager, SharedOrganizationManager, SharedUserManager
13
+ from .managers import SharedMemberManager, SharedOrganizationManager, UserManager
14
14
  from .storage_backend import Storage
15
15
 
16
16
 
@@ -155,7 +155,7 @@ class User(AbstractUser):
155
155
  updatedat = models.DateTimeField()
156
156
  deleted_at = models.DateTimeField(null=True, blank=True)
157
157
 
158
- objects = SharedUserManager()
158
+ objects = UserManager()
159
159
 
160
160
  class Meta:
161
161
  managed = False
@@ -1,5 +1,14 @@
1
1
  """
2
2
  Serializers compartilhados para DRF
3
+
4
+ Separação de responsabilidades:
5
+ - CreateSerializerMixin: apenas para criação (seta IDs do request)
6
+ - SerializerMixin: listagem com dados aninhados + criação (compatibilidade com código existente)
7
+
8
+ Se quiser usar separadamente:
9
+ - Use apenas *CreateSerializerMixin para create
10
+ - Use apenas *SerializerMixin para listagem
11
+ - Ou herde ambos se precisar
3
12
  """
4
13
 
5
14
  from rest_framework import serializers
@@ -7,6 +16,27 @@ from rest_framework import serializers
7
16
  from .models import SharedOrganization, User
8
17
 
9
18
 
19
+ class OrganizationCreateSerializerMixin(serializers.ModelSerializer):
20
+ """
21
+ Mixin APENAS para criação.
22
+ Automaticamente seta organization_id no create a partir do request context.
23
+
24
+ Usage:
25
+ class RascunhoCreateSerializer(OrganizationCreateSerializerMixin, serializers.ModelSerializer):
26
+ class Meta:
27
+ model = Rascunho
28
+ fields = ['id', 'titulo', 'conteudo']
29
+ """
30
+
31
+ def create(self, validated_data):
32
+ """Automatically set organization_id from request context"""
33
+ if self.context.get("request") and hasattr(
34
+ self.context["request"], "organization_id"
35
+ ):
36
+ validated_data["organization_id"] = self.context["request"].organization_id
37
+ return super().create(validated_data)
38
+
39
+
10
40
  class OrganizationSerializerMixin(serializers.ModelSerializer):
11
41
  """
12
42
  Mixin para serializers que incluem dados de organização como objeto aninhado
@@ -30,6 +60,18 @@ class OrganizationSerializerMixin(serializers.ModelSerializer):
30
60
  class Meta:
31
61
  model = Rascunho
32
62
  fields = ['id', 'titulo', 'organization']
63
+
64
+ # Ou apenas para listagem (sem create):
65
+ class RascunhoListSerializer(OrganizationSerializerMixin, serializers.ModelSerializer):
66
+ class Meta:
67
+ model = Rascunho
68
+ fields = ['id', 'titulo', 'organization']
69
+
70
+ # Ou combinar com create:
71
+ class RascunhoFullSerializer(OrganizationSerializerMixin, OrganizationCreateSerializerMixin):
72
+ class Meta:
73
+ model = Rascunho
74
+ fields = ['id', 'titulo', 'organization']
33
75
  """
34
76
 
35
77
  organization = serializers.SerializerMethodField()
@@ -55,13 +97,22 @@ class OrganizationSerializerMixin(serializers.ModelSerializer):
55
97
  except Exception:
56
98
  return None
57
99
 
58
- def create(self, validated_data):
59
- """Automatically set organization_id from request context"""
60
- if self.context.get("request") and hasattr(
61
- self.context["request"], "organization_id"
62
- ):
63
- validated_data["organization_id"] = self.context["request"].organization_id
64
- return super().create(validated_data)
100
+
101
+ class OrganizationListCreateSerializerMixin(
102
+ OrganizationSerializerMixin, OrganizationCreateSerializerMixin
103
+ ):
104
+ """
105
+ Mixin COMPLETO pronto para usar: listagem + criação.
106
+ Combina OrganizationSerializerMixin + OrganizationCreateSerializerMixin.
107
+
108
+ Usage:
109
+ class RascunhoSerializer(OrganizationListCreateSerializerMixin, serializers.ModelSerializer):
110
+ class Meta:
111
+ model = Rascunho
112
+ fields = ['id', 'titulo', 'organization']
113
+ """
114
+
115
+ pass
65
116
 
66
117
 
67
118
  class OrganizationSerializer(serializers.ModelSerializer):
@@ -70,21 +121,23 @@ class OrganizationSerializer(serializers.ModelSerializer):
70
121
  fields = "__all__"
71
122
 
72
123
 
73
- class UserSerializer(serializers.ModelSerializer):
74
- class Meta:
75
- model = User
76
- fields = [
77
- "id",
78
- "username",
79
- "first_name",
80
- "last_name",
81
- "email",
82
- "is_active",
83
- "is_staff",
84
- "is_superuser",
85
- "date_joined",
86
- "last_login",
87
- ]
124
+ class UserCreateSerializerMixin(serializers.ModelSerializer):
125
+ """
126
+ Mixin APENAS para criação.
127
+ Automaticamente seta user_id no create a partir do request context.
128
+
129
+ Usage:
130
+ class RascunhoCreateSerializer(UserCreateSerializerMixin, serializers.ModelSerializer):
131
+ class Meta:
132
+ model = Rascunho
133
+ fields = ['id', 'titulo', 'conteudo']
134
+ """
135
+
136
+ def create(self, validated_data):
137
+ """Automatically set user_id from request context"""
138
+ if self.context.get("request") and hasattr(self.context["request"], "user"):
139
+ validated_data["user_id"] = self.context["request"].user.id
140
+ return super().create(validated_data)
88
141
 
89
142
 
90
143
  class UserSerializerMixin(serializers.ModelSerializer):
@@ -110,6 +163,18 @@ class UserSerializerMixin(serializers.ModelSerializer):
110
163
  class Meta:
111
164
  model = Rascunho
112
165
  fields = ['id', 'titulo', 'user']
166
+
167
+ # Ou apenas para listagem (sem create):
168
+ class RascunhoListSerializer(UserSerializerMixin, serializers.ModelSerializer):
169
+ class Meta:
170
+ model = Rascunho
171
+ fields = ['id', 'titulo', 'user']
172
+
173
+ # Ou combinar com create:
174
+ class RascunhoFullSerializer(UserSerializerMixin, UserCreateSerializerMixin):
175
+ class Meta:
176
+ model = Rascunho
177
+ fields = ['id', 'titulo', 'user']
113
178
  """
114
179
 
115
180
  user = serializers.SerializerMethodField()
@@ -131,10 +196,59 @@ class UserSerializerMixin(serializers.ModelSerializer):
131
196
  except Exception:
132
197
  return None
133
198
 
199
+
200
+ class UserListCreateSerializerMixin(UserSerializerMixin, UserCreateSerializerMixin):
201
+ """
202
+ Mixin COMPLETO pronto para usar: listagem + criação.
203
+ Combina UserSerializerMixin + UserCreateSerializerMixin.
204
+
205
+ Usage:
206
+ class RascunhoSerializer(UserListCreateSerializerMixin, serializers.ModelSerializer):
207
+ class Meta:
208
+ model = Rascunho
209
+ fields = ['id', 'titulo', 'user']
210
+ """
211
+
212
+ pass
213
+
214
+
215
+ class UserSerializer(serializers.ModelSerializer):
216
+ class Meta:
217
+ model = User
218
+ fields = [
219
+ "id",
220
+ "username",
221
+ "first_name",
222
+ "last_name",
223
+ "email",
224
+ "is_active",
225
+ "is_staff",
226
+ "is_superuser",
227
+ "date_joined",
228
+ "last_login",
229
+ ]
230
+
231
+
232
+ class OrganizationUserCreateSerializerMixin(serializers.ModelSerializer):
233
+ """
234
+ Mixin APENAS para criação com organization + user.
235
+ Automaticamente seta organization_id e user_id no create a partir do request context.
236
+
237
+ Usage:
238
+ class RascunhoCreateSerializer(OrganizationUserCreateSerializerMixin, serializers.ModelSerializer):
239
+ class Meta:
240
+ model = Rascunho
241
+ fields = ['id', 'titulo', 'conteudo']
242
+ """
243
+
134
244
  def create(self, validated_data):
135
- """Automatically set user_id from request context"""
136
- if self.context.get("request") and hasattr(self.context["request"], "user"):
137
- validated_data["user_id"] = self.context["request"].user.id
245
+ """Automatically set both organization_id and user_id from request context"""
246
+ if self.context.get("request"):
247
+ request = self.context["request"]
248
+ if hasattr(request, "organization_id"):
249
+ validated_data["organization_id"] = request.organization_id
250
+ if hasattr(request, "user"):
251
+ validated_data["user_id"] = request.user.id
138
252
  return super().create(validated_data)
139
253
 
140
254
 
@@ -164,24 +278,57 @@ class OrganizationUserSerializerMixin(OrganizationSerializerMixin, UserSerialize
164
278
  class Meta:
165
279
  model = Rascunho
166
280
  fields = ['id', 'titulo', 'conteudo', 'organization', 'user']
281
+
282
+ # Ou apenas para listagem (sem create):
283
+ class RascunhoListSerializer(OrganizationUserSerializerMixin, serializers.ModelSerializer):
284
+ class Meta:
285
+ model = Rascunho
286
+ fields = ['id', 'titulo', 'organization', 'user']
287
+
288
+ # Ou combinar com create:
289
+ class RascunhoFullSerializer(OrganizationUserSerializerMixin, OrganizationUserCreateSerializerMixin):
290
+ class Meta:
291
+ model = Rascunho
292
+ fields = ['id', 'titulo', 'organization', 'user']
167
293
  """
168
294
 
169
- def create(self, validated_data):
170
- """Automatically set both organization_id and user_id from request context"""
171
- if self.context.get("request"):
172
- request = self.context["request"]
173
- if hasattr(request, "organization_id"):
174
- validated_data["organization_id"] = request.organization_id
175
- if hasattr(request, "user"):
176
- validated_data["user_id"] = request.user.id
177
- return super(UserSerializerMixin, self).create(validated_data)
295
+ pass
296
+
297
+
298
+ class OrganizationUserListCreateSerializerMixin(
299
+ OrganizationUserSerializerMixin, OrganizationUserCreateSerializerMixin
300
+ ):
301
+ """
302
+ Mixin COMPLETO pronto para usar: listagem + criação com organization + user.
303
+ Combina OrganizationUserSerializerMixin + OrganizationUserCreateSerializerMixin.
304
+
305
+ Usage:
306
+ class RascunhoSerializer(OrganizationUserListCreateSerializerMixin, serializers.ModelSerializer):
307
+ class Meta:
308
+ model = Rascunho
309
+ fields = ['id', 'titulo', 'organization', 'user']
310
+ """
311
+
312
+ pass
178
313
 
179
314
 
180
- # Versões simplificadas (opcional)
181
315
  class OrganizationSimpleSerializerMixin(serializers.ModelSerializer):
182
316
  """
183
317
  Versão simplificada que retorna apenas campos essenciais da organização
184
318
  e automaticamente seta organization_id no create a partir do request context.
319
+
320
+ Usage:
321
+ # Para listagem:
322
+ class RascunhoListSerializer(OrganizationSimpleSerializerMixin, serializers.ModelSerializer):
323
+ class Meta:
324
+ model = Rascunho
325
+ fields = ['id', 'titulo', 'organization']
326
+
327
+ # Para criar com organization:
328
+ class RascunhoCreateSerializer(OrganizationSimpleSerializerMixin, OrganizationCreateSerializerMixin):
329
+ class Meta:
330
+ model = Rascunho
331
+ fields = ['id', 'titulo', 'organization']
185
332
  """
186
333
 
187
334
  organization = serializers.SerializerMethodField()
@@ -194,22 +341,44 @@ class OrganizationSimpleSerializerMixin(serializers.ModelSerializer):
194
341
  "name": org.name,
195
342
  "cnpj": org.cnpj,
196
343
  }
197
- except:
344
+ except Exception:
198
345
  return None
199
346
 
200
- def create(self, validated_data):
201
- """Automatically set organization_id from request context"""
202
- if self.context.get("request") and hasattr(
203
- self.context["request"], "organization_id"
204
- ):
205
- validated_data["organization_id"] = self.context["request"].organization_id
206
- return super().create(validated_data)
347
+
348
+ class OrganizationSimpleListCreateSerializerMixin(
349
+ OrganizationSimpleSerializerMixin, OrganizationCreateSerializerMixin
350
+ ):
351
+ """
352
+ Versão simplificada COMPLETA pronta para usar: listagem + criação.
353
+ Retorna apenas campos essenciais da organização.
354
+
355
+ Usage:
356
+ class RascunhoSerializer(OrganizationSimpleListCreateSerializerMixin, serializers.ModelSerializer):
357
+ class Meta:
358
+ model = Rascunho
359
+ fields = ['id', 'titulo', 'organization']
360
+ """
361
+
362
+ pass
207
363
 
208
364
 
209
365
  class UserSimpleSerializerMixin(serializers.ModelSerializer):
210
366
  """
211
367
  Versão simplificada que retorna apenas campos essenciais do usuário
212
368
  e automaticamente seta user_id no create a partir do request context.
369
+
370
+ Usage:
371
+ # Para listagem:
372
+ class RascunhoListSerializer(UserSimpleSerializerMixin, serializers.ModelSerializer):
373
+ class Meta:
374
+ model = Rascunho
375
+ fields = ['id', 'titulo', 'user']
376
+
377
+ # Para criar com user:
378
+ class RascunhoCreateSerializer(UserSimpleSerializerMixin, UserCreateSerializerMixin):
379
+ class Meta:
380
+ model = Rascunho
381
+ fields = ['id', 'titulo', 'user']
213
382
  """
214
383
 
215
384
  user = serializers.SerializerMethodField()
@@ -222,11 +391,22 @@ class UserSimpleSerializerMixin(serializers.ModelSerializer):
222
391
  "email": user.email,
223
392
  "full_name": user.get_full_name(),
224
393
  }
225
- except:
394
+ except Exception:
226
395
  return None
227
396
 
228
- def create(self, validated_data):
229
- """Automatically set user_id from request context"""
230
- if self.context.get("request") and hasattr(self.context["request"], "user"):
231
- validated_data["user_id"] = self.context["request"].user.id
232
- return super().create(validated_data)
397
+
398
+ class UserSimpleListCreateSerializerMixin(
399
+ UserSimpleSerializerMixin, UserCreateSerializerMixin
400
+ ):
401
+ """
402
+ Versão simplificada COMPLETA pronta para usar: listagem + criação.
403
+ Retorna apenas campos essenciais do usuário.
404
+
405
+ Usage:
406
+ class RascunhoSerializer(UserSimpleListCreateSerializerMixin, serializers.ModelSerializer):
407
+ class Meta:
408
+ model = Rascunho
409
+ fields = ['id', 'titulo', 'user']
410
+ """
411
+
412
+ pass