Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

1K
Visualizações
Django: implementar múltiples niveles de usuario/roles/tipos

He estado usando Django durante bastante tiempo, pero nunca había pensado en esto hasta ahora.

Actualmente, tengo un proyecto que contiene diferentes niveles de usuario. Por lo general, en mi experiencia pasada, solo desarrollé sistemas usando Django con solo dos niveles de usuario que son superusuario y usuario normal/regular. Entonces, mi pregunta es ¿cuáles son las formas efectivas de presentar estos diferentes niveles de usuario en el modelo/base de datos? Aquí, usaré un sistema escolar como ejemplo y también proporcionaré algunos de mis pensamientos iniciales sobre su implementación.

Niveles de usuario:

  1. Administrador (superusuario y personal)
  2. Principal
  3. Profesor
  4. Estudiantes

Método n.º 1: agregar nuevas tablas en función de cada nivel de usuario

 from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): user = models.CharfieldField(max_length = 10, unique = True) class Admin(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True) class Pricipal(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True) class Teacher(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True) class Student(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

Método n.º 2: agregue atributos de tipos de usuario adicionales en el modelo de usuario

 from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): user = models.CharfieldField(max_length = 10, unique = True) is_superuser = models.BooleanField(default = False) is_staff = models.BooleanField(default = False) is_principal = models.BooleanField(default = False) is_teacher = models.BooleanField(default = False) is_student = models.BooleanField(default = False ''' User table in DB: user | is_superuser | is_staff | is_principal | is_teacher | is_student '''

Mis pensamientos:

En el método n.º 1, dado que el modelo de usuario integrado tiene dos campos, is_staff y is_superuser, ¿es posible implementar/cambiar los campos en una tabla de superusuario/administrador como en el ejemplo anterior? Esto significa que cuando creo un administrador/superusuario, quiero que agregue una nueva fila en la tabla de administración, en lugar de agregar un nuevo usuario y actualizar los campos is_superuser y is_staff del usuario en 1 en el modelo de usuario integrado.

En el Método #2, el problema es que las tablas con diferentes privilegios de acceso están directamente conectadas a él. Por ejemplo, el modelo Salario (al que no puede acceder el usuario Estudiante) tiene un vínculo directo con el modelo Usuario (contiene el usuario Estudiante).

Espero poder obtener algunas ideas y también una forma adecuada y efectiva de implementar esto para evitar cualquier inconveniente y error de implementación en el futuro. Muchas gracias.

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Uno de los métodos que utilicé en varios proyectos es este (pseudocódigo):

 class User(AbstractUser): ADMIN = 0 PRINCIPLE = 1 TEACHER = 2 STUDENT = 3 USER_LEVEL_CHOICES = ( (ADMIN, "Admin"), (PRINCIPLE, "Principle"), (TEACHER, "Teacher"), (STUDENT, "Student"), ) user_level = models.IntgerField(choices=USER_LEVEL_CHOICES) def lvl_decorator(): def check_lvl(func): def function_wrapper(self, actor, action_on, *args, **kwargs): if 'action_lvl' not in action_on: # then action_on is user if actor.user_lvl < action_on.user_lvl: return True return False else: # then action_on is action of some kind for that user (you can add action_lvl to ... and pas them to this wapper) if actor.user_lvl < action_on.action_lvl: return True return False return function_wrapper return check_lvl

Luego, puede escribir la función contenedora con esta lógica para cualquier acción, verifique si el nivel de acción es mayor que el nivel de usuario, por ejemplo: si alguien quiere cambiar la contraseña de superusuario, debe iniciar sesión con el usuario de nivel 0, pero para cambiar la contraseña del usuario normal. debe ser de nivel 0, 1. Esta lógica también se puede aplicar a acciones de clase, funciones, etc.

Cree una clase base y luego agréguele lvl_decorator y luego inherente a ella => esto mantiene su código súper limpio y evita que se copie y pegue más.

ejemplo de lo que quiero decir:

 def lvl_decorator(): def check_lvl(func): def function_wrapper(self, actor, action_on, *args, **kwargs): if 'action_lvl' not in action_on: # then action_on is user if actor.user_lvl < action_on.user_lvl: return True return False else: if actor.user_lvl < action_on.action_lvl: return True return False return function_wrapper return check_lvl class BaseClass(type): def __new__(cls, name, bases, local): for attr in local: value = local[attr] if callable(value): local[attr] = lvl_decorator() return type.__new__(cls, name, bases, local) # in other locations like views.py use this sample class FooViewDjango(object, ApiView): # don't remove object or this won't work, you can use any Django stuff you need to inherent. __metaclass__ = BaseClass def baz(self): print('hora hora')

Utilice esta clase base en cualquier lugar que desee.

over 4 years ago · Santiago Trujillo Relatório

0

Creo que estás en el camino correcto con el método #2. Es más ligero y más sencillo.

No usaría un modelo personalizado "similar al usuario" para cada nivel de permiso. Demasiado complicado, no escala y multiplica el número de consultas, sin ningún beneficio para su problema. No es su esquema UML sino su contenido el que debe garantizar sus requisitos de permisos .

Si los niveles de permiso no son mutuamente excluyentes:

 from django.db import models from django.contrib.postgres.fields import ArrayField class User(AbstractUser): ADMIN = 0 PRINCIPLE = 1 TEACHER = 2 STUDENT = 3 USER_LEVEL_CHOICES = ( (ADMIN, "Admin"), (PRINCIPLE, "Principle"), (TEACHER, "Teacher"), (STUDENT, "Student"), ) status = ArrayField( models.IntegerField(choices=USER_LEVEL_CHOICES, blank=True, default=STUDENT), )

Pero hay que tener una reflexión más amplia.


Creo que estás hablando de dos problemas separados: polimorfismo y permisos .

  • Polimorfismo :

El polimorfismo es la capacidad de un objeto para adoptar muchas formas. Para un modelo Django, se puede hacer con muchas estrategias: OneToOneField -como mencionaste- herencia de tablas múltiples , modelos abstractos o modelos proxy .

Muy buenos recursos: este artículo y el documento de Django sobre la herencia del modelo .

Este problema muy complejo se refiere a: en qué medida sus diversas formas de una misma entidad son similares o diferentes. Y qué operaciones son particularmente similares o diferentes (forma de datos, consultas, permisos, etc.)

  • Diseño de permisos :

Puedes elegir entre varios estampados

  • Permiso orientado al modelo : un usuario tiene permiso para "agregar", "ver", "editar" o "eliminar" a un Model . Esto se hace en Django con el modelo de Permission incorporado, que tiene una ForeignKey para ContentType
  • Permiso orientado a objetos : a un usuario se le otorga permiso para "agregar", "ver", "editar" o "eliminar" para cada instancia del Model . Algunos paquetes proporcionan esta capacidad, por ejemplo, django-guardian .
  • Permiso orientado a reglas : a un usuario se le otorga permiso para una instancia de modelo a través de una lógica personalizada en lugar de una tabla M2M. El paquete de rules de Django proporciona este tipo de arquitectura.
over 4 years ago · Santiago Trujillo Relatório

0

Puede crear desde AbstractUser (un modelo de usuario completo, completo con campos, incluidos is_superuser y is_staff) un perfil y luego, una vez que tenga el perfil, dar la oportunidad a los usuarios de crear otro tipo de perfil (Estudiante, Profesor o Principio) que podría tener funcionalidades propias.

Por ejemplo, en sus modelos.py

 class Profiles(AbstractUser): date_of_birth = models.DateField(max_length=128, blank=True, null=True, default=None, verbose_name=_(u'Date of birth')) principle = models.OneToOneField(Principles, null=True, blank=True, verbose_name=_(u'Principles'), on_delete=models.CASCADE) teacher = models.OneToOneField(Teachers, null=True, blank=True, verbose_name=_(u'Teachers'), on_delete=models.CASCADE) student = models.OneToOneField(Students, null=True, blank=True, verbose_name=_(u'Students'), on_delete=models.CASCADE) class Meta: db_table = 'profiles' verbose_name = _('Profile') verbose_name_plural = _('Profiles')

A ese modelo puede agregar métodos de clase, como

 def is_teacher(self): if self.teacher: return True else: return False

Entonces, su modelo de Profesores podría verse así

 class Teachers(models.Model): image = models.FileField(upload_to=UploadToPathAndRename(settings.TEACHERS_IMAGES_DIR), blank=True, null=True, verbose_name=_('Teacher logo')) name = models.CharField(blank=False, null=False, default=None, max_length=255, validators=[MaxLengthValidator(255)], verbose_name=_('Name')) street = models.CharField( max_length=128, blank=False, null=True, default=None, verbose_name=_('Street')) created_by = models.ForeignKey('Profiles', null=True, blank=True, on_delete=models.SET_NULL)
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda