Commit fad0df08 authored by Volkov Gherman's avatar Volkov Gherman

завершил Курсовую работу с новостным проектом

parent bde08a12
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="db" uuid="fb1dd082-ca0e-419a-affb-8cf1144abbd9">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:C:\Users\Герман\Desktop\python_dev\django\62\Сoursework\News\source\db.sqlite3</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
<libraries>
<library>
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.34.0/sqlite-jdbc-3.34.0.jar</url>
</library>
<library>
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.34.0/sqlite-jdbc-3.34.0.jar</url>
</library>
</libraries>
</data-source>
</component>
</project>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="2">
<item index="0" class="java.lang.String" itemvalue="django-crispy-forms" />
<item index="1" class="java.lang.String" itemvalue="Markdown" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="3.8 @ Ubuntu (12)" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/source.iml" filepath="$PROJECT_DIR$/.idea/source.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="news/settings.py" />
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="migrations" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="3.8 @ Ubuntu (12)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/webapp/templates" />
<option value="$MODULE_DIR$/accounts/templates" />
</list>
</option>
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
\ No newline at end of file
Проект с кодовым названием NEWS, нужно склонировать, установить зависимости из файла requirements.txt, загрузить фикстуры
\ No newline at end of file
from django.contrib.auth.forms import UserCreationForm
class RegistrationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
fields = ["username", "password1", "password2"]
{% extends 'base.html' %}
{% load crispy_forms_filters %}
{% block content %}
<form action="{% url 'accounts:login' %}" method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-outline-dark log_btn" type="submit">Login</button>
</form>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% load crispy_forms_filters %}
{% block content %}
<div class="log">
<form action="{% url 'accounts:password_change_done' request.user.pk %}" method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-outline-dark log_btn" type="submit">Login</button>
</form>
</div>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% load crispy_forms_filters %}
{% block content %}
<div class="log">
<form action="{% url 'accounts:register' %}" method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-outline-dark log_btn" type="submit">Sign up</button>
</form>
</div>
{% endblock %}
\ No newline at end of file
from django.contrib.auth.views import LoginView, LogoutView, PasswordChangeView
from django.urls import path
from accounts.views import RegisterView
app_name = "accounts"
urlpatterns = [
path("account/login/", LoginView.as_view(), name="login"),
path("account/logout/", LogoutView.as_view(), name="logout"),
path("account/registration/", RegisterView.as_view(), name="register"),
path("account/<int:pk>/change_password", PasswordChangeView.as_view(), name="password_change_done"),
]
from django.shortcuts import render
from django.contrib.auth import get_user_model, login
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.views.generic import CreateView
from accounts.forms import RegistrationForm
class RegisterView(CreateView):
model = get_user_model()
template_name = 'registration/register.html'
form_class = RegistrationForm
success_url = reverse_lazy('webapp:index')
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect("webapp:index")
# Create your views here.
No preview for this file type
[
{
"model": "contenttypes.contenttype",
"pk": 1,
"fields": {
"app_label": "admin",
"model": "logentry"
}
},
{
"model": "contenttypes.contenttype",
"pk": 2,
"fields": {
"app_label": "auth",
"model": "permission"
}
},
{
"model": "contenttypes.contenttype",
"pk": 3,
"fields": {
"app_label": "auth",
"model": "group"
}
},
{
"model": "contenttypes.contenttype",
"pk": 4,
"fields": {
"app_label": "auth",
"model": "user"
}
},
{
"model": "contenttypes.contenttype",
"pk": 5,
"fields": {
"app_label": "contenttypes",
"model": "contenttype"
}
},
{
"model": "contenttypes.contenttype",
"pk": 6,
"fields": {
"app_label": "sessions",
"model": "session"
}
},
{
"model": "contenttypes.contenttype",
"pk": 7,
"fields": {
"app_label": "webapp",
"model": "comment"
}
},
{
"model": "contenttypes.contenttype",
"pk": 8,
"fields": {
"app_label": "webapp",
"model": "post"
}
},
{
"model": "sessions.session",
"pk": "o2zhr73zm9owy1b7x8y0jdlfl7dgsq8h",
"fields": {
"session_data": ".eJxVjMsOwiAQAP-FsyEbnsWjd7-BLOwiVUOT0p6M_64kPeh1ZjIvEXHfatw7r3EmcRZKnH5ZwvzgNgTdsd0WmZe2rXOSI5GH7fK6ED8vR_s3qNjr2LqcpkBGoXW-WGZUgKRNUOASJwSgoNkjWuN1YSLjvhqgkEJiP4n3B_WUOLM:1mic3e:_t5oJmYGaUO-kMKVuqDSZeCfNXMwxzIsFi_EDb_Pl_s",
"expire_date": "2021-11-18T12:41:30.452Z"
}
},
{
"model": "sessions.session",
"pk": "yh2sd6segb04vvvc7kq7kdx4093n57we",
"fields": {
"session_data": ".eJxVjEEOwiAQRe_C2pBCaZm6dO8ZyAwzSNVAUtqV8e7apAvd_vfef6mA25rD1mQJM6uzMur0uxHGh5Qd8B3LrepYy7rMpHdFH7Tpa2V5Xg737yBjy9_aTqOn3iBY55P3IIQpIQsDDwYcWRQAStZ2yKn3BE66CVIcJjPanqJ6fwD13zh0:1miZp6:yWYRpUNJd_f8wMw6qTFSrrgYvYBKw0tjrpGvKiwOQFw",
"expire_date": "2021-11-18T10:18:20.354Z"
}
},
{
"model": "webapp.post",
"pk": 4,
"fields": {
"title": "wknfiowheiJWEFJIF",
"pic": "https://www.planetware.com/wpimages/2019/10/switzerland-in-pictures-most-beautiful-places-matterhorn.jpg",
"text": "WNEINfjnowefj[oKFO\r\nWEKFOWEKFPOMWEFPOEMWPOMWEPOVMWPOEMVLSMV;LDMVL;SMDL;MSLMSMVMSDVMSDOPMVPOWVMOPMSEVMSLVMlkmvLKDS",
"create": "2021-11-04",
"is_active": true
}
},
{
"model": "webapp.post",
"pk": 5,
"fields": {
"title": "Post post",
"pic": "https://media.nature.com/lw800/magazine-assets/d41586-017-08492-y/d41586-017-08492-y_15302384.jpg",
"text": "mweinc[onvjasdnvnvioawenvouanseicsdovnaiovniwenvoiuwnvoiwanevoinaskjvndlkjvnakjsdnvkjasndvkj;nasdkjvnoiwenvoiwenvoi[awnvsd",
"create": "2021-11-04",
"is_active": false
}
},
{
"model": "webapp.post",
"pk": 6,
"fields": {
"title": "POST POPOST",
"pic": "https://www.nme.com/wp-content/uploads/2017/03/Stephen-King-696x442.png",
"text": "WInwfe]iFIEHfehbi\r\nuOHWFOEIJ8/huIOFHnOIJIGVJAERIOJZB0AERJB9DRJB0ISDAJF0OIBJDIFOBJS",
"create": "2021-11-04",
"is_active": true
}
},
{
"model": "auth.permission",
"pk": 1,
"fields": {
"name": "Can add log entry",
"content_type": [
"admin",
"logentry"
],
"codename": "add_logentry"
}
},
{
"model": "auth.permission",
"pk": 2,
"fields": {
"name": "Can change log entry",
"content_type": [
"admin",
"logentry"
],
"codename": "change_logentry"
}
},
{
"model": "auth.permission",
"pk": 3,
"fields": {
"name": "Can delete log entry",
"content_type": [
"admin",
"logentry"
],
"codename": "delete_logentry"
}
},
{
"model": "auth.permission",
"pk": 4,
"fields": {
"name": "Can view log entry",
"content_type": [
"admin",
"logentry"
],
"codename": "view_logentry"
}
},
{
"model": "auth.permission",
"pk": 5,
"fields": {
"name": "Can add permission",
"content_type": [
"auth",
"permission"
],
"codename": "add_permission"
}
},
{
"model": "auth.permission",
"pk": 6,
"fields": {
"name": "Can change permission",
"content_type": [
"auth",
"permission"
],
"codename": "change_permission"
}
},
{
"model": "auth.permission",
"pk": 7,
"fields": {
"name": "Can delete permission",
"content_type": [
"auth",
"permission"
],
"codename": "delete_permission"
}
},
{
"model": "auth.permission",
"pk": 8,
"fields": {
"name": "Can view permission",
"content_type": [
"auth",
"permission"
],
"codename": "view_permission"
}
},
{
"model": "auth.permission",
"pk": 9,
"fields": {
"name": "Can add group",
"content_type": [
"auth",
"group"
],
"codename": "add_group"
}
},
{
"model": "auth.permission",
"pk": 10,
"fields": {
"name": "Can change group",
"content_type": [
"auth",
"group"
],
"codename": "change_group"
}
},
{
"model": "auth.permission",
"pk": 11,
"fields": {
"name": "Can delete group",
"content_type": [
"auth",
"group"
],
"codename": "delete_group"
}
},
{
"model": "auth.permission",
"pk": 12,
"fields": {
"name": "Can view group",
"content_type": [
"auth",
"group"
],
"codename": "view_group"
}
},
{
"model": "auth.permission",
"pk": 13,
"fields": {
"name": "Can add user",
"content_type": [
"auth",
"user"
],
"codename": "add_user"
}
},
{
"model": "auth.permission",
"pk": 14,
"fields": {
"name": "Can change user",
"content_type": [
"auth",
"user"
],
"codename": "change_user"
}
},
{
"model": "auth.permission",
"pk": 15,
"fields": {
"name": "Can delete user",
"content_type": [
"auth",
"user"
],
"codename": "delete_user"
}
},
{
"model": "auth.permission",
"pk": 16,
"fields": {
"name": "Can view user",
"content_type": [
"auth",
"user"
],
"codename": "view_user"
}
},
{
"model": "auth.permission",
"pk": 17,
"fields": {
"name": "Can add content type",
"content_type": [
"contenttypes",
"contenttype"
],
"codename": "add_contenttype"
}
},
{
"model": "auth.permission",
"pk": 18,
"fields": {
"name": "Can change content type",
"content_type": [
"contenttypes",
"contenttype"
],
"codename": "change_contenttype"
}
},
{
"model": "auth.permission",
"pk": 19,
"fields": {
"name": "Can delete content type",
"content_type": [
"contenttypes",
"contenttype"
],
"codename": "delete_contenttype"
}
},
{
"model": "auth.permission",
"pk": 20,
"fields": {
"name": "Can view content type",
"content_type": [
"contenttypes",
"contenttype"
],
"codename": "view_contenttype"
}
},
{
"model": "auth.permission",
"pk": 21,
"fields": {
"name": "Can add session",
"content_type": [
"sessions",
"session"
],
"codename": "add_session"
}
},
{
"model": "auth.permission",
"pk": 22,
"fields": {
"name": "Can change session",
"content_type": [
"sessions",
"session"
],
"codename": "change_session"
}
},
{
"model": "auth.permission",
"pk": 23,
"fields": {
"name": "Can delete session",
"content_type": [
"sessions",
"session"
],
"codename": "delete_session"
}
},
{
"model": "auth.permission",
"pk": 24,
"fields": {
"name": "Can view session",
"content_type": [
"sessions",
"session"
],
"codename": "view_session"
}
},
{
"model": "auth.permission",
"pk": 25,
"fields": {
"name": "Can add comment",
"content_type": [
"webapp",
"comment"
],
"codename": "add_comment"
}
},
{
"model": "auth.permission",
"pk": 26,
"fields": {
"name": "Can change comment",
"content_type": [
"webapp",
"comment"
],
"codename": "change_comment"
}
},
{
"model": "auth.permission",
"pk": 27,
"fields": {
"name": "Can delete comment",
"content_type": [
"webapp",
"comment"
],
"codename": "delete_comment"
}
},
{
"model": "auth.permission",
"pk": 28,
"fields": {
"name": "Can view comment",
"content_type": [
"webapp",
"comment"
],
"codename": "view_comment"
}
},
{
"model": "auth.permission",
"pk": 29,
"fields": {
"name": "Can add post",
"content_type": [
"webapp",
"post"
],
"codename": "add_post"
}
},
{
"model": "auth.permission",
"pk": 30,
"fields": {
"name": "Can change post",
"content_type": [
"webapp",
"post"
],
"codename": "change_post"
}
},
{
"model": "auth.permission",
"pk": 31,
"fields": {
"name": "Can delete post",
"content_type": [
"webapp",
"post"
],
"codename": "delete_post"
}
},
{
"model": "auth.permission",
"pk": 32,
"fields": {
"name": "Can view post",
"content_type": [
"webapp",
"post"
],
"codename": "view_post"
}
},
{
"model": "auth.group",
"pk": 1,
"fields": {
"name": "admins",
"permissions": [
[
"delete_comment",
"webapp",
"comment"
],
[
"add_post",
"webapp",
"post"
],
[
"change_post",
"webapp",
"post"
],
[
"delete_post",
"webapp",
"post"
]
]
}
},
{
"model": "auth.user",
"pk": 1,
"fields": {
"password": "pbkdf2_sha256$260000$MGOkJpfnHcu5empwNMYqnH$KM4/fB1Y9Cd6qhM7UpahUlisTpxWpGL7Dw9MHELAYs0=",
"last_login": "2021-11-04T11:25:32Z",
"is_superuser": true,
"username": "admin",
"first_name": "",
"last_name": "",
"email": "admin@admin.com",
"is_staff": true,
"is_active": true,
"date_joined": "2021-11-03T10:02:31Z",
"groups": [
[
"admins"
]
],
"user_permissions": []
}
},
{
"model": "auth.user",
"pk": 2,
"fields": {
"password": "pbkdf2_sha256$260000$ybcOGjNYyTH1quFNAP2uVp$L2VRoRPW+abvGMTIgqAxpSI781cCkptmxQsb4Z3bOA8=",
"last_login": "2021-11-04T12:41:30.438Z",
"is_superuser": false,
"username": "gogi",
"first_name": "",
"last_name": "",
"email": "",
"is_staff": false,
"is_active": true,
"date_joined": "2021-11-04T12:41:30.231Z",
"groups": [],
"user_permissions": []
}
},
{
"model": "webapp.comment",
"pk": 8,
"fields": {
"author": [
"gogi"
],
"post": 4,
"text": "vamklvmdkfvklad",
"create": "2021-11-04"
}
},
{
"model": "admin.logentry",
"pk": 1,
"fields": {
"action_time": "2021-11-03T10:06:11.683Z",
"user": [
"admin"
],
"content_type": [
"webapp",
"post"
],
"object_id": "1",
"object_repr": "post 1",
"action_flag": 1,
"change_message": "[{\"added\": {}}]"
}
},
{
"model": "admin.logentry",
"pk": 2,
"fields": {
"action_time": "2021-11-03T10:06:13.733Z",
"user": [
"admin"
],
"content_type": [
"webapp",
"post"
],
"object_id": "1",
"object_repr": "post 1",
"action_flag": 2,
"change_message": "[]"
}
},
{
"model": "admin.logentry",
"pk": 3,
"fields": {
"action_time": "2021-11-03T10:06:25.543Z",
"user": [
"admin"
],
"content_type": [
"webapp",
"post"
],
"object_id": "2",
"object_repr": "post 2",
"action_flag": 1,
"change_message": "[{\"added\": {}}]"
}
},
{
"model": "admin.logentry",
"pk": 4,
"fields": {
"action_time": "2021-11-03T10:06:34.438Z",
"user": [
"admin"
],
"content_type": [
"webapp",
"post"
],
"object_id": "3",
"object_repr": "post 3",
"action_flag": 1,
"change_message": "[{\"added\": {}}]"
}
},
{
"model": "admin.logentry",
"pk": 5,
"fields": {
"action_time": "2021-11-04T12:37:40.900Z",
"user": [
"admin"
],
"content_type": [
"auth",
"group"
],
"object_id": "1",
"object_repr": "admins",
"action_flag": 1,
"change_message": "[{\"added\": {}}]"
}
},
{
"model": "admin.logentry",
"pk": 6,
"fields": {
"action_time": "2021-11-04T12:38:00.432Z",
"user": [
"admin"
],
"content_type": [
"auth",
"user"
],
"object_id": "1",
"object_repr": "admin",
"action_flag": 2,
"change_message": "[{\"changed\": {\"fields\": [\"Groups\"]}}]"
}
}
]
......@@ -31,7 +31,6 @@ ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
......@@ -39,6 +38,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'webapp',
'accounts',
'django.contrib.admin',
'crispy_forms'
]
......
......@@ -14,8 +14,10 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('webapp.urls')),
path('', include('accounts.urls')),
]
from django.contrib import admin
# Register your models here.
from webapp.models import Post, Comment
admin.site.register(Post)
admin.site.register(Comment)
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from webapp.models import Post
class PostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Submit'))
class Meta:
model = Post
exclude = ['create']
widgets = {
'is_active': forms.CheckboxInput()
}
class SearchForm(forms.Form):
q = forms.CharField(max_length=30, required=False, label="Search")
# Generated by Django 3.2.9 on 2021-11-03 10:05
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='Post',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200, verbose_name='Post title')),
('pic', models.URLField(blank=True, null=True, verbose_name='Post pics')),
('text', models.TextField(max_length=2000, verbose_name='Post text')),
('create', models.DateField(auto_now_add=True, verbose_name='Post create time')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
],
),
migrations.CreateModel(
name='Comment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(max_length=500, verbose_name='Comment text')),
('create', models.DateField(auto_now_add=True, verbose_name='Comment create time')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to=settings.AUTH_USER_MODEL, verbose_name='Comment author')),
('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='webapp.post', verbose_name='Post')),
],
),
]
from django.contrib.auth import get_user_model
from django.db import models
class Post(models.Model):
pass
title = models.CharField(max_length=200, blank=False, null=False, verbose_name='Post title')
pic = models.URLField(max_length=200, blank=True, null=True, verbose_name='Post pics')
text = models.TextField(max_length=2000, blank=False, null=False, verbose_name='Post text')
create = models.DateField(auto_now_add=True, verbose_name='Post create time')
is_active = models.BooleanField(default=True, verbose_name='Is active')
def __str__(self):
return self.title
class Comment(models.Model):
pass
author = models.ForeignKey(get_user_model(), verbose_name='Comment author', related_name='comments', on_delete=models.CASCADE)
post = models.ForeignKey('webapp.Post', verbose_name='Post', related_name='comments', on_delete=models.CASCADE)
text = models.TextField(max_length=500, blank=False, null=False, verbose_name='Comment text')
create = models.DateField(auto_now_add=True, verbose_name='Comment create time')
def __str__(self):
return self.author
body {
margin: 0;
}
footer {
position: absolute;
bottom: 0;
right: 0;
left: 0;
}
/*BASE*/
.nav_right_container {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.icon {
font-size: 1.5rem;
}
.reg_cont {
margin-right: 10px;
}
/*INDEX*/
/*POST DETAIL*/
.post_detail_container {
margin: 30px auto;
}
.post_d_body {
background: #f0f0f0;
}
.post_d_title {
text-align: center;
}
.post_d_text {
padding: 10px 30px;
}
.post_d_buttons {
display: flex;
justify-content: space-between;
padding: 0 20px;
}
/*COMMENTS*/
.comment_input {
height: 50px;
width: 40rem;
margin-right: 5px
}
.comment_container {
width: 500px;
margin: 10px auto;
border-radius: 3px;
border: 1px darkgray solid;
}
.com_header {
background: #F8F9FA;
text-align: center;
padding: 5px;
}
.com_text {
background: #f0f0f0;
padding: 5px;
}
/*ACCOUNTS*/
.log {
align-items: center;
}
.log_btn {
margin:10px auto;
}
\ No newline at end of file
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.6.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="{% static "css/main.css" %}">
<title>Document</title>
</head>
<body>
{% block header %}
<nav class="navbar navbar-light bg-light border border-bottom-4">
<div class="d-flex justify-content-between w-100 p-2 align-items-center">
<div>
<a class="navbar-brand" title="main page" href="{% url "webapp:index" %}">
<h1 class="logo">News</h1>
</a>
</div>
<div class="nav_right_container">
{% if user.is_authenticated %}
<div style="margin-right: 10px;" class="link_anon d-flex justify-content-between align-items-center">
<form action="{% url "accounts:logout" %}" method="post">
{% csrf_token %}
<button class="btn text-dark btn-link" title="Logout"><i class="bi bi-door-closed icon"></i></button>
</form>
{% if requert.user.is_superuser %}
<a style="margin-right: 10px;" href="{% url "webapp:post_create" %}" class="text-dark" title="Add post"><i class="bi bi-file-plus icon"></i></a>
{% endif %}
<a style="margin-right: 10px;" href="{% url "accounts:password_change_done" request.user.pk %}" class="text-dark" title="Change password"><i class="bi bi-pencil icon"></i></a>
</div>
{% else %}
<div class="link_anon d-flex justify-content-between reg_cont">
<div class="reg_cont">
<a href="{% url "accounts:register" %}" class="text-dark" title="Registration"><i class="bi bi-person-plus icon"></i></a>
</div>
<a href="{% url "accounts:login" %}" class="text-dark" title="Login"><i class="bi bi-door-open icon"></i></a>
</div>
{% endif %}
<div>
<form class="d-flex" action="{% url 'webapp:search' %}" method="get">
<input class="form-control me-2" name="q" type="search" placeholder="Search" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
{% endblock %}
{% block profile %}
{% endblock %}
<div class="container">
<div class="block">
{% block title %}{% endblock %}
{% block content %}
{% endblock %}
</div>
</div>
{% block footer %}
<footer style="background: #F8F9FA" class="p-4 d-flex justify-content-around border border-top-2">
<p>© 2021 NEWS</p>
<p class="fst-italic">
Designed by GoGa Gogich. All rights reserved.
</p>
</footer>
{% endblock %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity=
"sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
\ No newline at end of file
<form action="{% url 'webapp:comment_delete' comment.pk%}" method="post">
{% csrf_token %}
<button type="submit" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span title="Delete" aria-hidden="true">&times;</span>
</button>
</form>
\ No newline at end of file
<form action="{% url 'webapp:comment_create' post.pk %}" method="post">
{% csrf_token %}
<div class="d-flex justify-content-between align-items-between">
<input class="d-block input_comment comment_input" name="text" type="text" placeholder="Write comment">
<button class="btn btn-outline-dark" type="submit">Comment</button>
</div>
</form>
\ No newline at end of file
{% extends "base.html" %}
{% block title %}{% endblock %}
{% block content %}
{% for post in posts %}
<div class="card post_detail_container" style="width: 50rem;">
{% if post.pic %}
<img src="{{ post.pic }}" class="card-img-top" alt="pic">
{% endif %}
<div class="card-body">
<h5 class="card-title post_d_title">{{ post.title }}</h5>
<p class="card-text post_d_text">{{ post.text }}</p>
<hr>
<p class="card-text"><i>{{ post.create }}</i></p>
<a href="{% url 'webapp:post_detail' post.pk %}" class="btn btn-outline-dark">In detail..</a>
</div>
</div>
{% endfor %}
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}{% endblock %}
{% block content %}
<div class="post_create_container">
<h2>Add new Post</h2>
{% crispy form form.helper %}
<a class="btn btn-outline-dark" href="{% url 'webapp:index' %}">Back to main</a>
</div>
{% endblock %}
<form action="{% url 'webapp:post_delete' post.pk %}" method="post">
{% csrf_token %}
<button type="submit" class="btn btn-outline-danger" onclick="return confirm('Are you sure?')">Delete</button>
</form>
\ No newline at end of file
{% extends "base.html" %}
{% block title %}{% endblock %}
{% block content %}
<div class="card post_detail_container" style="width: 50rem;">
{% if post.pic %}
<img src="{{ post.pic }}" class="card-img-top" alt="pic">
{% endif %}
<div class="card-body post_d_body">
<h5 class="card-title post_d_title">{{ post.title }}</h5>
<hr>
<p class="card-text post_d_text">{{ post.text }}</p>
<hr>
<p class="card-text"><i>{{ post.create }}</i></p>
{% if request.user.is_superuser %}
<div class="post_d_buttons">
<a href="{% url 'webapp:post_update' post.pk %}" class="btn btn-outline-dark">Update</a>
{% include 'post/post_delete.html' %}
</div>
{% endif %}
<hr>
{% include 'comment/comment_form.html' %}
</div>
</div>
{% if comments %}
{% for comment in comments %}
<div class="toast comment_container" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header com_header">
{# <img src="..." class="rounded mr-2" alt="...">#}
{% if request.user.is_superuser %}
{% include 'comment/comment_delete.html' %}
{% endif %}
<strong class="mr-auto">{{ comment.author }}</strong>
<small class="text-muted">{{ comment.create }}</small>
</div>
<div class="toast-body com_text">
{{ comment.text }}
</div>
</div>
{% endfor %}
{% endif %}
{% endblock %}
\ No newline at end of file
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}{% endblock %}
{% block content %}
<div class="book_create_container">
<h2>Update Post {{ post.title }}</h2>
{% crispy form form.helper %}
<a class="btn btn-outline-dark" href="{% url 'webapp:index' %}">Back to main</a>
</div>
{% endblock %}
{% extends "base.html" %}
{% block title %}{% endblock %}
{% block content %}
<div class="card" style="width: 18rem; margin: 50px auto;">
<div class="card-header">
<h5>Search results</h5>
</div>
<ul class="list-group list-group-flush">
{% for post in posts %}
<li class="list-group-item"><a style="color: black" href="{% url 'webapp:post_detail' post.pk %}">{{ post.title }}</a></li>
{% empty %}
<li class="list-group-item">No results</li>
{% endfor %}
</ul>
</div>
{% endblock %}
\ No newline at end of file
from django.urls import path
from webapp import views as webapp_views
app_name = "webapp"
urlpatterns = [
path("", webapp_views.PostListView.as_view(), name="index"),
path("post/new/", webapp_views.PostCreateView.as_view(), name="post_create"),
path("post/<int:pk>/", webapp_views.PostDetailView.as_view(), name="post_detail"),
path("post/<int:pk>/edit/", webapp_views.PostUpdateView.as_view(), name="post_update"),
path("post/<int:pk>/delete/", webapp_views.PostDeleteView.as_view(), name="post_delete"),
path("post/<int:p_pk>/comment/new/", webapp_views.CommentCreateView.as_view(), name="comment_create"),
path("comment/<int:pk>/delete/", webapp_views.CommentDeleteView.as_view(), name="comment_delete"),
path("search/", webapp_views.SearchView.as_view(), name="search")
]
from django.shortcuts import render
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
from django.utils.http import urlencode
from django.views.generic import CreateView, ListView, DetailView, UpdateView, DeleteView
from webapp.forms import PostForm, SearchForm
from webapp.models import Post, Comment
class PostListView(ListView):
model = Post
template_name = 'index.html'
context_object_name = 'posts'
ordering = ['-create']
paginate_by = 10
def get_queryset(self):
queryset = super().get_queryset().filter(is_active=True)
return queryset
class PostDetailView(DetailView):
model = Post
template_name = 'post/post_detail.html'
context_object_name = 'post'
pk_url_kwarg = 'pk'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
comments = self.get_object().comments.order_by('-create')
context['comments'] = comments
return context
class PostCreateView(PermissionRequiredMixin, CreateView):
model = Post
template_name = 'post/post_create.html'
form_class = PostForm
permission_required = 'webapp.add_post'
def get_success_url(self):
return reverse('webapp:post_detail', kwargs={"pk": self.object.pk})
class PostUpdateView(PermissionRequiredMixin, UpdateView):
model = Post
context_object_name = 'post'
template_name = 'post/post_update.html'
form_class = PostForm
permission_required = 'webapp.change_post'
def get_success_url(self):
return reverse('webapp:post_detail', kwargs={"pk": self.object.pk})
class PostDeleteView(PermissionRequiredMixin, DeleteView):
model = Post
template_name = 'post/post_delete.html'
pk_url_kwarg = 'pk'
success_url = reverse_lazy('webapp:index')
permission_required = 'webapp.delete_post'
class CommentCreateView(CreateView):
model = Comment
template_name = 'comment/comment_form.html'
fields = ['text']
def form_valid(self, form):
form.instance.post = self.get_object()
form.instance.author = self.request.user
return super().form_valid(form)
def get_object(self, queryset=None):
pk = self.kwargs.get("p_pk")
return get_object_or_404(Post, pk=pk)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['post'] = self.get_object()
return self.get_context_data(context)
def get_success_url(self):
return reverse('webapp:post_detail', kwargs={"pk": self.get_object().pk})
class CommentDeleteView(PermissionRequiredMixin, DeleteView):
model = Comment
template_name = 'comment/comment_delete.html'
pk_url_kwarg = 'pk'
permission_required = 'webapp.delete_comment'
def has_permission(self):
return super().has_permission() or self.object == self.request.user
def get_success_url(self):
return reverse('webapp:post_detail', kwargs={"pk": self.object.post.pk})
class SearchView(ListView):
model = Post
template_name = 'post/search_list.html'
context_object_name = 'posts'
def get(self, request, *args, **kwargs):
self.form = self.get_search_form()
self.search_value = self.get_search_value()
return super().get(request, *args, **kwargs)
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
context['search_form'] = self.form
if self.search_value:
context['query'] = urlencode({'q': self.search_value})
return context
def get_queryset(self):
query_set = super().get_queryset()
if self.search_value:
query = Q(title__icontains=self.search_value) | Q(text__icontains=self.search_value)
query_set = query_set.filter(query)
return query_set
def get_search_form(self):
return SearchForm(self.request.GET)
def get_search_value(self):
if self.form.is_valid():
return self.form.cleaned_data['q']
# Create your views here.
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