Skip to content

Desenvolvendo um blog simples onde vamos utilizar CRUD quatro operações essenciais para gerenciar e aplicar conceitos basicos para que você conheça o poder desse framework incrível.

Notifications You must be signed in to change notification settings

opencodigos/DjangoProjeto1-BlogSimples

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Django CRUD Blog Simples

Primeiro vídeo tutorial de como criar um blog Simples com Django. Nesses tutorial vamos trabalhar com CRUD para que usuário iniciante tenha seu primeiro contato com esse framework incrível.

Playlist 10 Vídeos Link

Vamos desenvolver um Blog com Django. Para conhecer mais a plataforma e conceitos.

Ambiente Virtual Linux/Windows
  • Ambiente Virtual Linux/Windows

    Lembrando… Precisa ter Python instalado no seu ambiente.

    https://www.python.org/downloads/

    Criar o ambiente virtual Linux/Windows

    ## Windows
    python -m venv .venv
    source .venv/Scripts/activate # Ativar ambiente
    
    ## Linux 
    ## Caso não tenha virtualenv. "pip install virtualenv"
    virtualenv .venv
    source .venv/bin/activate # Ativar ambiente

    Instalar os seguintes pacotes.

    pip install django
    pip install pillow

    Para criar o arquivo requirements.txt

    pip freeze > requirements.txt
Criando o Projeto
  • Criando o Projeto

    Criando o projeto

    “core” é nome do seu projeto e quando colocamos um “.” depois do nome do projeto significa que é para criar os arquivos na raiz da pasta. Assim não cria subpasta do projeto.

    django-admin startproject core .

    Testar a aplicação

    python manage.py runserver
Criando App
  • Criando App

    Vamos criar nosso aplicativo no Django.

    Para criar a aplicação no Django rode comando abaixo. “posts_app” é nome do seu App.

    python manage.py startapp posts_app

    Agora precisamos registrar nossa aplicação no INSTALLED_APPS localizado em settings.py.

    posts_app/models.py

    from django.db import models
    
    # Create your models here.
    class Posts(models.Model):
        title = models.CharField(max_length=100)
        description = models.TextField()
        image = models.ImageField(upload_to='images/')
        create_at = models.DateTimeField(auto_now_add=True)

    posts_app/admin.py

    Temos que registrar nosso modelo Posts para aparecer no dashboard do Django.

    from django.contrib import admin
    from .models import Posts
    
    # Register your models here.
    admin.site.register(Posts)

    Migrações.

    python manage.py makemigrations
    python manage.py migrate

    Vamos acessar o Dashboard Admin do Django precisamos ter um usuário.

    python manage.py createsuperuser

    agora acessar a plataforma.

    python manage.py runserver
    
    # http://127.0.0.1:8000/admin/

    Conseguimos fazer os testes no dashboard do Django e criar algumas postagens.

    Ao tentar acessar link da imagem aparece esse erro.

    Esse erro por que precisamos configurar nossos arquivos static no projeto.

Arquivos Static
  • Arquivos Static

    Vamos configurar nossos arquivos static

    import os 
    
    # base_dir config
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    TEMPLATE_DIR = os.path.join(BASE_DIR,'templates')
    STATIC_DIR=os.path.join(BASE_DIR,'static')
    
    # Database
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 
        }
    }
    
    # Passando para portugues BR
    LANGUAGE_CODE = 'pt-br'
    TIME_ZONE = 'America/Sao_Paulo'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True
    
    STATIC_ROOT = os.path.join(BASE_DIR,'static')
    STATIC_URL = '/static/' 
    
    MEDIA_ROOT=os.path.join(BASE_DIR,'media')
    MEDIA_URL = '/media/'

    core/urls.py

    from django.contrib import admin
    from django.conf import settings
    from django.conf.urls.static import static
    from django.urls import path
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    ]
    
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # Adicionar Isto
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # Adicionar Isto

    Acessar a aplicação e testar.

    Agora as imagens serão encontradas na raiz do seu projeto. Pois já configuramos e dizemos para nosso App buscar lá. Isso é valido para qualquer arquivos estático. Incluindo Templates.

    Outro detalhes que vamos configurar é aqui. Como você pode ver na imagem abaixo todos os registros de criamos ficaram com nomenclatura de object. Em grandes continuidades isso pode gerar confusão. Vamos organizar isso.

    posts_app/models.py Adicionar str e Meta.

    from django.db import models
    
    # Create your models here.
    class Posts(models.Model):
        title = models.CharField(max_length=100)
        description = models.TextField()
        image = models.ImageField(upload_to='images/')
        create_at = models.DateTimeField(auto_now_add=True)
        
        def __str__(self): # adicionar isso
            return self.title
        
        class Meta:  # adicionar isso
            verbose_name = 'Post'
            verbose_name_plural = 'Posts'
            ordering = ['id']

    Já temos nossa lista de registro com nomes.

Templates
  • Templates

    Vamos configurar nossas views e Templates para deixar as coisas mais visual. Em nosso posts_app vamos criar uma pasta chamada templates

    Porque templates ? No arquivo settings.py definimos que “TEMPLATE_DIR” é onde vamos buscar nossos templates. Podemos criar pasta templates em qualquer lugar da nossa aplicação que nosso projeto vai entender e buscar esses templates. Isso vale para arquivos static tambem.

    Template Base

    1 - criar um arquivo base base.html onde vamos renderizar nosso conteúdo.

    {% load static %} # Adicionar isso
    <!DOCTYPE html>
    <html lang="en">
    <head>
    		<meta charset="UTF-8">
    		<meta http-equiv="X-UA-Compatible" content="IE=edge">
    		<meta name="viewport" content="width=device-width, initial-scale=1.0">
    		<title>{% block title %}{% endblock %}</title> # Adicionar isso
    </head>
    <body>
    		{% block content %} # adicionar isso
    		{% endblock %} 
    </body>
    </html>
Listar Posts
  • Listar Posts

    Listar Postagens

    Arquivo post-list.html vamos listar as postagens que criamos.

    {% extends 'base.html' %}
    
    {% block title %}Lista Postagens{% endblock %}
    
    {% block content %}
    	<h1>Todos os Posts</h1>
    
    	<!-- lista os posts aqui -->
    
    {% endblock content %}

    posts_app/views.py

    from django.shortcuts import render
    from posts_app.models import Posts
    
    # Create your views here.
    def post_list(request):
        template_name = 'post-list.html' # template
        posts = Posts.objects.all() # query com todas as postagens
        context = { # cria context para chamar no template
            'posts': posts
            }
        return render(request, template_name, context) # render

    No nosso app posts_app/urls.py criar arquivo urls.py.

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.post_list, name='post-list'),
    ]

    Não podemos esquecer de registrar as rotas da aplicação no projeto. Então no arquivo urls.py do projeto. core/urls.py.

    from django.urls import path, include ## adicionar include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    	 	path('', include('posts_app.urls')), # Adicionar isso.
    ] 

    No template post-list.html vamos chamar nosso contexto que definimos na view. “posts”.

    Chamando dessa maneira {{posts}} em nosso template ele retorna uma query com vários registro.

    Então precisamos fazer um for para “indentar” essas informações no template. Vou deixar {{post.description}} comentado. Por ser uma lista essa informação ficaria interessante na rota detalhes do post.

    {% extends 'base.html' %}
    {% block title %}Lista Postagens{% endblock %}
    {% block content %}
    	<h1>Todos os Posts</h1>
    	# Adiciona esse for
    	{% for post in posts %} 
    			<img src="{{post.image.url}}" width="150" alt="{{post.title}}">
    			<p>{{post.title}}</p>
    			<!-- <p>{{post.description}}</p> --> 
    	{% endfor %}
    {% endblock content %}
