Есть ли хороший способ сделать это в django без развертывания моей собственной системы аутентификации? Я хочу, чтобы имя пользователя было адресом электронной почты пользователя, а не создавало имя пользователя.
Пожалуйста, посоветуйте, спасибо.
python
django
authentication
Деймон
источник
источник
Ответы:
Для всех, кто хочет это сделать, я бы порекомендовал взглянуть на django-email-as-username, которое является довольно комплексным решением, которое включает исправление администратора и
createsuperuser
команд управления, среди прочего.Изменить : начиная с Django 1.5 и далее вам следует рассмотреть возможность использования пользовательской модели вместо django-email-as-username .
источник
Вот что мы делаем. Это не «полное» решение, но оно делает многое из того, что вы ищете.
from django import forms from django.contrib import admin from django.contrib.auth.admin import UserAdmin from django.contrib.auth.models import User class UserForm(forms.ModelForm): class Meta: model = User exclude = ('email',) username = forms.EmailField(max_length=64, help_text="The person's email address.") def clean_email(self): email = self.cleaned_data['username'] return email class UserAdmin(UserAdmin): form = UserForm list_display = ('email', 'first_name', 'last_name', 'is_staff') list_filter = ('is_staff',) search_fields = ('email',) admin.site.unregister(User) admin.site.register(User, UserAdmin)
источник
Вот один из способов сделать это, чтобы принимались и имя пользователя, и адрес электронной почты:
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from django.forms import ValidationError class EmailAuthenticationForm(AuthenticationForm): def clean_username(self): username = self.data['username'] if '@' in username: try: username = User.objects.get(email=username).username except ObjectDoesNotExist: raise ValidationError( self.error_messages['invalid_login'], code='invalid_login', params={'username':self.username_field.verbose_name}, ) return username
Не знаю, есть ли какой-то параметр для установки формы аутентификации по умолчанию, но вы также можете переопределить URL-адрес в urls.py
url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),
Повышение ValidationError предотвратит 500 ошибок при отправке недопустимого электронного письма. Использование определения super для «invalid_login» делает сообщение об ошибке неоднозначным (по сравнению с конкретным «ни один пользователь по этому адресу электронной почты не обнаружен»), что необходимо для предотвращения утечки информации о том, зарегистрирован ли адрес электронной почты для учетной записи в вашей службе. Если эта информация небезопасна в вашей архитектуре, было бы удобнее иметь более информативное сообщение об ошибке.
источник
Django теперь предоставляет полный пример расширенной системы аутентификации с администратором и формой: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example
Вы можете скопировать / вставить и адаптировать (мне не нужен
date_of_birth
в моем случае ).Фактически он доступен с Django 1.5 и все еще доступен сейчас (django 1.7).
источник
Если вы собираетесь расширить модель пользователя, вам все равно придется реализовать собственную модель пользователя.
Вот пример для Django 1.8. Django 1.7 потребует немного больше работы, в основном для изменения форм по умолчанию (просто взгляните на
UserChangeForm
&UserCreationForm
indjango.contrib.auth.forms
- это то, что вам нужно в 1.7).user_manager.py:
from django.contrib.auth.models import BaseUserManager from django.utils import timezone class SiteUserManager(BaseUserManager): def create_user(self, email, password=None, **extra_fields): today = timezone.now() if not email: raise ValueError('The given email address must be set') email = SiteUserManager.normalize_email(email) user = self.model(email=email, is_staff=False, is_active=True, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, password, **extra_fields): u = self.create_user(email, password, **extra_fields) u.is_staff = True u.is_active = True u.is_superuser = True u.save(using=self._db) return u
models.py:
from mainsite.user_manager import SiteUserManager from django.contrib.auth.models import AbstractBaseUser from django.contrib.auth.models import PermissionsMixin class SiteUser(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True, blank=False) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) is_staff = models.BooleanField(default=False) USERNAME_FIELD = 'email' objects = SiteUserManager() def get_full_name(self): return self.email def get_short_name(self): return self.email
forms.py:
from django.contrib import admin from django.contrib.auth.admin import UserAdmin from django.contrib.auth.forms import UserChangeForm, UserCreationForm from mainsite.models import SiteUser class MyUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): model = SiteUser fields = ("email",) class MyUserChangeForm(UserChangeForm): class Meta(UserChangeForm.Meta): model = SiteUser class MyUserAdmin(UserAdmin): form = MyUserChangeForm add_form = MyUserCreationForm fieldsets = ( (None, {'fields': ('email', 'password',)}), ('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',)}), ('Groups', {'fields': ('groups', 'user_permissions',)}), ) add_fieldsets = ( (None, { 'classes': ('wide',), 'fields': ('email', 'password1', 'password2')} ), ) list_display = ('email', ) list_filter = ('is_active', ) search_fields = ('email',) ordering = ('email',) admin.site.register(SiteUser, MyUserAdmin)
settings.py:
AUTH_USER_MODEL = 'mainsite.SiteUser'
источник
username
поле вSiteUser
модель, потому что, когда я выполняюpython manage.py makemigrations ...
команду, я получаю следующий результат:ERRORS: <class 'accounts.admin.UserAdmin'>: (admin.E033) The value of 'ordering[0]' refers to 'username', which is not an attribute of 'accounts.User'.
username
поле в своюUser
модель с ихnull=True
атрибутом. В этой записи бункера для вставки я действительно хотел показать реализацию. pastebin.com/W1PgLrD9Другие альтернативы кажутся мне слишком сложными, поэтому я написал фрагмент, который позволяет аутентифицироваться с использованием имени пользователя, электронной почты или того и другого, а также включать или отключать регистр. Я загрузил его в pip как django-dual-authentication .
from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model from django.conf import settings ################################### """ DEFAULT SETTINGS + ALIAS """ ################################### try: am = settings.AUTHENTICATION_METHOD except: am = 'both' try: cs = settings.AUTHENTICATION_CASE_SENSITIVE except: cs = 'both' ##################### """ EXCEPTIONS """ ##################### VALID_AM = ['username', 'email', 'both'] VALID_CS = ['username', 'email', 'both', 'none'] if (am not in VALID_AM): raise Exception("Invalid value for AUTHENTICATION_METHOD in project " "settings. Use 'username','email', or 'both'.") if (cs not in VALID_CS): raise Exception("Invalid value for AUTHENTICATION_CASE_SENSITIVE in project " "settings. Use 'username','email', 'both' or 'none'.") ############################ """ OVERRIDDEN METHODS """ ############################ class DualAuthentication(ModelBackend): """ This is a ModelBacked that allows authentication with either a username or an email address. """ def authenticate(self, username=None, password=None): UserModel = get_user_model() try: if ((am == 'email') or (am == 'both')): if ((cs == 'email') or cs == 'both'): kwargs = {'email': username} else: kwargs = {'email__iexact': username} user = UserModel.objects.get(**kwargs) else: raise except: if ((am == 'username') or (am == 'both')): if ((cs == 'username') or cs == 'both'): kwargs = {'username': username} else: kwargs = {'username__iexact': username} user = UserModel.objects.get(**kwargs) finally: try: if user.check_password(password): return user except: # Run the default password hasher once to reduce the timing # difference between an existing and a non-existing user. UserModel().set_password(password) return None def get_user(self, username): UserModel = get_user_model() try: return UserModel.objects.get(pk=username) except UserModel.DoesNotExist: return None
источник
Последняя версия django-registration допускает некоторую приятную настройку и может сработать - документы здесь https://bitbucket.org/ubernostrum/django-registration/src/fad7080fe769/docs/backend-api.rst
источник
if user_form.is_valid(): # Save the user's form data to a user object without committing. user = user_form.save(commit=False) user.set_password(user.password) #Set username of user as the email user.username = user.email #commit user.save()
отлично работает ... для django 1.11.4
источник
вы также можете найти интересное обсуждение этой темы по ссылке ниже:
http://groups.google.com/group/django-users/browse_thread/thread/c943ede66e6807c/2fbf2afeade397eb#2fbf2afeade397eb
источник
Самый простой способ - найти имя пользователя по электронной почте в окне входа в систему. Таким образом, вы можете оставить все остальное в покое:
from django.contrib.auth import authenticate, login as auth_login def _is_valid_email(email): from django.core.validators import validate_email from django.core.exceptions import ValidationError try: validate_email(email) return True except ValidationError: return False def login(request): next = request.GET.get('next', '/') if request.method == 'POST': username = request.POST['username'].lower() # case insensitivity password = request.POST['password'] if _is_valid_email(username): try: username = User.objects.filter(email=username).values_list('username', flat=True) except User.DoesNotExist: username = None kwargs = {'username': username, 'password': password} user = authenticate(**kwargs) if user is not None: if user.is_active: auth_login(request, user) return redirect(next or '/') else: messages.info(request, "<stvrong>Error</strong> User account has not been activated..") else: messages.info(request, "<strong>Error</strong> Username or password was incorrect.") return render_to_response('accounts/login.html', {}, context_instance=RequestContext(request))
В вашем шаблоне установите следующую переменную соответственно, т.е.
<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">
И дайте вашему логину / паролю входы правильные имена, то есть имя пользователя, пароль.
ОБНОВЛЕНИЕ :
В качестве альтернативы вызов if _is_valid_email (email): можно заменить на if '@' в имени пользователя. Таким образом вы можете отказаться от функции _is_valid_email. Это действительно зависит от того, как вы определяете свое имя пользователя. Это не сработает, если вы разрешите использовать символ «@» в своих именах пользователей.
источник
Я думаю, что самый быстрый способ - создать форму, унаследованную от
UserCreateForm
, а затем переопределитьusername
поле с помощьюforms.EmailField
. Затем для каждого нового зарегистрированного пользователя им необходимо войти в систему со своим адресом электронной почты.Например:
urls.py
... urlpatterns += url(r'^signon/$', SignonView.as_view(), name="signon")
views.py
from django.contrib.auth.models import User from django.contrib.auth.forms import UserCreationForm from django import forms class UserSignonForm(UserCreationForm): username = forms.EmailField() class SignonView(CreateView): template_name = "registration/signon.html" model = User form_class = UserSignonForm
signon.html
... <form action="#" method="post"> ... <input type="email" name="username" /> ... </form> ...
источник
UserCreationForm
классе? И, пожалуйста, не рекомендую выписывать,<input …
когда, конечно,{{form.username}}
лучше.Не уверен, что люди пытаются это сделать, но я нашел хороший (и чистый) способ только запросить электронную почту, а затем установить имя пользователя в качестве адреса электронной почты в представлении перед сохранением.
My UserForm требует только адрес электронной почты и пароль:
class UserForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput()) class Meta: model = User fields = ('email', 'password')
Затем, на мой взгляд, я добавляю следующую логику:
if user_form.is_valid(): # Save the user's form data to a user object without committing. user = user_form.save(commit=False) user.set_password(user.password) #Set username of user as the email user.username = user.email #commit user.save()
источник