Commit 8efb80b4 authored by Давид Ли's avatar Давид Ли

lesson 70

parent 0edc3494
...@@ -18,6 +18,9 @@ class User(AbstractUser): ...@@ -18,6 +18,9 @@ class User(AbstractUser):
), ),
) )
password = models.CharField(max_length=128, verbose_name='password', null=True) password = models.CharField(max_length=128, verbose_name='password', null=True)
def is_moderator(self):
return 'Moderators' in self.groups.values_list('name', flat=True)
# Pillow # Pillow
......
...@@ -79,7 +79,7 @@ class UserDetailView(mixins.LoginRequiredMixin, generic.DetailView): ...@@ -79,7 +79,7 @@ class UserDetailView(mixins.LoginRequiredMixin, generic.DetailView):
# Проверяем, если профиль привязанный к нашему юзеру уже есть, то ничего не делать # Проверяем, если профиль привязанный к нашему юзеру уже есть, то ничего не делать
# Если нет, то создать пустой профиль # Если нет, то создать пустой профиль
models.Profile.objects.get_or_create(user=self.object) models.Profile.objects.get_or_create(user=self.object)
paginator = self.__get_paginator() paginator = self.__get_paginator()
page_number = self.request.GET.get('page', 1) page_number = self.request.GET.get('page', 1)
......
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'
from django.db import models
# Create your models here.
from rest_framework import serializers
from webapp import models
class _ArticleSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=200, required=True)
text = serializers.CharField(max_length=3000, required=True)
author_id = serializers.IntegerField(write_only=True)
author = serializers.PrimaryKeyRelatedField(read_only=True)
created_at = serializers.DateTimeField(read_only=True)
updated_at = serializers.DateTimeField(read_only=True)
def create(self, validated_data):
return models.Article.objects.create(**validated_data)
def update(self, instance, validated_data):
for key, value in validated_data.items():
setattr(instance, key, value)
instance.save()
return instance
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = models.Article
fields = ['id', 'title', 'text', 'author', 'created_at', 'updated_at']
import json
from django.views.generic import View
from rest_framework.views import APIView
from rest_framework.response import Response
from api import serializers
from webapp import models
class ArticleListView(APIView):
def get(self, request, *args, **kwargs):
articles = models.Article.objects.all()
serializer = serializers.ArticleSerializer(articles, many=True)
return Response(serializer.data, safe=False)
class ArticleCreateView(APIView):
def post(self, request, *args, **kwargs):
serializer = serializers.ArticleSerializer(data=json.loads(request.body))
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=400)
...@@ -38,6 +38,9 @@ INSTALLED_APPS = [ ...@@ -38,6 +38,9 @@ INSTALLED_APPS = [
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'rest_framework',
'api',
'webapp', 'webapp',
'accounts', 'accounts',
] ]
...@@ -143,5 +146,6 @@ MEDIA_ROOT = BASE_DIR / 'uploads' ...@@ -143,5 +146,6 @@ MEDIA_ROOT = BASE_DIR / 'uploads'
MEDIA_URL = '/images/' MEDIA_URL = '/images/'
# localhost:1025/uploads/avatars/user_1.jpg # localhost:1025/uploads/avatars/user_1.jpg
SESSION_COOKIE_AGE = 5 * 60
# DATE_INPUT_FORMATS = ('%d.%m.%Y',) # DATE_INPUT_FORMATS = ('%d.%m.%Y',)
"""ap_12 URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
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.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include
from django.conf.urls.static import static from django.conf.urls.static import static
from django.conf import settings from django.conf import settings
from api import views as api_views
from webapp import views from webapp import views
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('', views.IndexRedirectView.as_view(), name='redirect_to_index'), path('', views.IndexRedirectView.as_view(), name='redirect_to_index'),
path('articles/', include('webapp.urls')), path('articles/', include('webapp.urls')),
path('accounts/', include('accounts.urls')), path('accounts/', include('accounts.urls')),
path('api/articles/', api_views.ArticleListView.as_view()),
path('api/articles/create', api_views.ArticleCreateView.as_view()),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
{% block content %} {% block content %}
<h1>Article</h1> <h1>Article</h1>
{% for message in messages %}
<div class="alert alert-success">
{{ message }}
</div>
{% endfor %}
<h2>{{ article.title }}</h2> <h2>{{ article.title }}</h2>
<p>{{ article.text }}</p> <p>{{ article.text }}</p>
<p>By: {{ article.author }}</p> <p>By: {{ article.author }}</p>
......
...@@ -14,11 +14,18 @@ ...@@ -14,11 +14,18 @@
<p>Дата Рождения: {{ user_obj.profile.birth_date|date:'d.m.Y' }}</p> <p>Дата Рождения: {{ user_obj.profile.birth_date|date:'d.m.Y' }}</p>
<p>Почта: {{ user_obj.email }}</p> <p>Почта: {{ user_obj.email }}</p>
{% if user_obj.is_moderator %}
<ul>
<li>Active: {{ user.is_active }}</li>
<li>Staff: {{ user.is_staff }}</li>
<li>Superuser: {{ user.is_superuser }}</li>
</ul>
{% endif %}
<a href="{% url 'user_update' %}" class="btn btn-warning mt-3">Обновить</a> <a href="{% url 'user_update' %}" class="btn btn-warning mt-3">Обновить</a>
<a href="{% url 'change_password' %}" class="btn btn-primary mt-3">Сменить пароль</a> <a href="{% url 'change_password' %}" class="btn btn-primary mt-3">Сменить пароль</a>
<h2 class="text-center">Статьи</h2> <h2 class="text-center mb-5">Статьи</h2>
{{page_obj.has_other_pages}}
{% include 'partial/article_list.html' with articles=page_obj.object_list is_paginated=page_obj.has_other_pages %} {% include 'partial/article_list.html' with articles=page_obj.object_list is_paginated=page_obj.has_other_pages %}
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -56,5 +56,10 @@ ...@@ -56,5 +56,10 @@
{% endblock %} {% endblock %}
</div> </div>
<script>
let a = 1
</script>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
{% block content %} {% block content %}
<div class="text-center"> <div class="text-center">
<!-- {% for message in messages %}
<div class="alert alert-success">
{{ message }}
</div>
{% endfor %} -->
<h1>Articles</h1> <h1>Articles</h1>
<p><a href="{% url 'articles_add' %}">Добавить</a></p> <p><a href="{% url 'articles_add' %}">Добавить</a></p>
......
...@@ -5,6 +5,7 @@ from webapp import views ...@@ -5,6 +5,7 @@ from webapp import views
urlpatterns = [ urlpatterns = [
path('', views.IndexListView.as_view(), name='index'), path('', views.IndexListView.as_view(), name='index'),
path('add', views.ArticleCreateView.as_view(), name='articles_add'), path('add', views.ArticleCreateView.as_view(), name='articles_add'),
path('echo', views.articles.json_echo_view),
path('<int:id>', views.ArticleDetailView.as_view(), name='articles_detail'), path('<int:id>', views.ArticleDetailView.as_view(), name='articles_detail'),
path('<int:id>/update', views.ArticleUpdateView.as_view(), name='articles_update'), path('<int:id>/update', views.ArticleUpdateView.as_view(), name='articles_update'),
path('<int:id>/delete', views.ArticleDeleteView.as_view(), name='articles_delete'), path('<int:id>/delete', views.ArticleDeleteView.as_view(), name='articles_delete'),
...@@ -18,5 +19,21 @@ urlpatterns = [ ...@@ -18,5 +19,21 @@ urlpatterns = [
'<int:article_id>/comments/<int:comment_id>/delete', '<int:article_id>/comments/<int:comment_id>/delete',
views.CommentDeleteView.as_view(), views.CommentDeleteView.as_view(),
name='comments_delete', name='comments_delete',
), ),
# path('api/', views.articles.index_api_view, name='index_api_view'),
path('api/', views.articles.articles_create_api_view, name='articles_create_api_view'),
# path('', views.art.as_view(), name='articles_add'), # POST
# path('<int:id>', views.ArticleDetailView.as_view(), name='articles_detail'), # GET
# path('<int:id>', views.ArticleUpdateView.as_view(), name='articles_update'), # PUT PATCH
# path('<int:id>', views.ArticleDeleteView.as_view(), name='articles_delete'), # DELETE
] ]
# Safe URLs: list, detail
# Unsafe URLs: create, update, delete
# list GET /articles/
# create POST /articles/
# detail GET /articles/123
# update PUT/PATCH /articles/123
# delete DELETE /articles/123
from urllib.parse import urlencode from urllib.parse import urlencode
from django.http.response import HttpResponse as HttpResponse from django.http.response import HttpResponse as HttpResponse
from django.contrib import messages
from django.views import generic from django.views import generic
from django.db.models import Q from django.db.models import Q
...@@ -46,6 +47,21 @@ class IndexListView(generic.ListView): ...@@ -46,6 +47,21 @@ class IndexListView(generic.ListView):
if self.search_value: if self.search_value:
context['query_params'] = urlencode({'search': self.search_value}) context['query_params'] = urlencode({'search': self.search_value})
# DEBUG - Отладка
# INFO - Информационное
# SUCCESS - Успех
# WARNING - Предупреждение
# ERROR - Ошибка
messages.add_message(self.request, messages.SUCCESS, 'Вы молодец!')
# list comp
self.request.session['index:messages'] = [vars(m) for m in self.request._messages]
res = []
for m in self.request._messages:
res.append(vars(m)['message'])
return context return context
def get_queryset(self): def get_queryset(self):
......
import json
from typing import Any from typing import Any
from django.http import HttpRequest from datetime import datetime as dt
from django.http.response import HttpResponse as HttpResponse from django.http import HttpRequest, HttpResponse, HttpResponseNotAllowed, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.core import serializers
from django.views import generic from django.views import generic
from django.views.decorators.csrf import ensure_csrf_cookie
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
...@@ -19,10 +23,12 @@ class ArticleDetailView(PermissionRequiredMixin, generic.DetailView): ...@@ -19,10 +23,12 @@ class ArticleDetailView(PermissionRequiredMixin, generic.DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
comments = self.object.comments.order_by('-created_at') comments = self.object.comments.order_by('-created_at')
return super().get_context_data( return super().get_context_data(
**kwargs, **kwargs,
comments=comments, comments=comments,
comments_form=CommentForm, comments_form=CommentForm,
messages=self.request.session.get('index:messages', []),
) )
...@@ -100,3 +106,43 @@ class ArticleDeleteView(generic.DeleteView): ...@@ -100,3 +106,43 @@ class ArticleDeleteView(generic.DeleteView):
model = Article model = Article
pk_url_kwarg = 'id' pk_url_kwarg = 'id'
success_url = reverse_lazy('index') success_url = reverse_lazy('index')
@ensure_csrf_cookie
def get_token_view(request, *args, **kwargs):
if request.method == 'GET':
return HttpResponse()
return HttpResponseNotAllowed('Only GET requests allowed')
def json_echo_view(request, *args, **kwargs):
answer = {
'time': dt.now().strftime('%d-%m-%Y %H:%M:%S'),
'method': request.method,
}
if request.body:
answer['content'] = json.loads(request.body)
return JsonResponse(answer)
def index_api_view(request, *args, **kwargs):
if request.method == 'GET':
articles = Article.objects.all()
serialized_articles = serializers.serialize('json', articles)
return HttpResponse(serialized_articles)
def articles_create_api_view(request, *args, **kwargs):
if request.method == 'POST':
if request.body:
article_data = json.loads(request.body)
article = Article.objects.create(**article_data)
return HttpResponse(serializers.serialize('json', [article]))
else:
return JsonResponse({'error': 'No data provided!'}, status_code=400)
Когда используют ветки:
1. 2 дефолтных ветки - develop (код на стадии разработки), master (код на проде)
2. Для выполнения задач
Пример задачи: Реализовать CRUD для статей
Что мы делаем: Создаем отдельную ветку и называем по такому принципу
dkasmgkasdgnadsgndlash
Далее: Задачу выполнили => заливаем в develop
gitlab: merge request
github: pull request
Django==3.2.23 Django==3.2.23
djangorestframework==3.14.0
Pillow==10.0.0 Pillow==10.0.0
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