Commit 8b183733 authored by Isataev Adlet's avatar Isataev Adlet

Создал приложение для accounts. Создал модель для профайла, форму. Создал…

Создал приложение для accounts. Создал модель для профайла, форму. Создал шаблоны, вьюхи и пути для Регистрации, Авторизации, Входа, Выхода, детального просмотра аккаунта, смена пароля и редактирования профиля
parent dfad726e
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth import get_user_model
from accounts.models import Profile, Gender
class ProfileInline(admin.StackedInline):
model = Profile
fields = ["birth_date", "phone_number", "gender"]
class ProfileAdmin(UserAdmin):
inlines = [ProfileInline]
User = get_user_model()
admin.site.register(Gender)
admin.site.unregister(User)
admin.site.register(User, ProfileAdmin)
from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'accounts'
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from accounts.models import Profile
class RegistrationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
fields = ["username", "first_name",
"last_name", "email", "password1", "password2"]
class UserChangeForm(forms.ModelForm):
class Meta:
model = get_user_model()
fields = ["first_name", "last_name", "email"]
labels = {"first_name": "Name", "last_name": "Surname", "email": "Email"}
class ProfileChangeForm(forms.ModelForm):
class Meta:
model = Profile
exclude = ["user"]
class PasswordChangeForm(forms.ModelForm):
old_password = forms.CharField(label="Old password", strip=False,
widget=forms.PasswordInput)
password = forms.CharField(label="Password", strip=False,
widget=forms.PasswordInput)
password_confirm = forms.CharField(label="Confirm password", strip=False,
widget=forms.PasswordInput)
def clean_password_confirm(self):
password = self.cleaned_data["password"]
password_confirm = self.cleaned_data["password_confirm"]
if password and password_confirm and password != password_confirm:
raise forms.ValidationError("Passwords are not equal")
return password_confirm
def clean_old_password(self):
old_password = self.cleaned_data["old_password"]
if not self.instance.check_password(old_password):
raise forms.ValidationError("Wrong old password")
return old_password
def save(self, commit=True):
user = self.instance
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
class Meta:
model = get_user_model()
fields = ["old_password", "password", "password_confirm"]
\ No newline at end of file
# Generated by Django 3.2.9 on 2021-11-03 12:10
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Gender',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=15, verbose_name='Пол')),
],
),
migrations.CreateModel(
name='Profile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('birth_date', models.DateField(verbose_name='Дата рождения')),
('phone_number', models.CharField(max_length=25, verbose_name='Номер телефона')),
('gender', models.ForeignKey(default='None', on_delete=django.db.models.deletion.SET_DEFAULT, to='accounts.gender', verbose_name='Пол пользователя')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL, verbose_name='Пользователь')),
],
),
]
# Generated by Django 3.2.9 on 2021-11-03 12:48
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('accounts', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='gender',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='accounts.gender', verbose_name='Пол пользователя'),
),
]
# Generated by Django 3.2.9 on 2021-11-03 12:50
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('accounts', '0002_alter_profile_gender'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='birth_date',
field=models.DateField(blank=True, null=True, verbose_name='Дата рождения'),
),
migrations.AlterField(
model_name='profile',
name='gender',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='accounts.gender', verbose_name='Пол пользователя'),
),
migrations.AlterField(
model_name='profile',
name='phone_number',
field=models.CharField(blank=True, max_length=25, null=True, verbose_name='Номер телефона'),
),
]
from django.db import models
from django.contrib.auth import get_user_model
class Gender(models.Model):
name = models.CharField(max_length=15, verbose_name="Пол")
def __str__(self):
return f'{self.name}'
class Profile(models.Model):
user = models.OneToOneField(get_user_model(), related_name="profile", on_delete=models.CASCADE,
verbose_name="Пользователь")
birth_date = models.DateField(null=True, blank=True, verbose_name="Дата рождения")
phone_number = models.CharField(null=True, blank=True, max_length=25, verbose_name="Номер телефона")
gender = models.ForeignKey(Gender, null=True, blank=True, on_delete=models.PROTECT, verbose_name="Пол пользователя")
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% block title %}Изменить пароль{% endblock %}
{% block content %}
<h1>Изменить пароль {{ user_obj.username }}</h1>
<form action="{% url "change_password" user_obj.pk %}" method="post">
{% csrf_token %}
{{ form|crispy }}
<button>Изменить</button>
</form>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% block title %}Edit {{ user_obj.username }}{% endblock %}
{% block content %}
<h1>Редактирование профиля</h1>
<form
action="{% url "edit_profile" user_obj.pk %}"
method="post"
>
{% csrf_token %}
{{ user_form|crispy }}
{{ profile_form|crispy }}
<button>Редактировать</button>
</form>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block content %}
<h1>Вход</h1>
<form action="{% url "login" %}" method="post">
{% csrf_token %}
{% if has_error %}
<p>Wrong username or password</p>
{% endif %}
<p><input type="text" name="username" placeholder="Username"></p>
<p><input type="password" name="password" placeholder="Password"></p>
<input type="hidden" name="next" value="{{ request.GET.next }}">
<button>Войти</button>
</form>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% block title %}Register{% endblock %}
{% block content %}
<form action="{% url "register" %}" method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary">Регистрация</button>
</form>
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% block title %}User {{ user_obj.username }}{% endblock %}
{% block content %}
<h1>Профиль {{ user_obj.username }}</h1>
{% ifequal user user_obj %}
<p>
<a href="{% url "edit_profile" user_obj.pk %}">
Edit account
</a>
<a href="{% url "change_password" user_obj.pk %}">
Change password
</a>
</p>
{% endifequal %}
<p>Username: {{ user_obj.username }}</p>
<p>First name: {{ user_obj.first_name }}</p>
<p>Last name: {{ user_obj.last_name }}</p>
<p>Date of birth: {{ user_obj.profile.birth_date }}</p>
{% endblock %}
\ No newline at end of file
from django.test import TestCase
# Create your tests here.
from django.conf import settings
from django.contrib.auth import login, authenticate, logout, get_user_model, update_session_auth_hash
from django.contrib.auth.mixins import UserPassesTestMixin
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from django.views.generic import CreateView, DetailView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from accounts.forms import RegistrationForm, ProfileChangeForm, UserChangeForm, PasswordChangeForm
from accounts.models import Profile
class LoginView(View):
def get(self, request, *args, **kwargs):
return render(request, "registration/login.html")
def post(self, request, *args, **kwargs):
username = request.POST.get("username")
password = request.POST.get("password")
next_path = request.POST.get("next")
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
if next_path:
return HttpResponseRedirect(next_path)
return redirect(settings.LOGIN_REDIRECT_URL)
return render(request, "registration/login.html", {"has_error": True})
class LogoutView(View):
def post(self, request, *args, **kwargs):
logout(request)
return redirect(settings.LOGOUT_REDIRECT_URL)
class RegisterView(CreateView):
model = User
template_name = "registration/register.html"
form_class = RegistrationForm
def form_valid(self, form):
user = form.save()
Profile.objects.create(user=user)
login(self.request, user)
return redirect("index")
class UserDetailView(DetailView):
model = get_user_model()
template_name = "user_detail.html"
context_object_name = "user_obj"
# class ChangeProfileAccessMixin(UserPassesTestMixin):
# def test_func(self):
# return self.request.user == self.get_object() or \
# self.request.user.is_superuser or self.request.user.groups.filter(name="admins")
class UserChangeView(UpdateView):
model = get_user_model()
form_class = UserChangeForm
template_name = "edit_profile.html"
context_object_name = "user_obj"
def get_profile_form(self):
form_kwargs = {"instance": self.object.profile}
if self.request.method == "POST":
form_kwargs["data"] = self.request.POST
form_kwargs["files"] = self.request.FILES
return ProfileChangeForm(**form_kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
user_form = self.get_form()
profile_form = self.get_profile_form()
if user_form.is_valid() and profile_form.is_valid():
return self.form_valid(user_form, profile_form)
else:
return self.form_invalid(user_form, profile_form)
def form_valid(self, user_form, profile_form):
result = super().form_valid(user_form)
profile_form.save()
return result
def form_invalid(self, user_form, profile_form):
context = self.get_context_data(
user_form=user_form,
profile_form=profile_form
)
return self.render_to_response(context)
def get_context_data(self, **kwargs):
if "profile_form" not in kwargs:
kwargs["profile_form"] = self.get_profile_form()
kwargs["user_form"] = self.get_form()
return super().get_context_data(**kwargs)
def get_success_url(self):
return reverse("profile", kwargs={"pk": self.object.pk})
class ChangePasswordView(LoginRequiredMixin, UpdateView):
model = get_user_model()
form_class = PasswordChangeForm
template_name = "change_password.html"
context_object_name = "user_obj"
def form_valid(self, form):
form.save()
update_session_auth_hash(self.request, form.instance)
return redirect("profile", pk=self.get_object().pk)
......@@ -38,6 +38,7 @@ INSTALLED_APPS = [
'django.contrib.messages',
'django.contrib.staticfiles',
'webapp',
'accounts',
'crispy_forms'
]
......@@ -128,5 +129,9 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
CRISPY_TEMPLATE_PACK = 'bootstrap4'
LOGIN_URL = "login"
LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/"
MEDIA_ROOT = os.path.join(BASE_DIR, "uploads")
MEDIA_URL = "/uploads/"
......@@ -18,9 +18,16 @@ from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
from webapp import views as webapp_views
from accounts import views as accounts_views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', accounts_views.LoginView.as_view(), name="login"),
path('logout/', accounts_views.LogoutView.as_view(), name="logout"),
path('create/', accounts_views.RegisterView.as_view(), name="register"),
path("<int:pk>/", accounts_views.UserDetailView.as_view(), name="profile"),
path("<int:pk>/edit/", accounts_views.UserChangeView.as_view(), name="edit_profile"),
path("<int:pk>/change-password/", accounts_views.ChangePasswordView.as_view(), name="change_password"),
path("", webapp_views.index_view, name="index"),
path("events/", webapp_views.EventView.as_view(), name="list_events"),
path("events/create/", webapp_views.EventCreateView.as_view(), name="create_events"),
......
......@@ -25,15 +25,25 @@
<li class="nav-item">
<a class="nav-link" href="{% url 'create_events' %}">Создать мероприятие</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Редактировать профиль</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Войти</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Регистрация</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item">
<form action="{% url "logout" %}" method="post">
{% csrf_token %}
<button class="btn btn-sm btn-primary">Выйти</button>
</form>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url "profile" user.pk %}">Привет, {{ user.username }}</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url "login" %}?next={{ request.get_full_path }}">Войти</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url "register" %}?next={{ request.get_full_path }}">Регистрация</a>
</li>
{% endif %}
</ul>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment