Вопрос дизайна Django: расширение User, чтобы пользователи, которые не могут войти - PullRequest
3 голосов
/ 02 мая 2010

Сайт, над которым я работаю, включает учителей, создающих объекты учеников. Учитель может сделать так, чтобы ученик мог войти на сайт (проверить календари и т. Д.), ИЛИ учитель может использовать объект ученика только для ведения учета и не разрешать ученику войти в систему. При создании ученика Если учитель вводит имя пользователя и пароль, он должен создать объект первого типа - тот, который может войти в систему, то есть обычный объект пользователя. Если учитель не предоставляет имя пользователя / пароль, он должен создать второй тип. Другое требование состоит в том, что учитель должен быть в состоянии прийти позже и сменить учащегося, не входящего в систему, на другой вид. Каков наилучший способ дизайна для этого сценария? Подкласс пользователя и сделать имя пользователя и пароль не требуется? На что еще это повлияет?

Edit: В итоге я использовал User.set_unusable_password (). Вот код - я пропустил другие формы и т. Д., Которые я также использую в моем представлении:

Форма

class StudentForm(forms.ModelForm):
    username = forms.RegexField(regex=r'^\w+$',
                                required=False,
                                max_length=30,
                                label=("Username"),
                                error_messages={ 'invalid': ("This value must contain only letters, numbers and underscores.") })
    password = forms.CharField(widget=forms.PasswordInput(),
                                    label="Password", required=False)

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'username', 'email', 'password')

Обратите внимание, что имя пользователя и пароль не требуются в форме.

View

def create_student(request):
    if request.method == "POST":
        student_form = StudentForm(request.POST)
        if student_form.is_valid():
            user = student_form.save(commit=False)
            if student_form.cleaned_data['username'] == '':
                user.username = generate_random_username()
                user.set_unusable_password()
            else:
                user.set_password(user.password)
            user.save()

            return HttpResponseRedirect(reverse('student_list', args=['active']))

    #GET an empty form
    else:
        student_form = StudentForm()

return render_to_response('priviostudio/create_student.html', {
    'student_form': student_form,
})

И для редактирования студента (который, вероятно, будет объединен с представлением create_student) у меня есть это для GET:

student_form_initial = {
        'username': user_instance.username if user_instance.has_usable_password() else '',
        'password': user_instance.password if user_instance.has_usable_password() else '',
    }
    student_form = StudentForm(instance=user_instance, initial=student_form_initial)

А в POST, если учитель отправит новое имя пользователя и действительный пароль, я просто установлю их в экземпляре User.

Спасибо за идеи всем.

Ответы [ 4 ]

3 голосов
/ 02 мая 2010

Модель User приложения авторизации имеет метод set_unusable_password; это, вероятно, делает то, что вы хотите, не требуя расширения модели.

2 голосов
/ 02 мая 2010

Модель пользователя по умолчанию в Django имеет поле is_active.

http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.models.User.is_active

Вы, вероятно, хотите использовать это.

Таким образом, когда учитель решит, что хочет, чтобы пользователь мог войти в систему, ваш код просто установит для пользователя учащегося значение is_active = True и наоборот.

Кроме того, в соответствии со ссылкой на документацию выше, в форме аутентификации Django и методах разрешения по умолчанию проверьте флаг is_active, так что это часть работы, которую вы уже сделали.

Возможно, вам также понадобится сгенерировать имя пользователя для студента, но вы можете легко сделать это, используя слаг из имени, если это предусмотрено.

Самый очевидный способ для меня отличить учеников от учителей - это действительно группы, и Django также предоставляет механизмы для этого.

1 голос
/ 02 мая 2010

Вы могли бы рассмотреть вопрос о том, чтобы сделать всех учеников одним видом объекта - не Пользователь - и затем дополнить эту модель пользовательскими объектами, где учитель позволил учащемуся войти в систему. Композиция этих двух объектов модели могла бы решить, что вы хотите достаточно чисто .

0 голосов
/ 02 мая 2010

Я бы не хотел создавать подклассы пользователя. Вместо этого вы можете захотеть создать собственный аутентификатор, который позволит вам проверять членство в группе для возможности входа в систему.

"""
DummyBackend.py

"""

from django.contrib.auth.models import User, check_password
from django.contrib.auth.backends import RemoteUserBackend
from lecture_feedback.daily.models import Student
class DummyBackend(RemoteUserBackend):
    """
    Dummy authentication module that takes a username and password. The password must match the username.
    """

    def authenticate(self, username=None, password=None):
        """
        The username passed as ``remote_user`` is considered trusted.  This
        method simply returns the ``User`` object with the given username,
        creating a new ``User`` object if ``create_unknown_user`` is ``True``.

        Returns None if ``create_unknown_user`` is ``False`` and a ``User``
        object with the given username is not found in the database.

        """

        try:
            student = Student.objects.get(globalid=username)
        except Student.DoesNotExist:
            return None

        if username != password:
            return
        user = None

        # Note that this could be accomplished in one try-except clause, but
        # instead we use get_or_create when creating unknown users since it has
        # built-in safeguards for multiple threads.
        if self.create_unknown_user:
            user, created = User.objects.get_or_create(username=username)
            if created:
                user = self.configure_user(user)
        else:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                pass
        return user


    def configure_user(self, user):
         """
         Configures a user after creation and returns the updated user.

         By default, returns the user unmodified.
         """
         student = Student.objects.get(globalid=user.username)
         user.first_name = student.first_name
         user.last_name = student.last_name
         return user

Модель Студента может содержать поле, которое указывает, разрешено ли студенту входить в систему. Также взгляните на http://docs.djangoproject.com/en/dev/howto/auth-remote-user/#attributes.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...