init
This commit is contained in:
0
blog/__init__.py
Normal file
0
blog/__init__.py
Normal file
26
blog/admin.py
Normal file
26
blog/admin.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from ordered_model.admin import OrderedModelAdmin
|
||||
|
||||
from .models import Article, Tag, Category
|
||||
from .forms import ArticleForm
|
||||
|
||||
|
||||
@admin.register(Article)
|
||||
class ArticleAdmin(admin.ModelAdmin):
|
||||
form = ArticleForm
|
||||
list_display = ('title', 'description', 'author')
|
||||
exclude = ["author"]
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
obj.author = request.user
|
||||
return super().save_model(request, obj, form, change)
|
||||
|
||||
|
||||
@admin.register(Category)
|
||||
class CategoryAdmin(OrderedModelAdmin):
|
||||
list_display = ('name', 'move_up_down_links')
|
||||
|
||||
|
||||
admin.site.register(Tag)
|
||||
|
||||
6
blog/apps.py
Normal file
6
blog/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BlogConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'blog'
|
||||
13
blog/forms.py
Normal file
13
blog/forms.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django import forms
|
||||
from tinymce.widgets import TinyMCE
|
||||
|
||||
from blog.models import Article
|
||||
|
||||
|
||||
class ArticleForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Article
|
||||
exclude = "__all__"
|
||||
widgets = {
|
||||
"content": TinyMCE()
|
||||
}
|
||||
32
blog/jinja2/blog/article_detail.html
Normal file
32
blog/jinja2/blog/article_detail.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends "blog/layout.html" %}
|
||||
|
||||
{% block css %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/toolbar/prism-toolbar.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/show-language/prism-show-language.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<header>
|
||||
<h2>
|
||||
{{ article.title }}
|
||||
</h2>
|
||||
</header>
|
||||
<p>{{ article.description.replace("\n", "<br />")|safe }}</p>
|
||||
<div class="blog_content line-numbers">
|
||||
{{ article.content|safe }}
|
||||
</div>
|
||||
</article>
|
||||
{% endblock %}
|
||||
34
blog/jinja2/blog/article_list.html
Normal file
34
blog/jinja2/blog/article_list.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "blog/layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="article_list">
|
||||
{% for article in articles %}
|
||||
<a href="{{ url("blog:article_detail", args=[article.pk, slugify(article.title)]) }}">
|
||||
<article>
|
||||
{% set article_image %}
|
||||
<section class="article_image">
|
||||
{# <img src="{{ static("images/no_mage_600_x_400.svg") }}">#}
|
||||
<img src="{{ static("images/no_image.png") }}" alt="No image"/>
|
||||
</section>
|
||||
{% endset %}
|
||||
|
||||
{% set article_text %}
|
||||
<section class="article_text">
|
||||
<header>
|
||||
<h2>{{ article.title }}</h2>
|
||||
</header>
|
||||
<p>{{ article.description.replace("\n", "<br/>")|safe }}</p>
|
||||
</section>
|
||||
{% endset %}
|
||||
|
||||
{{ article_image }}
|
||||
{{ article_text }}
|
||||
</article>
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
<p>Aucun article</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
11
blog/jinja2/blog/layout.html
Normal file
11
blog/jinja2/blog/layout.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block css %}
|
||||
{{ super() }}
|
||||
{{ stylesheet_pack("blog") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ super() }}
|
||||
{{ javascript_pack("blog") }}
|
||||
{% endblock %}
|
||||
54
blog/migrations/0001_initial.py
Normal file
54
blog/migrations/0001_initial.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-19 08:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Article',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('description', models.TextField()),
|
||||
('content', models.TextField()),
|
||||
('date_created', models.DateTimeField(auto_now_add=True)),
|
||||
('date_modified', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Category',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('order', models.PositiveIntegerField(db_index=True, editable=False, verbose_name='order')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Categories',
|
||||
'ordering': ('order',),
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Comment',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('content', models.TextField()),
|
||||
('date_created', models.DateTimeField(auto_now_add=True)),
|
||||
('date_modified', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Tag',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
],
|
||||
),
|
||||
]
|
||||
48
blog/migrations/0002_initial.py
Normal file
48
blog/migrations/0002_initial.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-19 08:31
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('blog', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='author',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='category',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.category'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='comment',
|
||||
name='article',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.article'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='comment',
|
||||
name='author',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='comment',
|
||||
name='response_to',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.comment'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='tags',
|
||||
field=models.ManyToManyField(blank=True, to='blog.tag'),
|
||||
),
|
||||
]
|
||||
0
blog/migrations/__init__.py
Normal file
0
blog/migrations/__init__.py
Normal file
44
blog/models.py
Normal file
44
blog/models.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from django.db import models
|
||||
|
||||
from ordered_model.models import OrderedModel
|
||||
|
||||
|
||||
class Article(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.TextField()
|
||||
content = models.TextField()
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
date_modified = models.DateTimeField(auto_now=True)
|
||||
category = models.ForeignKey("Category", on_delete=models.CASCADE, null=True, blank=True)
|
||||
tags = models.ManyToManyField("Tag", blank=True)
|
||||
author = models.ForeignKey("user.User", on_delete=models.CASCADE, null=True, blank=True)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
|
||||
class Category(OrderedModel):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
class Meta(OrderedModel.Meta):
|
||||
verbose_name_plural = "Categories"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Comment(models.Model):
|
||||
author = models.ForeignKey("user.User", on_delete=models.CASCADE)
|
||||
article = models.ForeignKey("Article", on_delete=models.CASCADE)
|
||||
content = models.TextField()
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
date_modified = models.DateTimeField(auto_now=True)
|
||||
response_to = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True)
|
||||
32
blog/templates/blog/article_detail.html
Normal file
32
blog/templates/blog/article_detail.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends "blog/layout.html" %}
|
||||
|
||||
{% block css %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/toolbar/prism-toolbar.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/show-language/prism-show-language.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<article>
|
||||
<header>
|
||||
<h2>
|
||||
{{ article.title }}
|
||||
</h2>
|
||||
</header>
|
||||
<p>{{ article.description.replace("\n", "<br />")|safe }}</p>
|
||||
<div class="blog_content line-numbers">
|
||||
{{ article.content|safe }}
|
||||
</div>
|
||||
</article>
|
||||
{% endblock %}
|
||||
34
blog/templates/blog/article_list.html
Normal file
34
blog/templates/blog/article_list.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "blog/layout.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="article_list">
|
||||
{% for article in articles %}
|
||||
<a href="{% url "blog:article_detail" article.pk article.title|slugify %}">
|
||||
<article>
|
||||
{# {% set article_image %}#}
|
||||
{# <section class="article_image">#}
|
||||
{# <img src="{{ static("images/no_mage_600_x_400.svg") }}">#}
|
||||
{# <img src="{% static "images/no_image.png" %}" alt="No image"/>#}
|
||||
{# </section>#}
|
||||
{# {% endset %}#}
|
||||
{##}
|
||||
{# {% set article_text %}#}
|
||||
{# <section class="article_text">#}
|
||||
{# <header>#}
|
||||
{# <h2>{{ article.title }}</h2>#}
|
||||
{# </header>#}
|
||||
{# <p>{{ article.description|safe|linebreaks }}</p>#}
|
||||
{# </section>#}
|
||||
{# {% endset %}#}
|
||||
|
||||
{# {{ article_image }}#}
|
||||
{# {{ article_text }}#}
|
||||
</article>
|
||||
</a>
|
||||
{% empty %}
|
||||
<p>Aucun article</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
11
blog/templates/blog/layout.html
Normal file
11
blog/templates/blog/layout.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block css %}
|
||||
{{ super }}
|
||||
{# {{ stylesheet_pack("blog") }}#}
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ super }}
|
||||
{# {{ javascript_pack("blog") }}#}
|
||||
{% endblock %}
|
||||
3
blog/tests.py
Normal file
3
blog/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
9
blog/urls.py
Normal file
9
blog/urls.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = 'blog'
|
||||
urlpatterns = [
|
||||
path("", views.ArticleListView.as_view(), name="article_list"),
|
||||
path("<int:pk>-<str:slug>/", views.ArticleDetailView.as_view(), name="article_detail"),
|
||||
]
|
||||
15
blog/views.py
Normal file
15
blog/views.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.views.generic import ListView, DetailView
|
||||
|
||||
from blog.models import Article
|
||||
|
||||
|
||||
class ArticleListView(ListView):
|
||||
model = Article
|
||||
template_name = 'blog/article_list.html'
|
||||
context_object_name = 'articles'
|
||||
|
||||
|
||||
class ArticleDetailView(DetailView):
|
||||
model = Article
|
||||
template_name = 'blog/article_detail.html'
|
||||
context_object_name = 'article'
|
||||
Reference in New Issue
Block a user