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

lesson 54

parent 3dea0324
from django.contrib import admin
from accounts.models import User
# Register your models here.
admin.site.register(User)
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):
......@@ -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 @@
{% endblock %}
{% block content %}
<form action="{% url 'login' %}" method="post">
<form action="{% url 'login' %}?next={{ request.GET.next }}" method="post">
{% csrf_token %}
{% include 'partial/form.html' with button_text='Login' %}
</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.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'
form_class = LoginForm
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"
AUTH_USER_MODEL = 'accounts.User'
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'main_page'
LOGOUT_REDIRECT_URL = 'main_page'
# LOGIN_REDIRECT_URL = 'main_page'
# LOGOUT_REDIRECT_URL = 'main_page'
......@@ -16,37 +16,14 @@ Including another URLconf
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from web import views
from accounts import views as accounts_views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.MainPageRedirectView.as_view()),
path('auth/login/', accounts_views.LoginView.as_view(), name='login'),
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'
),
path('', include('web.urls')),
path('auth/', include('accounts.urls'))
] + 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):
fields = ('title', 'author', 'status', 'text', 'tags')
widgets = {
'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'}),
'text': forms.Textarea(attrs={'class': 'form-control mb-3'}),
'tags': forms.CheckboxSelectMultiple(attrs={'class': 'mb-3'})
......@@ -38,7 +38,7 @@ class CommentModelForm(forms.ModelForm):
fields = ['author', 'text', 'article']
widgets = {
'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()
}
......
# 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):
verbose_name='Текст'
)
author = models.CharField(
max_length=100,
null=False,
blank=False,
default='Unknown',
author = models.ForeignKey(
'accounts.User',
on_delete=models.CASCADE,
default=1,
related_name='articles',
verbose_name='Автор'
)
......@@ -59,6 +59,9 @@ class Article(models.Model):
class Meta:
verbose_name = 'статью'
verbose_name_plural = 'статьи'
permissions = [
('can_eat_pizza', 'Может съесть пиццу')
]
def __str__(self):
return f'{self.author}: {self.title}'
......@@ -12,11 +12,11 @@ class Comment(models.Model):
text = models.TextField(max_length=400, verbose_name='Текст')
author = models.CharField(
max_length=40,
null=True,
blank=True,
default='Аноним',
author = models.ForeignKey(
'accounts.User',
on_delete=models.CASCADE,
default=1,
related_name='comments',
verbose_name='Автор'
)
......
......@@ -10,6 +10,7 @@
<form action="/articles/add/" method="post">
{% csrf_token %}
{% include 'partial/form.html' with button_text='Create' %}
<input type="hidden" name="author" value="{{ request.user.id }}">
</form>
{% endblock %}
......@@ -25,7 +25,9 @@
<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?')">
{% csrf_token %}
<button class="btn btn-danger mt-4">Delete</button>
......@@ -39,6 +41,7 @@
{% csrf_token %}
{% include 'partial/form.html' with button_text='add' %}
<input type="hidden" name="article" value="{{ article.id }}">
<input type="hidden" name="author" value="{{ request.user.id }}">
</form>
{% for comment in comments %}
......@@ -46,9 +49,11 @@
<div class="card-header d-flex justify-content-between">
{{ comment.author }}
<div class="d-flex justify-content-between">
<a href="{% url 'comment_update' id=comment.id %}" class="me-5">
<i class="fa fa-regular fa-pen-to-square"></i>
</a>
{% if perms.web.change_comment or request.user == comment.author %}
<a href="{% url 'comment_update' id=comment.id %}" class="me-5">
<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?')">
{% csrf_token %}
......
......@@ -4,7 +4,11 @@
{% block content %}
<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' %}
{% for article in articles %}
<br>
......@@ -12,13 +16,13 @@
<br>
<h2>{{ article.title }}</h2>
{% if user.is_authenticated %}
{# {% if user.is_authenticated %}#}
<p>
<a href="{% url 'articles-detail' id=article.id %}">
Подробнее
</a>
</p>
{% endif %}
{# {% endif %}#}
<br>
<hr>
<br>
......
......@@ -6,6 +6,7 @@
{% block content %}
<form action="{% url 'article_update' article.pk %}" method="post">
{% csrf_token %}
{% include 'partial/form.html' with button_text='Update' abc='123' %}
</form>
{% endblock %}
......
......@@ -56,7 +56,10 @@
{% else %}
<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>
{% 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
from django.urls import reverse, reverse_lazy
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 (
ListView,
DetailView,
......@@ -51,16 +52,18 @@ class ArticleIndexView(ListView):
return self.form.cleaned_data.get('search')
class ArticleCreateView(CreateView):
class ArticleCreateView(PermissionRequiredMixin, CreateView):
template_name = 'article/article_create.html'
model = Article
form_class = ArticleModelForm
permission_required = 'web.add_article'
permission_denied_message = 'You have no rights'
def get_success_url(self):
return reverse('articles-detail', kwargs={'id': self.object.id})
class ArticleDetailView(LoginRequiredMixin, DetailView):
class ArticleDetailView(DetailView):
raise_exception = True
template_name = 'article/article_detail.html'
model = Article
......@@ -75,12 +78,17 @@ class ArticleDetailView(LoginRequiredMixin, DetailView):
)
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
class ArticleUpdateView(UserPassesTestMixin, UpdateView):
model = Article
template_name = 'article/update.html'
form_class = ArticleModelForm
context_object_name = 'article'
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):
return reverse('articles-detail', kwargs={'id': self.object.id})
......
......@@ -4,6 +4,7 @@ from django.views.generic import (
UpdateView,
DeleteView
)
from django.contrib.auth.mixins import PermissionRequiredMixin
from web.forms import CommentModelForm
from web.models import Comment
......@@ -17,17 +18,21 @@ class CommentCreateView(CreateView):
return reverse('articles-detail', kwargs={'id': self.object.article.id})
class CommentUpdateView(UpdateView):
class CommentUpdateView(PermissionRequiredMixin, UpdateView):
model = Comment
template_name = 'comment/create_update.html'
context_object_name = 'comment'
pk_url_kwarg = 'id'
form_class = CommentModelForm
extra_context = {'button_text': 'Update', 'title': 'Update comment'}
permission_required = 'web.change_comment'
def get_initial(self):
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):
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