Commit 76d5ea91 authored by Давид Ли's avatar Давид Ли

lesson 51

parent a8300edd
...@@ -22,11 +22,17 @@ from web import views ...@@ -22,11 +22,17 @@ from web import views
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('', views.MainPageRedirectView.as_view()), path('', views.MainPageRedirectView.as_view()),
path('articles/', views.index_view, name='main_page'), path('articles/', views.ArticleIndexView.as_view(), name='main_page'),
path('articles/add/', views.ArticleCreateView.as_view(), name='articles-add'), path('articles/add/', views.ArticleCreateView.as_view(), name='articles-add'),
# /articles/1/ OR /articles/?id=1 # /articles/1/ OR /articles/?id=1
# article_details_view(request, id) # article_details_view(request, id)
path('articles/<int:id>/', views.ArticleDetailView.as_view(), name='articles-detail'), 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>/edit', views.ArticleUpdateView.as_view(), name='article_update'),
path('articles/<int:id>/delete', views.delete_article, name='delete_article') path(
'articles/<int:article_id>/comments/',
views.ArticleCommentCreateView.as_view(),
name='article_comment_create'
),
path('articles/<int:id>/delete', views.ArticleDeleteView.as_view(), name='delete_article')
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
...@@ -2,7 +2,7 @@ from django import forms ...@@ -2,7 +2,7 @@ from django import forms
from django.forms import widgets, ValidationError from django.forms import widgets, ValidationError
from core.validators import at_least_5 from core.validators import at_least_5
from web.models import Article from web.models import Article, Comment
class ArticleForm(forms.Form): class ArticleForm(forms.Form):
...@@ -30,3 +30,25 @@ class ArticleModelForm(forms.ModelForm): ...@@ -30,3 +30,25 @@ class ArticleModelForm(forms.ModelForm):
raise ValidationError('Text of the article should not duplicate it\'s title') raise ValidationError('Text of the article should not duplicate it\'s title')
return cleaned_data return cleaned_data
class ArticleCommentModelForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['author', 'text']
widgets = {
'text': forms.TextInput(attrs={'class': 'form-control mb-3'}),
'author': forms.TextInput(attrs={'class': 'form-control mb-3'}),
}
class SearchForm(forms.Form):
search = forms.CharField(
max_length=100,
required=False,
label='Найти',
widget=forms.TextInput(attrs={
'class': 'form-control my-3',
'placeholder': 'enter search value'
})
)
from django.db import models from django.db import models
# article_1 - (comment_1, comment_2)
# comment_1 = comment_1.article
# comment_1 = comment_1.article_id
# article_1 = article_1.comment.all()
class Comment(models.Model): class Comment(models.Model):
# article - object
# article_id - id
article = models.ForeignKey( article = models.ForeignKey(
'web.Article', 'web.Article',
on_delete=models.CASCADE, on_delete=models.CASCADE,
......
...@@ -26,5 +26,31 @@ ...@@ -26,5 +26,31 @@
<hr> <hr>
<a href="{% url 'article_update' article.pk %}" class="btn btn-primary mt-4 me-3">Edit</a> <a href="{% url 'article_update' article.pk %}" class="btn btn-primary mt-4 me-3">Edit</a>
<a href="{% url 'delete_article' article.pk %}" class="btn btn-danger mt-4">Delete</a> <form action="{% url 'delete_article' article.pk %}" method="POST" onsubmit="confirm('Are you sure?')">
{% csrf_token %}
<button class="btn btn-danger mt-4">Delete</button>
</form>
<h3 class="mt-4">Comments:</h3>
<div class="comments-list">
<form action="{% url 'article_comment_create' article_id=article.id %}" method="POST">
{% csrf_token %}
{% include 'partial/form.html' with button_text='add' %}
</form>
{% for comment in comments %}
<div class="card my-3">
<div class="card-header">
{{ comment.author }}
</div>
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>{{ comment.text }}</p>
<footer class="blockquote-footer"><cite title="Source Title">{{ comment.created_at }}</cite></footer>
</blockquote>
</div>
</div>
{% empty %}
<p>No comments yet.</p>
{% endfor %}
</div>
{% endblock %} {% endblock %}
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
{% block content %} {% block content %}
<h1>Articles</h1> <h1>Articles</h1>
<a href="{% url 'articles-add' %}" class="btn btn-primary">Создать</a> <a href="{% url 'articles-add' %}" class="btn btn-primary">Создать</a>
{% for article in articles %} {% include 'partial/search_form.html' %}
{% for article in articles %}
<br> <br>
<hr> <hr>
<br> <br>
...@@ -18,5 +19,9 @@ ...@@ -18,5 +19,9 @@
<br> <br>
<hr> <hr>
<br> <br>
{% endfor %} {% endfor %}
{% if is_paginated %}
{% include 'partial/pagination.html' %}
{% endif %}
{% endblock %} {% endblock %}
<div class="d-flex justify-content-center ">
<nav aria-label="...">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?{% if query %}{{ query }}&{% endif %}page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#">Previous</a>
</li>
{% endif %}
{% for num in paginator.page_range %}
<li class="
page-item
{% if page_obj.number == num %}
active
{% else %}
{% endif %}
">
<a class="page-link" href="?{% if query %}{{ query }}&{% endif %}page={{ num }}">
{{ num }}
</a>
</li>
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?{% if query %}{{ query }}&{% endif %}page={{ page_obj.next_page_number }}">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#">Next</a>
</li>
{% endif %}
</ul>
</nav>
</div>
\ No newline at end of file
<form action="" method="GET">
<label for="{{ form.search.id_for_label }}"></label>
{{ form.search }}
<button type="submit" class="btn btn-success">Submit</button>
{% for error in form.search.errors %}
<div class="alert alert-danger">{{ error }}</div>
{% endfor %}
</form>
\ No newline at end of file
from django.shortcuts import render, redirect, get_object_or_404 from urllib.parse import urlencode
from django.urls import reverse
from django.views.generic import View, TemplateView, RedirectView, FormView from django.shortcuts import get_object_or_404
from web.forms import ArticleForm, ArticleModelForm from django.urls import reverse, reverse_lazy
from web.models import Article, StatusChoices from django.db.models import Q
from django.views.generic import (
RedirectView,
def index_view(request): ListView,
return render( DetailView,
request, 'index.html', context={ CreateView,
'articles': Article.objects.order_by('-created_at'), UpdateView,
'reverse': reverse('articles-detail', kwargs={'id': 1}) DeleteView
} )
) from web.forms import ArticleModelForm, SearchForm, ArticleCommentModelForm
from web.models import Article, Comment
class ArticleIndexView(ListView):
template_name = 'index.html'
context_object_name = 'articles'
model = Article
ordering = ['-created_at']
paginate_by = 3
class MainPageRedirectView(RedirectView): def dispatch(self, request, *args, **kwargs):
pattern_name = 'main_page' self.form = self.get_search_form()
self.search_value = self.get_search_value()
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.form
# Class-based views if self.search_value:
class ArticleCreateView(View): context['query'] = urlencode({'search': self.search_value})
def get(self, request, *args, **kwargs):
form = ArticleModelForm()
return render( return context
self.request,
'article_create.html',
context={
'status_choices': StatusChoices.choices,
'form': form
}
)
def post(self, request, *args, **kwargs): def get_queryset(self):
errors = {} qs = super().get_queryset()
data = request.POST if self.search_value:
form = ArticleModelForm(data=data) query = Q(title__icontains=self.search_value) | Q(author__icontains=self.search_value)
if form.is_valid(): qs = qs.filter(query)
article = form.save()
return redirect('articles-detail', id=article.id)
else:
return render(self.request, 'article_create.html', context={'form': form, 'status_choices': StatusChoices.choices})
return qs
# /articles/{id} def get_search_form(self):
def article_detail_view(request, id: int): return SearchForm(self.request.GET)
article = get_object_or_404(Article, id=id)
return render(request, 'article_detail.html', context={'article': article})
def get_search_value(self):
if self.form.is_valid():
return self.form.cleaned_data.get('search')
class ArticleDetailView(TemplateView):
template_name = 'article_detail.html'
def get_context_data(self, **kwargs): class MainPageRedirectView(RedirectView):
article = get_object_or_404(Article, id=kwargs.get('id')) pattern_name = 'main_page'
return super().get_context_data(article=article)
class ArticleUpdateView(FormView): class ArticleCreateView(CreateView):
template_name = 'update.html' template_name = 'article_create.html'
model = Article
form_class = ArticleModelForm form_class = ArticleModelForm
def dispatch(self, request, *args, **kwargs): def get_success_url(self):
self.article = get_object_or_404(self.form_class.Meta.model, id=kwargs.get('id')) return reverse('articles-detail', kwargs={'id': self.object.id})
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
return super().get_context_data(article=self.article, **kwargs)
def get_initial(self): class ArticleCommentCreateView(CreateView):
initial = self.article.__dict__ model = Comment
initial['tags'] = self.article.tags.all() form_class = ArticleCommentModelForm
return initial
def get_form_kwargs(self): def dispatch(self, request, *args, **kwargs):
return super().get_form_kwargs() | {'instance': self.article} self.article = get_object_or_404(Article, id=self.kwargs.get('article_id'))
return super().dispatch(request, *args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
form.save() form.instance.article = self.article
return super().form_valid(form) return super().form_valid(form)
def get_success_url(self): def get_success_url(self):
return reverse('articles-detail', kwargs={'id': self.article.id}) return reverse('articles-detail', kwargs={'id': self.article.id})
def article_update_view(request, id): class ArticleDetailView(DetailView):
article = get_object_or_404(Article, pk=id) template_name = 'article_detail.html'
if request.method == 'GET': model = Article
form = ArticleForm(initial={ context_object_name = 'article'
'title': article.title, pk_url_kwarg = 'id'
'status': article.status, extra_context = {'form': ArticleCommentModelForm}
'author': article.author,
'text': article.text def get_context_data(self, **kwargs):
}) return super().get_context_data(
return render(request, 'update.html', context={'article': article, 'form': form, 'status_choices': StatusChoices.choices}) comments=self.object.comments.order_by('-created_at'),
elif request.method == 'POST': **kwargs
form = ArticleForm(data=request.POST) )
if form.is_valid():
article.title = request.POST.get('title') class ArticleUpdateView(UpdateView):
article.author = request.POST.get('author') model = Article
article.text = request.POST.get('text') template_name = 'update.html'
article.status = request.POST.get('status') form_class = ArticleModelForm
article.save() context_object_name = 'article'
return redirect('articles-detail', id=article.pk) pk_url_kwarg = 'id'
else:
return render(request, 'update.html', context={'article': article, 'form': form, 'status_choices': StatusChoices.choices}) def get_success_url(self):
return reverse('articles-detail', kwargs={'id': self.object.id})
def delete_article(request, id):
article = get_object_or_404(Article, pk=id) class ArticleDeleteView(DeleteView):
if request.method == 'GET': model = Article
return render(request, 'delete.html', context={'article': article}) template_name = 'delete.html'
context_object_name = 'article'
elif request.method == 'POST': success_url = reverse_lazy('main_page')
article.delete() pk_url_kwarg = 'id'
return redirect('main_page')
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