Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
A
article_proj
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Владислав Андреев
article_proj
Commits
d4212e20
Commit
d4212e20
authored
Sep 20, 2021
by
Владислав Андреев
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
asdf
parent
bcce99eb
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
336 additions
and
47 deletions
+336
-47
admin.py
accounts/admin.py
+19
-1
0001_initial.py
accounts/migrations/0001_initial.py
+30
-0
0002_auto_20210916_1447.py
accounts/migrations/0002_auto_20210916_1447.py
+20
-0
models.py
accounts/models.py
+24
-1
user_detail.html
accounts/templates/user_detail.html
+25
-0
urls.py
accounts/urls.py
+5
-4
views.py
accounts/views.py
+61
-21
forms.py
articles/forms.py
+5
-7
0016_alter_article_author.py
articles/migrations/0016_alter_article_author.py
+21
-0
0017_alter_comment_author.py
articles/migrations/0017_alter_comment_author.py
+21
-0
0018_alter_article_options.py
articles/migrations/0018_alter_article_options.py
+17
-0
models.py
articles/models.py
+13
-4
detail.html
articles/templates/articles/detail.html
+3
-1
list.html
articles/templates/articles/list.html
+1
-1
article_list.html
articles/templates/partial/article_list.html
+32
-0
navbar.html
articles/templates/partial/navbar.html
+1
-1
article_views.py
articles/views/article_views.py
+7
-4
comment_views.py
articles/views/comment_views.py
+1
-0
context_processor.py
core/context_processor.py
+4
-0
settings.py
core/settings.py
+4
-0
urls.py
core/urls.py
+4
-1
style.css
static/style.css
+18
-1
htmlcss.jpg
uploads/user_pics/htmlcss.jpg
+0
-0
htmlcss_jmhndwG.jpg
uploads/user_pics/htmlcss_jmhndwG.jpg
+0
-0
No files found.
accounts/admin.py
View file @
d4212e20
from
django.contrib
import
admin
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth.admin
import
UserAdmin
from
django.contrib.auth.models
import
User
# Register your models here.
from
accounts.models
import
Profile
class
ProfileInline
(
admin
.
StackedInline
):
model
=
Profile
fields
=
[
'birth_date'
,
'avatar'
]
class
ProfileAdmin
(
UserAdmin
):
inlines
=
[
ProfileInline
]
User
=
get_user_model
()
admin
.
site
.
unregister
(
User
)
admin
.
site
.
register
(
User
,
ProfileAdmin
)
\ No newline at end of file
accounts/migrations/0001_initial.py
0 → 100644
View file @
d4212e20
# Generated by Django 3.2.6 on 2021-09-16 11:29
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
=
'Profile'
,
fields
=
[
(
'id'
,
models
.
BigAutoField
(
auto_created
=
True
,
primary_key
=
True
,
serialize
=
False
,
verbose_name
=
'ID'
)),
(
'birth_date'
,
models
.
DateField
(
blank
=
True
,
null
=
True
,
verbose_name
=
'Дата рождения'
)),
(
'avatar'
,
models
.
ImageField
(
blank
=
True
,
null
=
True
,
upload_to
=
'user_pics'
,
verbose_name
=
'Аватар'
)),
(
'user'
,
models
.
OneToOneField
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
related_name
=
'profile'
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'Пользователь'
)),
],
options
=
{
'verbose_name'
:
'Профиль'
,
'verbose_name_plural'
:
'Профили'
,
},
),
]
accounts/migrations/0002_auto_20210916_1447.py
0 → 100644
View file @
d4212e20
# Generated by Django 3.2.6 on 2021-09-16 14:47
from
django.db
import
migrations
def
create_profiles
(
apps
,
schema_editor
):
User
=
apps
.
get_model
(
'auth'
,
'User'
)
Profile
=
apps
.
get_model
(
'accounts'
,
'Profile'
)
for
user
in
User
.
objects
.
all
():
Profile
.
objects
.
get_or_create
(
user
=
user
)
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'accounts'
,
'0001_initial'
),
]
operations
=
[
migrations
.
RunPython
(
create_profiles
,
migrations
.
RunPython
.
noop
)
]
accounts/models.py
View file @
d4212e20
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth.models
import
AbstractUser
from
django.db
import
models
# Create your models here.
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
=
"Дата рождения"
)
avatar
=
models
.
ImageField
(
null
=
True
,
blank
=
True
,
upload_to
=
'user_pics'
,
verbose_name
=
"Аватар"
)
def
__str__
(
self
):
return
self
.
user
.
get_full_name
()
+
"профиль"
class
Meta
:
verbose_name
=
"профиль"
verbose_name_plural
=
"профили"
accounts/templates/user_detail.html
0 → 100644
View file @
d4212e20
{% extends 'base.html' %}
{% block title %}Пользователь{% endblock %}
{% block menu_links %}
<li><a
href=
"#"
>
Редактировать
</a></li>
<li><a
href=
"#"
>
Смена пароля
</a></li>
{% endblock %}
{% block content %}
<div
class=
"container"
>
<h1>
Личная страница пользователя {{ user_obj.get_full_name|default:user_obj.username }}
</h1>
{% if user_obj.profile.avatar %}
<img
class=
"avatar"
src=
"{{ user_obj.profile.avatar.url }}"
width=
"250"
height=
"250"
alt=
"user picture"
>
{% endif %}
<p>
Имя пользователя: {{ user_obj.username }}
</p>
<p>
Имя: {{ user_obj.first_name }}
</p>
<p>
Фамилия: {{ user_obj.last_name }}
</p>
<p>
Дата рождения: {{ user_obj.profile.birth_date|date:'d.m.Y' }}
</p>
<p>
Почта: {{ user_obj.email }}
</p>
<h2
class=
"text-center clear"
>
Статьи автора:
</h2>
{% include 'partial/article_list.html' %}
</div>
{% endblock %}
accounts/urls.py
View file @
d4212e20
from
django.urls
import
path
from
.views
import
login_view
,
logout_view
,
register_v
iew
from
.views
import
LoginView
,
LogoutView
,
RegisterView
,
UserDetailV
iew
urlpatterns
=
[
path
(
'accounts/login'
,
login_view
,
name
=
'login'
),
path
(
'accounts/logout'
,
logout_view
,
name
=
'logout'
),
path
(
'accounts/create/'
,
register_view
,
name
=
"register"
)
path
(
'accounts/login'
,
LoginView
.
as_view
(),
name
=
'login'
),
path
(
'accounts/logout'
,
LogoutView
.
as_view
(),
name
=
'logout'
),
path
(
'accounts/create/'
,
RegisterView
.
as_view
(),
name
=
"register"
),
path
(
'<int:pk>/'
,
UserDetailView
.
as_view
(),
name
=
'user-detail'
)
]
\ No newline at end of file
accounts/views.py
View file @
d4212e20
from
django.contrib.auth
import
(
authenticate
,
login
,
logout
authenticate
,
login
,
logout
,
get_user_model
)
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.contrib.auth.models
import
Group
from
django.core.exceptions
import
ValidationError
from
django.core.paginator
import
Paginator
from
django.shortcuts
import
render
,
redirect
from
django.views
import
View
from
django.views.generic
import
DetailView
from
.forms
import
RegisterForm
,
MyRegisterForm
from
.models
import
Profile
def
logout_view
(
request
):
class
LogoutView
(
View
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
logout
(
request
)
next
=
request
.
GET
.
get
(
'next'
)
if
next
:
...
...
@@ -14,10 +22,15 @@ def logout_view(request):
return
redirect
(
'login'
)
def
login_view
(
request
):
class
LoginView
(
View
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
return
render
(
request
=
request
,
template_name
=
'login.html'
,
)
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
context
=
{}
print
(
request
.
GET
)
if
request
.
method
==
'POST'
:
username
=
request
.
POST
.
get
(
"username"
)
password
=
request
.
POST
.
get
(
"pass"
)
user
=
authenticate
(
...
...
@@ -40,18 +53,45 @@ def login_view(request):
)
def
register_view
(
request
,
*
args
,
**
kwargs
):
if
request
.
method
==
"POST"
:
class
RegisterView
(
View
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
form
=
MyRegisterForm
()
return
render
(
request
,
template_name
=
'register.html'
,
context
=
{
"form"
:
form
})
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
try
:
form
=
MyRegisterForm
(
data
=
request
.
POST
)
if
form
.
is_valid
():
user
=
form
.
save
()
Profile
.
objects
.
create
(
user
=
user
)
group
=
Group
.
objects
.
get
(
name
=
"Новые пользователи"
)
group
.
user_set
.
add
(
user
)
login
(
request
,
user
)
return
redirect
(
'article_list'
)
except
ValidationError
as
e
:
print
(
e
)
return
render
(
request
,
template_name
=
'register.html'
,
context
=
{
"form"
:
form
})
else
:
form
=
MyRegisterForm
()
return
render
(
request
,
template_name
=
'register.html'
,
context
=
{
"form"
:
form
})
class
UserDetailView
(
LoginRequiredMixin
,
DetailView
):
model
=
get_user_model
()
template_name
=
"user_detail.html"
context_object_name
=
"user_obj"
paginate_related_by
=
5
paginate_related_orphans
=
0
def
get_context_data
(
self
,
**
kwargs
):
articles
=
self
.
object
.
articles
.
order_by
(
'-created_at'
)
paginator
=
Paginator
(
articles
,
self
.
paginate_related_by
,
self
.
paginate_related_orphans
)
page_number
=
self
.
request
.
GET
.
get
(
'page'
,
1
)
page
=
paginator
.
get_page
(
page_number
)
kwargs
[
'page_obj'
]
=
page
kwargs
[
'articles'
]
=
page
.
object_list
kwargs
[
'is_paginated'
]
=
page
.
has_other_pages
()
return
super
(
UserDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
articles/forms.py
View file @
d4212e20
...
...
@@ -22,15 +22,13 @@ class AuthorForm(ModelForm):
class
CommentForm
(
ModelForm
):
class
Meta
:
model
=
Comment
fields
=
(
"text"
,
"author"
)
fields
=
[
"text"
,
]
class
ArticleForm
(
Form
):
__model
=
Article
title
=
CharField
()
body
=
CharField
()
author
=
ModelChoiceField
(
queryset
=
Author
.
objects
.
all
())
tags
=
ModelMultipleChoiceField
(
queryset
=
Tag
.
objects
.
all
())
class
ArticleForm
(
ModelForm
):
class
Meta
:
model
=
Article
fields
=
'__all__'
# class Meta:
# model = Article
...
...
articles/migrations/0016_alter_article_author.py
0 → 100644
View file @
d4212e20
# Generated by Django 3.2.6 on 2021-09-13 14:45
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
),
(
'articles'
,
'0015_alter_article_created_at'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'article'
,
name
=
'author'
,
field
=
models
.
ForeignKey
(
default
=
1
,
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_DEFAULT
,
related_name
=
'articles'
,
to
=
settings
.
AUTH_USER_MODEL
),
),
]
articles/migrations/0017_alter_comment_author.py
0 → 100644
View file @
d4212e20
# Generated by Django 3.2.6 on 2021-09-13 14:49
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
),
(
'articles'
,
'0016_alter_article_author'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'comment'
,
name
=
'author'
,
field
=
models
.
ForeignKey
(
default
=
1
,
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_DEFAULT
,
related_name
=
'author_of_comment'
,
to
=
settings
.
AUTH_USER_MODEL
),
),
]
articles/migrations/0018_alter_article_options.py
0 → 100644
View file @
d4212e20
# Generated by Django 3.2.6 on 2021-09-13 14:56
from
django.db
import
migrations
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'articles'
,
'0017_alter_comment_author'
),
]
operations
=
[
migrations
.
AlterModelOptions
(
name
=
'article'
,
options
=
{
'permissions'
:
[(
'can_read_article'
,
'Может читать статьи'
)]},
),
]
articles/models.py
View file @
d4212e20
from
django.contrib.auth
import
get_user_model
from
django.db
import
models
from
datetime
import
datetime
...
...
@@ -14,9 +15,9 @@ class Article(models.Model):
created_at
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
False
)
author
=
models
.
ForeignKey
(
"articles.Author"
,
on_delete
=
models
.
SET_
NULL
,
null
=
True
,
related_name
=
'articles'
)
get_user_model
()
,
on_delete
=
models
.
SET_
DEFAULT
,
null
=
True
,
related_name
=
'articles'
,
default
=
1
)
tags
=
models
.
ManyToManyField
(
'articles.Tag'
,
related_name
=
'articles'
,
...
...
@@ -26,6 +27,11 @@ class Article(models.Model):
def
__str__
(
self
):
return
f
"{self.id}. {self.title[:20]}"
class
Meta
:
permissions
=
[
(
'can_read_article'
,
'Может читать статьи'
)
]
class
Comment
(
models
.
Model
):
article
=
models
.
ForeignKey
(
...
...
@@ -34,7 +40,10 @@ class Comment(models.Model):
on_delete
=
models
.
CASCADE
,
verbose_name
=
"Статья"
)
text
=
models
.
TextField
(
max_length
=
400
,
verbose_name
=
"Комментарий"
)
author
=
models
.
CharField
(
max_length
=
40
,
null
=
True
,
blank
=
True
,
verbose_name
=
"Автор"
,
default
=
"Аноним"
)
author
=
models
.
ForeignKey
(
get_user_model
(),
on_delete
=
models
.
SET_DEFAULT
,
null
=
True
,
related_name
=
'author_of_comment'
,
default
=
1
)
created_at
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
"Дата создания"
)
updated_at
=
models
.
DateTimeField
(
auto_now
=
True
,
verbose_name
=
"Дата изменения"
)
...
...
articles/templates/articles/detail.html
View file @
d4212e20
...
...
@@ -31,7 +31,9 @@
class=
"btn btn-success"
value=
"Оставить комментарий"
>
</form>
{% if perms.articles.change_article %}
<a
href=
"{% url 'article_update' article.pk %}"
>
Изменить статью
</a>
{% endif %}
</div>
</div>
...
...
articles/templates/articles/list.html
View file @
d4212e20
...
...
@@ -21,7 +21,7 @@
<tr>
<th
scope=
"row"
>
{{ forloop.counter }}
</th>
<td><a
href=
"{% url 'article_detail' article.pk %}"
>
{{ article.title }}
</a></td>
<td>
{{ article.author
.name
}}
</td>
<td>
{{ article.author }}
</td>
<td>
{{ article.created_at|date:"d M Y" }}
</td>
<td><a
class=
"btn btn-danger btn-sm"
href=
"{% url "
article_delete
"
article
.
pk
%}"
>
Удалить
</a></td>
</tr>
...
...
articles/templates/partial/article_list.html
0 → 100644
View file @
d4212e20
{% if is_paginated %}
{% include 'partial/pagination.html' %}
{% endif %}
{% for article in articles %}
<div
class=
"box"
>
<h3><a
href=
"{% url "
article_detail
"
article
.
pk
%}"
>
{{ article.title }}
</a></h3>
<p>
<label
for=
"selected_articles-{{ article.pk }}"
>
Select:
</label>
<input
type=
"checkbox"
name=
"selected_articles"
id=
"selected_articles-{{ article.pk }}"
value=
"{{ article.pk }}"
>
</p>
<p>
Статус: ({{ article.status }} | {{ article.get_status_display }})
</p>
<p>
<a
href=
"{% url 'user-detail' article.author_id %}"
>
{{ article.author }}
</a>
| {{ article.created_at|date:"d.m.Y H:i:s" }}
</p>
<p>
Published at: {{ article.publish_at|date:"d.m.Y H:i:s" }}
</p>
{% if perms.articles.change_article or article.author == request.user %}
<p><a
href=
"{% url 'article_update' article.pk %}"
>
Update
</a></p>
{% endif %}
{% if perms.articles.delete_article or article.author == request.user %}
<p><a
href=
"{% url 'article_delete' article.pk %}"
>
Delete
</a></p>
{% endif %}
</div>
{% empty %}
<h2
class=
"text-center"
>
Нет статей
</h2>
{% endfor %}
{% if is_paginated %}
{% include 'partial/pagination.html' %}
{% endif %}
articles/templates/partial/navbar.html
View file @
d4212e20
...
...
@@ -10,11 +10,11 @@
<a
class=
"nav-link"
href=
"{% url 'author_list' %}"
>
Список авторов
</a>
</li>
</ul>
{{ user.is_authenticated }}
{% if not user.is_authenticated %}
<a
class=
"btn btn-success"
href=
"{% url 'login' %}?next={{ request.get_full_path }}"
>
Войти
</a>
<a
class=
"btn btn-success"
href=
"{% url 'register' %}?next={{ request.get_full_path }}"
>
Регистрация
</a>
{% else %}
<li
class=
"menu-right"
>
Привет,
<a
href=
"{% url 'user-detail' user.pk %}"
>
{{ user.username }}
</a>
!
</li>
<a
class=
"btn btn-danger"
href=
"{% url 'logout' %}?next={{ request.get_full_path }}"
>
Выйти
</a>
{% endif %}
</div>
...
...
articles/views/article_views.py
View file @
d4212e20
from
urllib.parse
import
urlencode
from
django.contrib.auth.mixins
import
LoginRequiredMixin
import
P
as
P
from
django.contrib.auth.mixins
import
LoginRequiredMixin
,
PermissionRequiredMixin
from
django.contrib.auth.decorators
import
login_required
from
django.core.exceptions
import
PermissionDenied
from
django.db.models
import
Q
from
django.shortcuts
import
get_object_or_404
,
render
,
redirect
from
django.urls
import
reverse
,
reverse_lazy
...
...
@@ -52,7 +55,7 @@ class ArticleListView(ListView):
return
queryset
class
ArticleCreateView
(
CreateView
):
class
ArticleCreateView
(
LoginRequiredMixin
,
CreateView
):
template_name
=
'articles/create.html'
form_class
=
ArticleForm
model
=
Article
...
...
@@ -60,12 +63,12 @@ class ArticleCreateView(CreateView):
def
get_redirect_url
(
self
):
return
reverse
(
'article_detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
class
ArticleUpdateView
(
UpdateView
):
class
ArticleUpdateView
(
PermissionRequiredMixin
,
LoginRequiredMixin
,
UpdateView
):
model
=
Article
template_name
=
"articles/update.html"
form_class
=
ArticleForm
context_object_name
=
'article'
permission_required
=
[
"articles.change_article"
,
"articles.can_read_article"
]
def
get_redirect_url
(
self
):
return
reverse
(
'article_detail'
,
kwargs
=
{
...
...
articles/views/comment_views.py
View file @
d4212e20
...
...
@@ -15,6 +15,7 @@ class CommentCreateView(CreateView):
def
form_valid
(
self
,
form
):
article
=
get_object_or_404
(
Article
,
pk
=
self
.
kwargs
.
get
(
'pk'
))
form
.
instance
.
article
=
article
form
.
instance
.
author
=
self
.
request
.
user
return
super
()
.
form_valid
(
form
)
def
get_redirect_url
(
self
):
...
...
core/context_processor.py
0 → 100644
View file @
d4212e20
def
func
(
request
):
return
{
"my_custom_request"
:
1
}
\ No newline at end of file
core/settings.py
View file @
d4212e20
...
...
@@ -65,6 +65,7 @@ TEMPLATES = [
'django.template.context_processors.request'
,
'django.contrib.auth.context_processors.auth'
,
'django.contrib.messages.context_processors.messages'
,
'core.context_processor.func'
],
},
},
...
...
@@ -102,6 +103,9 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
MEDIA_ROOT
=
os
.
path
.
join
(
BASE_DIR
,
'uploads'
)
MEDIA_URL
=
"/uploads/"
LOGIN_URL
=
'login'
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
...
...
core/urls.py
View file @
d4212e20
...
...
@@ -13,8 +13,11 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from
django.conf.urls.static
import
static
from
django.contrib
import
admin
from
django.urls
import
path
,
include
from
core
import
settings
from
core.error
import
error_404
handler404
=
error_404
...
...
@@ -23,4 +26,4 @@ urlpatterns = [
path
(
'admin/'
,
admin
.
site
.
urls
),
path
(
''
,
include
(
'articles.urls'
)),
path
(
''
,
include
(
'accounts.urls'
)),
]
]
+
static
(
settings
.
MEDIA_URL
,
document_root
=
settings
.
MEDIA_ROOT
)
static/style.css
View file @
d4212e20
body
{
background
:
aqua
;
}
.avatar
{
display
:
inline-block
;
float
:
left
;
width
:
250px
;
height
:
auto
;
margin-right
:
20px
;
margin-bottom
:
20px
;
}
.text-center
{
text-align
:
center
;
}
.clear
{
clear
:
both
;
}
uploads/user_pics/htmlcss.jpg
0 → 100644
View file @
d4212e20
199 KB
uploads/user_pics/htmlcss_jmhndwG.jpg
0 → 100644
View file @
d4212e20
199 KB
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment