En el siguiente post vamos a ver como crear un blog totalmente administrable utilizando el Framework Django
Descarga el código fuente desde el repositorio GitHub en el siguiente enlace
https://github.com/NorbeyCollazos/Blog_con_Django
Lo primero que hacemos es crear el proyecto, para eso abrimos la consola. En mi caso voy a utilizar el editor de código Visual Studio Code, por lo tanto abro la terminal y me ubico en la carpeta donde quiero que se guarde el proyecto (cd nombre_de_la_carpeta)
A continuación ejecutamos el siguiente comando para crear el proyecto
django-admin startproject Blog_con_Django
Ahora nos ubicamos en la carpeta que se ha creado (cd Blog_con_Django) y ejecutamos el siguiente comando para verificar que se ha creado correctamente
python manage.py runserver
Ahora creamos la primer app que la llamaremos mainapp
python manage.py startapp mainapp
ahora debemos agregar la app en el archivo settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'mainapp'
]
Ahora dentro de la app mainapp vamos a crear las vistas, urls y templates
En este caso he descargado una plantilla html para adelantar el proceso de diseño de las páginas. Voy a utilizar la siguiente plantilla que se puede descargar en la siguiente dirección: Devblog V1.1
Dentro de la app mainapp creamos un directorio con el nombre (templates), otro con el nombre (static)
Dentro del directorio templates creamos un directorio con el nombre (layouts) otro con el nombre (mainapp) y otro con el nombre (users)
En el directorio static se deben copiar todas las carpetas que contienen los archivos CSS, JS y Imagenes
En el directorio layouts creamos un archivo con el nombre layout.html que contenga la estructura de la pagina web que se va mostrar en todas las paginas
<!DOCTYPE html>
<html lang="en">
<head>
<title>
{% block title %}
{% endblock %}
</title>
<!-- Meta -->
{% load static %}
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Blog Template">
<meta name="author" content="Xiaoying Riley at 3rd Wave Media">
<link rel="shortcut icon" href="{% static 'assets/images/favicon.ico' %}">
<!-- FontAwesome JS-->
<script defer src="https://use.fontawesome.com/releases/v5.7.1/js/all.js" integrity="sha384-eVEQC9zshBn0rFj4+TU78eNA19HMNigMviK/PU/FFjLXqa/GKPgX58rvt5Z8PLs7" crossorigin="anonymous"></script>
<!-- Theme CSS -->
<link id="theme-style" rel="stylesheet" href="{% static 'assets/css/theme-1.css' %}">
</head>
<body>
<header class="header text-center">
<h1 class="blog-name pt-lg-4 mb-0"><a href="index.html">Anthony's Blog</a></h1>
<nav class="navbar navbar-expand-lg navbar-dark" >
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navigation" aria-controls="navigation" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div id="navigation" class="collapse navbar-collapse flex-column" >
<div class="profile-section pt-3 pt-lg-0">
<img class="profile-image mb-3 rounded-circle mx-auto" src="{% static 'assets/images/profile.png' %}" alt="image" >
<div class="bio mb-3">Hi, my name is Anthony Doe. Briefly introduce yourself here. You can also provide a link to the about page.<br><a href="about.html">Find out more about me</a></div><!--//bio-->
<ul class="social-list list-inline py-3 mx-auto">
<li class="list-inline-item"><a href="#"><i class="fab fa-twitter fa-fw"></i></a></li>
<li class="list-inline-item"><a href="#"><i class="fab fa-linkedin-in fa-fw"></i></a></li>
<li class="list-inline-item"><a href="#"><i class="fab fa-github-alt fa-fw"></i></a></li>
<li class="list-inline-item"><a href="#"><i class="fab fa-stack-overflow fa-fw"></i></a></li>
<li class="list-inline-item"><a href="#"><i class="fab fa-codepen fa-fw"></i></a></li>
</ul><!--//social-list-->
<hr>
</div><!--//profile-section-->
<ul class="navbar-nav flex-column text-left">
<li class="nav-item active">
<a class="nav-link" href="index.html"><i class="fas fa-home fa-fw mr-2"></i>Blog Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="blog-post.html"><i class="fas fa-bookmark fa-fw mr-2"></i>Blog Post</a>
</li>
<li class="nav-item">
<a class="nav-link" href="about.html"><i class="fas fa-user fa-fw mr-2"></i>About Me</a>
</li>
</ul>
<div class="my-2 my-md-3">
<a class="btn btn-primary" href="https://themes.3rdwavemedia.com/" target="_blank">Get in Touch</a>
</div>
</div>
</nav>
</header>
<div class="main-wrapper">
{% block titulo_buscador %}
{% endblock %}
<section class="blog-list px-3 py-5 p-md-5">
<div class="container">
{% block content %}
{% endblock %}
</div>
</section>
<footer class="footer text-center py-2 theme-bg-dark">
<!--/* This template is released under the Creative Commons Attribution 3.0 License. Please keep the attribution link below when using for your own project. Thank you for your support. :) If you'd like to use the template without the attribution, you can buy the commercial license via our website: themes.3rdwavemedia.com */-->
<small class="copyright">Designed with <i class="fas fa-heart" style="color: #fb866a;"></i> by <a href="http://themes.3rdwavemedia.com" target="_blank">Xiaoying Riley</a> for developers</small>
</footer>
</div><!--//main-wrapper-->
<!-- *****CONFIGURE STYLE (REMOVE ON YOUR PRODUCTION SITE)****** -->
<div id="config-panel" class="config-panel d-none d-lg-block">
<div class="panel-inner">
<a id="config-trigger" class="config-trigger config-panel-hide text-center" href="#"><i class="fas fa-cog fa-spin mx-auto" data-fa-transform="down-6" ></i></a>
<h5 class="panel-title">Choose Colour</h5>
<ul id="color-options" class="list-inline mb-0">
<li class="theme-1 active list-inline-item"><a data-style="{% static 'assets/css/theme-1.css' %}" href="#"></a></li>
<li class="theme-2 list-inline-item"><a data-style="{% static 'assets/css/theme-2.css' %}" href="#"></a></li>
<li class="theme-3 list-inline-item"><a data-style="{% static 'assets/css/theme-3.css' %}" href="#"></a></li>
<li class="theme-4 list-inline-item"><a data-style="{% static 'assets/css/theme-4.css' %}" href="#"></a></li>
<li class="theme-5 list-inline-item"><a data-style="{% static 'assets/css/theme-5.css' %}" href="#"></a></li>
<li class="theme-6 list-inline-item"><a data-style="{% static 'assets/css/theme-6.css' %}" href="#"></a></li>
<li class="theme-7 list-inline-item"><a data-style="{% static 'assets/css/theme-7.css' %}" href="#"></a></li>
<li class="theme-8 list-inline-item"><a data-style="{% static 'assets/css/theme-8.css' %}" href="#"></a></li>
</ul>
<a id="config-close" class="close" href="#"><i class="fa fa-times-circle"></i></a>
</div><!--//panel-inner-->
</div><!--//configure-panel-->
<!-- Javascript -->
<script src="{% static 'assets/plugins/jquery-3.3.1.min.js' %}"></script>
<script src="{% static 'assets/plugins/popper.min.js' %}"></script>
<script src="{% static 'assets/plugins/bootstrap/js/bootstrap.min.js' %}"></script>
<!-- Style Switcher (REMOVE ON YOUR PRODUCTION SITE) -->
<script src="{% static 'assets/js/demo/style-switcher.js' %}"></script>
</body>
</html>
Ahora pasamos al archivo views.py donde agregamos la vista para la página de inicio
def index(request):
return render(request, 'mainapp/index.html',{
'title': 'Inicio'
})
Ahora pasamos al archivo urls.py donde vamos a agregar la ruta de la página de inicio
from django.contrib import admin
from django.urls import path
import mainapp.views
urlpatterns = [
path('admin/', admin.site.urls),
path('', mainapp.views.index, name="index")
]
Ahora pasamos al archivo models.py para crear el modelo de la tabla Entradas del blog
from django.db import models
from ckeditor.fields import RichTextField
from django.contrib.auth.models import User
# Create your models here.
class Entrada(models.Model):
title = models.CharField(max_length=150, verbose_name="Título")
content = RichTextField(verbose_name="Contenido")
image = models.ImageField(default='null', verbose_name="Imagen", upload_to="articles")
public = models.BooleanField(verbose_name="¿Publicado?")
user = models.ForeignKey(User, editable=False, verbose_name="Usuario", on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Creado el")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Actualizado el")
class Meta:
verbose_name = "Entrada"
verbose_name_plural = "Entradas"
def __str__(self):
return self.title
Ahora se debe crear la migración
python manage.py makemigrations
Luego migramos al código sql
python manage.py sqlmigrate mainapp 0001
Y luego migramos
python manage.py migrate
No nos olvidemos de agregar la app ckeditor en los setting.py debido a que se está usando en el campo de content
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ckeditor',
'mainapp.apps.MainappConfig'
]
Ahora vamos al archivo admin.py para agregar el modelo al panel de administración y realizar algunas configuraciones
from django.contrib import admin
from .models import Entrada
class EntradaAdmin(admin.ModelAdmin):
readonly_fields = ('user','created_at', 'updated_at') #para mostrar campos
search_fields = ('title', 'content', 'user__username') #para crear fitro de busqueda
list_display = ('title', 'user', 'public', 'created_at') #para mstrar columnas
list_filter = ('public', 'user__username') #para filtrar
#este codigo es para guardar el usuario por defecto
def save_model(self, request, obj, form, change):
if not obj.user_id:
obj.user_id = request.user.id
obj.save()
# Register your models here.
admin.site.register(Entrada, EntradaAdmin)
A continuación vamos a crear el superusuario para acceder al panel de administración
python manage.py createsuperuser
Ahora vamos al archivo apps.py para cambiar el nombre de la tabla que aparece en el panel
from django.apps import AppConfig
class MainappConfig(AppConfig):
name = 'mainapp'
verbose_name = 'Gestión de entradas'
despues vamos al archivo settings.py para cambiar la forma de agregar la por la siguiente
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ckeditor',
'mainapp.apps.MainappConfig'
]
A continuación realizamos las configuraciones para poder subir imágenes
creamos una carpeta con el nombre (media) en la raíz del proyecto, dentro de esa carpeta creamos un directorio con el nombre (articles) o según el nombre que le hayamos colocado en la propiedad upload_to en el campo image del modelo
Ahora vamos al archivo settings.py y agregamos lo siguiente
#Para Media MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Ahora vamos al archivo urls.py y agregamos lo siguiente
from django.conf import settings #Ruta para imagenes if settings.DEBUG: from django.conf.urls.static import static urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
A continuación vamos realizar la consulta para mostrar la lista de entradas y de una vez integrando el paginator. Pra eso vvamos al archivo views.py y agregamos el siguiente codigo en la vista del index que es donde se va mostrar el listado
from mainapp.models import Entrada
from django.core.paginator import Paginator
# Create your views here.
def index(request):
entradas = Entrada.objects.all()
#paginar los articulos
paginator = Paginator(entradas, 2)
#obtener el numero de la pagina
page = request.GET.get('page')
page_entradas = paginator.get_page(page)
return render(request, 'mainapp/index.html',{
'title': 'Inicio',
'entradas': page_entradas
})
Ahora vamos al archivo index.html y realizamos el ciclo for para mostrar el listado de entradas
{% for entrada in entradas %}
<div class="item mb-5">
<div class="media">
{% if entrada.image != 'null' and entrada.image.url|length >= 1 %}
<img class="mr-3 img-fluid post-thumb d-none d-md-flex" src="{{entrada.image.url}}" alt="image">
{% else %}
<img class="mr-3 img-fluid post-thumb d-none d-md-flex" src="{% static 'assets/images/blog/blog-post-thumb-7.jpg' %}" alt="image">
{% endif %}
<div class="media-body">
<h3 class="title mb-1"><a href="">{{entrada.title}}</a></h3>
<div class="meta mb-1"><span class="date">{{entrada.created_at}}</span><span class="time"></span><span class="comment"><a href="#"></a></span></div>
<div class="intro">{{entrada.content|safe}}</div>
<a class="more-link" href="{% url 'detalle_entrada' %}">Read more →</a>
</div><!--//media-body-->
</div><!--//media-->
</div><!--//item-->
{% endfor %}
Ahora vamos a mostrar los botones para la paginación
<nav class="blog-nav nav nav-justified my-5">
{% if entradas.has_previous %}
<a class="nav-link-prev nav-item nav-link rounded-left" href="?page={{entradas.previous_page_number}}">Anterior<i class="arrow-prev fas fa-long-arrow-alt-left"></i></a>
{% endif %}
{% if entradas.has_next %}
<a class="nav-link-next nav-item nav-link rounded-right" href="?page={{entradas.next_page_number}}">Siguiente<i class="arrow-next fas fa-long-arrow-alt-right"></i></a>
{% endif %}
</nav>
Ahora hacemos lo siguiente para mostrar el detalle de la entrada
Creamos un archivo detalle_entrada.html con la siguiente estructura
{% extends 'layouts/layout.html' %} {% block title %}{{entrada.title}}{% endblock %} {% block content %} {% load static %} <header class="blog-post-header"> <h2 class="title mb-2">{{entrada.title}}</h2> <div class="meta mb-3"><span class="date">{{entrada.created_at}}</span><span class="time"></span><span class="comment"><a href="#"></a></span></div> </header> <div class="blog-post-body"> <figure class="blog-banner"> {% if entrada.image != 'null' and entrada.image.url|length >= 1 %} <a href="#"><img class="img-fluid" src="{{entrada.image.url}}" alt="image"></a> {% else %} <a href="#"><img class="img-fluid" src="{% static 'assets/images/blog/no_image.jpg' %}" alt="image"></a> {% endif %} </figure> <p>{{entrada.content|safe}}</p> </div> {% endblock %}
Creamos la vista en el archivo views.py
def detalle_entrada(request, entrada_id): entrada = Entrada.objects.get(id=entrada_id) return render(request,'mainapp/detalle_entrada.html',{ 'entrada': entrada })
Creamos la url en el archivo urls.py
path('detalle-entrada/<int:entrada_id>', mainapp.views.detalle_entrada, name="detalle_entrada"),
A continuación vamos a realizar el proceso para el registro de usuarios
En este caso lo primero que hacemos es entrar al panel de administración con el supersusuario que hemos registrado, luego vamos a crear un grupo con los permisos que le queramos dar a los usuarios que se registren
Dentro de la mainapp vamos a crear un archivo forms.py con el que vamos a personalizar el formulario de registro
from django import forms from django.core import validators from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User class RegisterForm(UserCreationForm): is_staff = forms.BooleanField(required=True) class Meta: model = User fields = ['username', 'email', 'first_name', 'last_name', 'password1', 'password2','is_staff']
Creamos el archivo register.html en el directorio templates/users
{% block title %}{{title}}{% endblock %} {% block titulo_buscador %} <section class="cta-section theme-bg-light py-5"> <div class="container text-center"> <h2 class="heading">{{title}}</h2> <div class="intro">Regístrate para acceder al panel de administración y crear tus entradas</div> </div><!--//container--> </section> {% endblock %} {% block content %} {{register_form.errors}} <form class="signup-form justify-content-center pt-3" method="POST"> {% csrf_token %} <div class="form-group"> {% for field in register_form %} {{field.label}} {{field}} {% endfor %} <br><span>Seleccione el <strong>Is staff</strong> para que pueda acceder al panel de administración</span> </div> <br> <input type="submit" class="btn btn-primary" value="Registrarse"></input> </form> {% endblock %}
Agregamos lo siguiente en el archivo views.py
from django.shortcuts import render, redirect from mainapp.models import Entrada from django.core.paginator import Paginator from mainapp.forms import RegisterForm import sqlite3 def registro_usuario(request): register_form = RegisterForm() if request.method == 'POST': register_form = RegisterForm(request.POST) if register_form.is_valid(): objeto = register_form.save() idr = str(objeto.id) cursor.execute("INSERT INTO auth_user_groups (user_id, group_id)VALUES ("+idr+", 1);") conexion.commit() return redirect('/admin') return render(request, 'users/register.html',{ 'title': 'Registro de usuario', 'register_form': register_form })
Creamos la ruto en el archivo urls.py
path('registro/', mainapp.views.registro_usuario, name="registro_usuario"),
Y por último si queremos podemos cambiar el idioma del panel de administración a español, para eso vamos al archivo settings.py y cambiamos LANGUAJE_CODE
LANGUAGE_CODE = 'es-es'
0 Comentarios