Criar Posts
  • Criar Posts

    Criar Posts

    posts_app/forms.py criar arquivo forms.py

    from django import forms
    from .models import Post
    
    class PostForm(forms.ModelForm):
        class Meta:
            model = Post # nosso modelo
            fields = ['title', 'description', 'image'] # campos do nosso modelo poderia ser '__all__'

    posts_app/views.py

    from django.contrib import messages
    from django.urls import reverse
    from django.http import HttpResponseRedirect
    from posts_app.forms import PostsForm
    
    def post_create(request):
        if request.method == 'POST': # para metodo POST
            form = PostsForm(request.POST, request.FILES) # pega as informações do form
            if form.is_valid(): # se for valido
                form = form.save(commit=False)
                form.save() # salva
                
                messages.success(request, 'O post foi criado com sucesso') # mensagem quando cria o post
                return HttpResponseRedirect(reverse('post-list')) # coloquei para retornar post-list
            
        form = PostsForm() # senão carrega o formulario  
        return render(request, 'post-form.html', {"form": form}) # nesse template

    *posts_app/*urls.py

    path('post-create', views.post_create, name='post-create'),

    Criar arquivo posts_app/templates/post-form.html.

    {% extends 'base.html' %}
    
    {% block title %}Criar/Atualizar Postagem{% endblock %}
    
    {% block content %} 
    	
    	<form method="post" 
    		action="{% if request.method == 'POST' %}{% url 'post-create' %}{% endif %}" 
    		enctype="multipart/form-data">
    
    		{% csrf_token %}
    		{{ form.as_p }}
    		<button type="submit">Criar</button> 
    	</form>
    
    {% endblock content %}

    posts_app/templates/post-list.html Adiciona a chamada para criar um post

    <a href="{% url 'post-create' %}">Criar um Post</a> # adiciona

    Configura mensagem. posts_app/templates/_message.html

    {% if messages %}
    <div class="messages">
        {% for message in messages %}
        <div {% if message.tags %} class="alert {{ message.tags }}"{% endif %} role="alert">{{ message }}</div>
        {% endfor %}
    </div>
    {% endif %}

    Adiciona na base

    <body> 
    	{% include '_message.html' %} ## adiciona isso.
    	{% block content %}
    	{% endblock %} 
    </body>
Ver Post
  • Ver Post

    Detalhes do post

    posts_app/views.py

    def post_detail(request, id):
        template_name = 'post-detail.html' # template
        post = Posts.objects.get(id=id) # Metodo Get
        context = { # cria context para chamar no template
            'post': post
            }
        return render(request, template_name, context) # render

    posts_app/urls.py

    path('post-detail/<int:id>/', views.post_detail, name='post-detail'),

    Criar template posts_app/templates/post-detail.html

    {% extends 'base.html' %}
    {% block title %}Detalhes Postagem{% endblock %}
    {% block content %}
    		<h1>Detalhes do Post: {{post.title}}</h1>
    		<p>{{post.create_at}}</p>
    		<img src="{{post.image.url}}" width="300" alt="{{post.title}}">
    		<p>{{post.description}}</p>  
    {% endblock content %}

    Para criar o clique para ir para detalhe da postagem. Modificar o template post-list.html Passamos um ID para rota e acessamos detalhes da postagem.

    	{% for post in posts %}  
    			<a href="{% url 'post-detail' post.id %}">Ver</a> ## Adicionar isso
    			<img src="{{post.image.url}}" width="150" alt="{{post.title}}">
    			<p>{{post.title}}</p> 
    	{% endfor %}
Atualizar Post
  • Atualizar Post

    Atualizar Post

    Vamos aproveitar o mesmo template que utilizamos para criar uma postagem. Então não precisa criar template HTML.

    posts_app/views.py

    def post_update(request, id):
        post = get_object_or_404(Posts, id=id) # id do post
        form = PostsForm(request.POST or None, request.FILES or None, instance=post) # pega as informações do form
        if form.is_valid(): # se for valido
            form.save() # salva
            
            messages.success(request, 'O post foi atualizado com sucesso') # mensagem quando cria o post
            return HttpResponseRedirect(reverse('post-detail', args=[post.id])) # coloquei para retornar post-list
             
        return render(request, 'post-form.html', {"form": form}) # nesse template

    posts_app/urls.py

    path('post-update/<int:id>', views.post_update, name='post-update'),

    posts_app/templates/post-form.html

    action="{% if request.method == 'POST' %}{% url 'post-create' %}{% endif %}"

    posts_app/templates/post-detail.html

    <a href="{% url 'post-update' post.id %}">Atualizar</a>
Deletar Post
  • Deletar Post

    Deletar Postagem

    posts_app/views.py

    from django.urls import reverse
    from django.http import HttpResponseRedirect
    
    def post_delete(request, id): 
        post = Posts.objects.get(id=id) # pelo ID pega o objeto
        post.delete() # deletar
        messages.success(request, 'O post foi deletado com sucesso') # quando deleta post
        return HttpResponseRedirect(reverse('post-list')) # retorna rota post-list

    *posts_app/*urls.py

    path('post-delete/<int:id>/', views.post_delete, name='post-delete'),

    *posts_app/templates/*post-detail.html

    <a href="{% url 'post-delete' post.id %}">Deletar</a> # adicionar botão delete

    Para colocar mensagem de confirme

    def post_delete(request, id): 
        post = Posts.objects.get(id=id) # pelo ID pega o objeto
        if request.method == 'POST':         
            post.delete()
            messages.success(request, 'O post foi deletado com sucesso') # quando deleta post 
            return HttpResponseRedirect(reverse('post-list')) # retorna rota post-list
        return render(request, 'post-delete.html') # nesse template

    myapp/post-delete.html

    {% extends 'base.html' %}
    {% block title %}Deletar Postagem{% endblock %}
    {% block content %}
    <form method="post">
        {% csrf_token %}
        <p>Deseja deletar esse post ?</p>
        <button type="submit">Deletar</button>
    </form> 
    {% endblock content %}
Bootstrap Configuração
  • Bootstrap Configuração

    Bootstrap configuração

    Doc: https://getbootstrap.com/docs/5.2/getting-started/introduction/

    Com Base na documentação para utilizar os recursos Boostrap basta adicionar as tags de CSS e JS. No HTML da Pagina Base.

    <!-- CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
    
    <!-- JS-->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

    posts_app/templates/base.html

    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<title>{% block title %}{% endblock %}</title>
    
    	<!-- CSS -->
    	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
    
    </head>
    <body> 
    	{% include '_messages.html' %}
    	
    	{% block content %}
    	{% endblock %} 
     
    	<!-- JS-->
    	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
    </body>
    </html>
Bootstrap Templates
  • Bootstrap Templates

    posts_app/templates/post-list.html

    {% extends 'base.html' %}
    
    {% block title %}Lista Postagens{% endblock %}
    
    {% block content %}
    	<a class="btn btn-success" href="{% url 'post-create' %}">Criar um Post</a>
    
    	<h1>Todos os Posts</h1>
    	<div class="row row-cols-1 row-cols-md-3 g-4">
    		{% for post in posts %} 
    		<div class="col">
    			<div class="card h-100 text-bg-light">
    				<img src="{{post.image.url}}" class="card-img-top" alt="{{post.title}}">
    				<div class="card-body">
    					<p class="card-text">{{post.title}}</p>
    					<a class="btn btn-info" href="{% url 'post-detail' post.id %}">Ver</a>
    				</div>
    			</div> 
    		</div>
    		{% endfor %} 
    	</div>	 
    {% endblock content %}

    posts_app/templates/post-detail.html

    {% extends 'base.html' %}
    
    {% block title %}Detalhes Postagem{% endblock %}
    
    {% block content %}
    	<div class="text-center">
    
    		<a class="btn btn-warning" href="{% url 'post-update' post.id %}">Atualizar</a>
    		<a class="btn btn-danger" href="{% url 'post-delete' post.id %}">Deletar</a>
    
    		<h1>Detalhes do Post: {{post.title}}</h1>
    	
    		<p>{{post.create_at}}</p> 
    	
    		<img src="{{post.image.url}}" width="100%" alt="{{post.title}}">
    	 
    		<p>{{post.description}}</p>  
    
    	</div>
    {% endblock content %}

    *posts_app/templates/*post-form.html

    {% extends 'base.html' %}
    
    {% block title %}Criar/Atualizar Postagem{% endblock %}
    
    {% block content %}  
    
    <div class="row justify-content-center">
    	<div class="col-md-6">
    		<h1>{% if request.path == '/post-create' %}Criar Postagem{% else %}Atualizar Post{% endif %}</h1>
    		
    		<form method="post" action="{% if request.method == 'POST' %}{% url 'post-create' %}{% endif %}" 
    			enctype="multipart/form-data">
    			{% csrf_token %}
    			{{ form.as_p }}
    			<button class="btn btn-success" type="submit">Criar</button> 
    		</form>
    
    	</div>
    	
    </div>
    
    {% endblock content %}

    posts_app/forms.py

    Aplicar as classes boostrap

    from django import forms
    from .models import Posts
    
    class PostsForm(forms.ModelForm):
        class Meta:
            model = Posts
            fields = ['title', 'description', 'image']
    
        def __init__(self, *args, **kwargs): # Adiciona 
            super().__init__(*args, **kwargs)  
            for field_name, field in self.fields.items():   
                  field.widget.attrs['class'] = 'form-control'

    myapp/settings.py

    import os
    from django.contrib.messages import constants as messages
    
    MESSAGE_TAGS = {
            messages.DEBUG: 'alert-secondary',
            messages.INFO: 'alert-info',
            messages.SUCCESS: 'alert-success',
            messages.WARNING: 'alert-warning',
            messages.ERROR: 'alert-danger',
     }
    

About

Desenvolvendo um blog simples onde vamos utilizar CRUD quatro operações essenciais para gerenciar e aplicar conceitos basicos para que você conheça o poder desse framework incrível.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published