Commit 23744ea8 authored by Давид Ли's avatar Давид Ли

lesson 54

parent 3dea0324
from django.contrib import admin from django.contrib import admin
from accounts.models import User
# Register your models here. # Register your models here.
admin.site.register(User)
from django import forms from django import forms
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth import password_validation
from accounts.models import User
class LoginForm(AuthenticationForm): class LoginForm(AuthenticationForm):
...@@ -19,3 +22,41 @@ class LoginForm(AuthenticationForm): ...@@ -19,3 +22,41 @@ class LoginForm(AuthenticationForm):
} }
) )
) )
class RegisterForm(UserCreationForm):
password1 = forms.CharField(
label="Password",
strip=False,
widget=forms.PasswordInput(
attrs={
'autocomplete': 'new-password',
'class': 'form-control mb-3'
}
),
help_text=password_validation.password_validators_help_text_html(),
)
password2 = forms.CharField(
label="Password confirmation",
widget=forms.PasswordInput(
attrs={
'autocomplete': 'new-password',
'class': 'form-control mb-3'
}
),
strip=False,
help_text="Enter the same password as before, for verification.",
)
class Meta(UserCreationForm.Meta):
model = User
fields = [
'username', 'first_name', 'last_name',
'email', 'password1', 'password2'
]
widgets = {
'username': forms.TextInput(attrs={'class': 'form-control mb-3'}),
'first_name': forms.TextInput(attrs={'class': 'form-control mb-3'}),
'last_name': forms.TextInput(attrs={'class': 'form-control mb-3'}),
'email': forms.EmailInput(attrs={'class': 'form-control mb-3'}),
}
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<form action="{% url 'login' %}" method="post"> <form action="{% url 'login' %}?next={{ request.GET.next }}" method="post">
{% csrf_token %} {% csrf_token %}
{% include 'partial/form.html' with button_text='Login' %} {% include 'partial/form.html' with button_text='Login' %}
</form> </form>
......
{% extends 'base.html' %}
{% block title %}
<h1 class="text-center my-3">Registration</h1>
{% endblock %}
{% block content %}
<form action="{% url 'register' %}?next={{ request.GET.next }}" method="post">
{% csrf_token %}
{% include 'partial/form.html' with button_text='Register' %}
</form>
{% endblock %}
from django.urls import path
from accounts import views
urlpatterns = [
path('login/', views.LoginView.as_view(), name='login'),
path('logout/', views.LogoutView.as_view(), name='logout'),
path('register/', views.RegisterView.as_view(), name='register')
]
from django.contrib.auth import views, login
from django.views.generic import CreateView
from django.shortcuts import redirect
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.contrib.auth import views
from accounts.forms import LoginForm from accounts.forms import LoginForm, RegisterForm
from accounts.models import User
class LoginView(views.LoginView): class AuthSuccessUrlMixin:
def get_success_url(self):
return self.request.GET.get(
'next',
self.request.POST.get(
'next',
reverse_lazy('main_page')
)
)
class LoginView(AuthSuccessUrlMixin, views.LoginView):
template_name = 'login.html' template_name = 'login.html'
form_class = LoginForm form_class = LoginForm
class LogoutView(views.LogoutView): class LogoutView(views.LogoutView):
pass def get_next_page(self):
return self.request.META.get('HTTP_REFERER')
class RegisterView(AuthSuccessUrlMixin, CreateView):
model = User
template_name = 'registration.html'
form_class = RegisterForm
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect(self.get_success_url())
...@@ -142,5 +142,5 @@ SHELL_PLUS = "bpython" ...@@ -142,5 +142,5 @@ SHELL_PLUS = "bpython"
AUTH_USER_MODEL = 'accounts.User' AUTH_USER_MODEL = 'accounts.User'
LOGIN_URL = 'login' LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'main_page' # LOGIN_REDIRECT_URL = 'main_page'
LOGOUT_REDIRECT_URL = 'main_page' # LOGOUT_REDIRECT_URL = 'main_page'
...@@ -16,37 +16,14 @@ Including another URLconf ...@@ -16,37 +16,14 @@ Including another URLconf
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.urls import path from django.urls import path, include
from web import views from web import views
from accounts import views as accounts_views
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('', views.MainPageRedirectView.as_view()), path('', views.MainPageRedirectView.as_view()),
path('', include('web.urls')),
path('auth/login/', accounts_views.LoginView.as_view(), name='login'), path('auth/', include('accounts.urls'))
path('auth/logout/', accounts_views.LogoutView.as_view(), name='logout'),
path('articles/', views.ArticleIndexView.as_view(), name='main_page'),
path('articles/add/', views.ArticleCreateView.as_view(), name='articles-add'),
path('articles/<int:id>/', views.ArticleDetailView.as_view(), name='articles-detail'),
path('articles/<int:id>/edit', views.ArticleUpdateView.as_view(), name='article_update'),
path('articles/<int:id>/delete', views.ArticleDeleteView.as_view(), name='delete_article'),
path(
'articles/article_id/comments/add/',
views.CommentCreateView.as_view(),
name='comment_create'
),
path(
'comments/<int:id>/edit',
views.CommentUpdateView.as_view(),
name='comment_update'
),
path(
'comments/<int:id>/delete',
views.CommentDeleteView.as_view(),
name='comment_delete'
),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
[
{
"model": "web.article",
"pk": 1,
"fields": {
"title": "fjdsgbafdgjkafgbjaf",
"status": "check",
"text": "gadpfgkadfnglndafgafd",
"author": 1,
"created_at": "2023-07-27T11:40:39.768Z",
"updated_at": "2023-07-27T11:40:39.768Z",
"tags": []
}
},
{
"model": "web.article",
"pk": 2,
"fields": {
"title": "fasdffdasgas",
"status": "check",
"text": "asdfsadfasdfsadf",
"author": 5,
"created_at": "2023-07-27T11:40:56.056Z",
"updated_at": "2023-07-27T11:50:41.848Z",
"tags": []
}
},
{
"model": "web.comment",
"pk": 1,
"fields": {
"article": 2,
"text": "dfadfasdfasdf",
"author": 5,
"created_at": "2023-07-27T11:42:42.869Z",
"updated_at": "2023-07-27T11:42:42.869Z"
}
},
{
"model": "web.comment",
"pk": 2,
"fields": {
"article": 2,
"text": "dfsafdsafasdfsadf",
"author": 5,
"created_at": "2023-07-27T11:42:45.916Z",
"updated_at": "2023-07-27T11:42:45.916Z"
}
},
{
"model": "web.comment",
"pk": 3,
"fields": {
"article": 2,
"text": "fsadfasdfsadfsadfsadfdasf",
"author": 5,
"created_at": "2023-07-27T11:42:48.064Z",
"updated_at": "2023-07-27T11:42:48.064Z"
}
},
{
"model": "web.comment",
"pk": 4,
"fields": {
"article": 2,
"text": "dfasfsagadsg",
"author": 5,
"created_at": "2023-07-27T11:44:47.632Z",
"updated_at": "2023-07-27T11:44:47.632Z"
}
}
]
...@@ -18,7 +18,7 @@ class ArticleModelForm(forms.ModelForm): ...@@ -18,7 +18,7 @@ class ArticleModelForm(forms.ModelForm):
fields = ('title', 'author', 'status', 'text', 'tags') fields = ('title', 'author', 'status', 'text', 'tags')
widgets = { widgets = {
'title': forms.TextInput(attrs={'class': 'form-control mb-3'}), 'title': forms.TextInput(attrs={'class': 'form-control mb-3'}),
'author': forms.TextInput(attrs={'class': 'form-control mb-3'}), 'author': forms.HiddenInput(attrs={'class': 'form-control mb-3'}),
'status': forms.Select(attrs={'class': 'form-select mb-3'}), 'status': forms.Select(attrs={'class': 'form-select mb-3'}),
'text': forms.Textarea(attrs={'class': 'form-control mb-3'}), 'text': forms.Textarea(attrs={'class': 'form-control mb-3'}),
'tags': forms.CheckboxSelectMultiple(attrs={'class': 'mb-3'}) 'tags': forms.CheckboxSelectMultiple(attrs={'class': 'mb-3'})
...@@ -38,7 +38,7 @@ class CommentModelForm(forms.ModelForm): ...@@ -38,7 +38,7 @@ class CommentModelForm(forms.ModelForm):
fields = ['author', 'text', 'article'] fields = ['author', 'text', 'article']
widgets = { widgets = {
'text': forms.TextInput(attrs={'class': 'form-control mb-3'}), 'text': forms.TextInput(attrs={'class': 'form-control mb-3'}),
'author': forms.TextInput(attrs={'class': 'form-control mb-3'}), 'author': forms.HiddenInput(attrs={'class': 'form-control mb-3'}),
'article': forms.HiddenInput() 'article': forms.HiddenInput()
} }
......
# Generated by Django 3.2.19 on 2023-07-27 11:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('web', '0013_alter_article_title'),
]
operations = [
migrations.AlterField(
model_name='article',
name='author',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='articles', to=settings.AUTH_USER_MODEL, verbose_name='Автор'),
),
migrations.AlterField(
model_name='comment',
name='author',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='comments', to=settings.AUTH_USER_MODEL, verbose_name='Автор'),
),
]
# Generated by Django 3.2.19 on 2023-07-27 11:54
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('web', '0014_auto_20230727_1734'),
]
operations = [
migrations.AlterModelOptions(
name='article',
options={'permissions': [('can_eat_pizza', 'Может съесть пиццу')], 'verbose_name': 'статью', 'verbose_name_plural': 'статьи'},
),
]
...@@ -38,11 +38,11 @@ class Article(models.Model): ...@@ -38,11 +38,11 @@ class Article(models.Model):
verbose_name='Текст' verbose_name='Текст'
) )
author = models.CharField( author = models.ForeignKey(
max_length=100, 'accounts.User',
null=False, on_delete=models.CASCADE,
blank=False, default=1,
default='Unknown', related_name='articles',
verbose_name='Автор' verbose_name='Автор'
) )
...@@ -59,6 +59,9 @@ class Article(models.Model): ...@@ -59,6 +59,9 @@ class Article(models.Model):
class Meta: class Meta:
verbose_name = 'статью' verbose_name = 'статью'
verbose_name_plural = 'статьи' verbose_name_plural = 'статьи'
permissions = [
('can_eat_pizza', 'Может съесть пиццу')
]
def __str__(self): def __str__(self):
return f'{self.author}: {self.title}' return f'{self.author}: {self.title}'
...@@ -12,11 +12,11 @@ class Comment(models.Model): ...@@ -12,11 +12,11 @@ class Comment(models.Model):
text = models.TextField(max_length=400, verbose_name='Текст') text = models.TextField(max_length=400, verbose_name='Текст')
author = models.CharField( author = models.ForeignKey(
max_length=40, 'accounts.User',
null=True, on_delete=models.CASCADE,
blank=True, default=1,
default='Аноним', related_name='comments',
verbose_name='Автор' verbose_name='Автор'
) )
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<form action="/articles/add/" method="post"> <form action="/articles/add/" method="post">
{% csrf_token %} {% csrf_token %}
{% include 'partial/form.html' with button_text='Create' %} {% include 'partial/form.html' with button_text='Create' %}
<input type="hidden" name="author" value="{{ request.user.id }}">
</form> </form>
{% endblock %} {% endblock %}
...@@ -25,7 +25,9 @@ ...@@ -25,7 +25,9 @@
<hr> <hr>
<a href="{% url 'article_update' article.pk %}" class="btn btn-primary mt-4 me-3">Edit</a> {% if perms.web.change_article or article.author == request.user %}
<a href="{% url 'article_update' article.pk %}" class="btn btn-primary mt-4 me-3">Edit</a>
{% endif %}
<form action="{% url 'delete_article' article.pk %}" method="POST" onsubmit="return confirm('Are you sure?')"> <form action="{% url 'delete_article' article.pk %}" method="POST" onsubmit="return confirm('Are you sure?')">
{% csrf_token %} {% csrf_token %}
<button class="btn btn-danger mt-4">Delete</button> <button class="btn btn-danger mt-4">Delete</button>
...@@ -39,6 +41,7 @@ ...@@ -39,6 +41,7 @@
{% csrf_token %} {% csrf_token %}
{% include 'partial/form.html' with button_text='add' %} {% include 'partial/form.html' with button_text='add' %}
<input type="hidden" name="article" value="{{ article.id }}"> <input type="hidden" name="article" value="{{ article.id }}">
<input type="hidden" name="author" value="{{ request.user.id }}">
</form> </form>
{% for comment in comments %} {% for comment in comments %}
...@@ -46,9 +49,11 @@ ...@@ -46,9 +49,11 @@
<div class="card-header d-flex justify-content-between"> <div class="card-header d-flex justify-content-between">
{{ comment.author }} {{ comment.author }}
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<a href="{% url 'comment_update' id=comment.id %}" class="me-5"> {% if perms.web.change_comment or request.user == comment.author %}
<i class="fa fa-regular fa-pen-to-square"></i> <a href="{% url 'comment_update' id=comment.id %}" class="me-5">
</a> <i class="fa fa-regular fa-pen-to-square"></i>
</a>
{% endif %}
<form action="{% url 'comment_delete' id=comment.id %}" method="POST" onsubmit="return confirm('Are you sure?')"> <form action="{% url 'comment_delete' id=comment.id %}" method="POST" onsubmit="return confirm('Are you sure?')">
{% csrf_token %} {% csrf_token %}
......
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
{% block content %} {% block content %}
<h1>Articles</h1> <h1>Articles</h1>
<a href="{% url 'articles-add' %}" class="btn btn-primary">Создать</a>
{% if perms.web.add_article %}
<a href="{% url 'articles-add' %}" class="btn btn-primary">Создать</a>
{% endif %}
{% include 'partial/search_form.html' %} {% include 'partial/search_form.html' %}
{% for article in articles %} {% for article in articles %}
<br> <br>
...@@ -12,13 +16,13 @@ ...@@ -12,13 +16,13 @@
<br> <br>
<h2>{{ article.title }}</h2> <h2>{{ article.title }}</h2>
{% if user.is_authenticated %} {# {% if user.is_authenticated %}#}
<p> <p>
<a href="{% url 'articles-detail' id=article.id %}"> <a href="{% url 'articles-detail' id=article.id %}">
Подробнее Подробнее
</a> </a>
</p> </p>
{% endif %} {# {% endif %}#}
<br> <br>
<hr> <hr>
<br> <br>
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
{% block content %} {% block content %}
<form action="{% url 'article_update' article.pk %}" method="post"> <form action="{% url 'article_update' article.pk %}" method="post">
{% csrf_token %}
{% include 'partial/form.html' with button_text='Update' abc='123' %} {% include 'partial/form.html' with button_text='Update' abc='123' %}
</form> </form>
{% endblock %} {% endblock %}
......
...@@ -56,7 +56,10 @@ ...@@ -56,7 +56,10 @@
{% else %} {% else %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'login' %}">Login</a> <a class="nav-link" href="{% url 'login' %}?next={{ request.get_full_path }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'register' %}?next={{ request.get_full_path }}">Register</a>
</li> </li>
{% endif %} {% endif %}
......
from django.urls import path
from web import views
urlpatterns = [
path('articles/', views.ArticleIndexView.as_view(), name='main_page'),
path('articles/add/', views.ArticleCreateView.as_view(), name='articles-add'),
path('articles/<int:id>/', views.ArticleDetailView.as_view(), name='articles-detail'),
path('articles/<int:id>/edit', views.ArticleUpdateView.as_view(), name='article_update'),
path('articles/<int:id>/delete', views.ArticleDeleteView.as_view(), name='delete_article'),
path(
'comments/add/',
views.CommentCreateView.as_view(),
name='comment_create'
),
path(
'comments/<int:id>/edit',
views.CommentUpdateView.as_view(),
name='comment_update'
),
path(
'comments/<int:id>/delete',
views.CommentDeleteView.as_view(),
name='comment_delete'
),
]
...@@ -2,7 +2,8 @@ from urllib.parse import urlencode ...@@ -2,7 +2,8 @@ from urllib.parse import urlencode
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.db.models import Q from django.db.models import Q
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin
from django.core.exceptions import PermissionDenied
from django.views.generic import ( from django.views.generic import (
ListView, ListView,
DetailView, DetailView,
...@@ -51,16 +52,18 @@ class ArticleIndexView(ListView): ...@@ -51,16 +52,18 @@ class ArticleIndexView(ListView):
return self.form.cleaned_data.get('search') return self.form.cleaned_data.get('search')
class ArticleCreateView(CreateView): class ArticleCreateView(PermissionRequiredMixin, CreateView):
template_name = 'article/article_create.html' template_name = 'article/article_create.html'
model = Article model = Article
form_class = ArticleModelForm form_class = ArticleModelForm
permission_required = 'web.add_article'
permission_denied_message = 'You have no rights'
def get_success_url(self): def get_success_url(self):
return reverse('articles-detail', kwargs={'id': self.object.id}) return reverse('articles-detail', kwargs={'id': self.object.id})
class ArticleDetailView(LoginRequiredMixin, DetailView): class ArticleDetailView(DetailView):
raise_exception = True raise_exception = True
template_name = 'article/article_detail.html' template_name = 'article/article_detail.html'
model = Article model = Article
...@@ -75,12 +78,17 @@ class ArticleDetailView(LoginRequiredMixin, DetailView): ...@@ -75,12 +78,17 @@ class ArticleDetailView(LoginRequiredMixin, DetailView):
) )
class ArticleUpdateView(LoginRequiredMixin, UpdateView): class ArticleUpdateView(UserPassesTestMixin, UpdateView):
model = Article model = Article
template_name = 'article/update.html' template_name = 'article/update.html'
form_class = ArticleModelForm form_class = ArticleModelForm
context_object_name = 'article' context_object_name = 'article'
pk_url_kwarg = 'id' pk_url_kwarg = 'id'
permission_required = 'web.change_article'
def test_func(self):
return self.get_object().author == self.request.user or \
self.request.user.has_perm('web.change_article')
def get_success_url(self): def get_success_url(self):
return reverse('articles-detail', kwargs={'id': self.object.id}) return reverse('articles-detail', kwargs={'id': self.object.id})
......
...@@ -4,6 +4,7 @@ from django.views.generic import ( ...@@ -4,6 +4,7 @@ from django.views.generic import (
UpdateView, UpdateView,
DeleteView DeleteView
) )
from django.contrib.auth.mixins import PermissionRequiredMixin
from web.forms import CommentModelForm from web.forms import CommentModelForm
from web.models import Comment from web.models import Comment
...@@ -17,17 +18,21 @@ class CommentCreateView(CreateView): ...@@ -17,17 +18,21 @@ class CommentCreateView(CreateView):
return reverse('articles-detail', kwargs={'id': self.object.article.id}) return reverse('articles-detail', kwargs={'id': self.object.article.id})
class CommentUpdateView(UpdateView): class CommentUpdateView(PermissionRequiredMixin, UpdateView):
model = Comment model = Comment
template_name = 'comment/create_update.html' template_name = 'comment/create_update.html'
context_object_name = 'comment' context_object_name = 'comment'
pk_url_kwarg = 'id' pk_url_kwarg = 'id'
form_class = CommentModelForm form_class = CommentModelForm
extra_context = {'button_text': 'Update', 'title': 'Update comment'} extra_context = {'button_text': 'Update', 'title': 'Update comment'}
permission_required = 'web.change_comment'
def get_initial(self): def get_initial(self):
return self.object.__dict__ return self.object.__dict__
def has_permission(self):
return super().has_permission() or self.request.user == self.get_object().author
def get_success_url(self): def get_success_url(self):
return reverse('articles-detail', kwargs={'id': self.object.article.id}) return reverse('articles-detail', kwargs={'id': self.object.article.id})
......
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