Python e Django Parte 04: “Ligação” dos registros/objetos com o usuário

Documentação dos Sistemas de Autenticação do Django

https://docs.djangoproject.com/en/2.2/topics/auth/default/

Nesta etapa, vamos relacionar nossos modelos com a classe “User” do Django para podermos separar os objetos por usuário, de modo que um usuário tenha seus próprios registros no nosso sistema e que um usuário não acesse os registros de outros usuários.

Importe o User no models.py para poder criar chave estrangeira com ele

from django.contrib.auth.models import User

Crie um atributo na sua classe, neste caso criei no Animal

class Animal(models.Model):
    tipo = models.ForeignKey(Tipo, on_delete=models.PROTECT)
    ...
    telefone = models.CharField(max_length=17)
    usuario = models.ForeignKey(User, on_delete=models.PROTECT)

    def __str__(self):
        return "{} - {}/{}".format(self.nome, self.raca, self.tipo)

Execute o makemigrations para preparar seu banco de dados com as modificações

python manage.py makemigrations adocao

Esta mensagem indica que você está alterando uma tabela no banco que já tem registros. Como não falamos que ele pode ser “blank” e “null” você precisa fornecer um valor padrão. Por isso, vamos na opção “1” e depois digitar um valor qualquer para ser preenchido na nova coluna “usuario”, por exemplo ”0”.

Execute o migrate para atualizar o banco

python manage.py migrate   

Inicie o servidor novamente e acesse a página para cadastrar um animal

python manage.py runserver

Tente cadastrar um animal e você terá o erro:

Isso aconteceu porque você também deve informar um usuário, mas no formulário não tem ele. Você pode atualizar suas views e colocar “usuario” nos “fields”, porém esse não é o jeito certo.

É aqui que entra um novo método que iremos sobrescrever nas views: o form_valid

Documentação do form_valid

https://docs.djangoproject.com/en/2.2/topics/class-based-views/generic-editing/

O form_valid é o método chamado depois que submetemos um formulário, seja ele para inserir, alterar ou excluir. Ele vai verificar se os campos foram preenchidos, se se os valores estão de acordo e todas as outras verificações que se deve fazer. Por fim, ele cria um objeto e salva no banco de dados (quando chamamos o super).

Vá no “adocao/views.py” e procure o “AnimalCreate”. Ele já tem um método que sobrescrevemos, o “get_context_data”. Agora vamos sobrescrever o form_valid:

def form_valid(self, form):
        return super().form_valid(form)

Agora vamos pegar o usuário que está “logado” e inserir ele como “usuario” nesse animal

Precisamos pegar o usuário antes de chamar o super(), se não ele vai dar aquele mesmo erro. Então, adicione form.instance.usuario = self.request.user antes dele:

def form_valid(self, form):
    # Define o usuário como usuário logado
    form.instance.usuario = self.request.user
    url = super().form_valid(form)
    return url

O “form.instance” vai manipular uma instância desse formulário com todos os dados recebidos antes de salvar no banco. Por isso, pegamos o “.usuario” porque é o nome do atributo criado na classe. O usuário logado sempre vai estar dentro do “request.user”. Aqui precisamos acessar ele pelo “self” porque estamos dentro de uma classe e queremos o usuário que fez essa requisição de salvar um animal.

A instrução retorna o endereço para onde redirecionar o usuário. 

Fazer coisas depois de salvar o objeto no banco

É possível fazer coisas depois de salvar o objeto no banco. No exemplo anterior, adicionamos um usuário antes de chamar o super(). Basta fazer antes do return:

def form_valid(self, form):
    # Define o usuário como usuário logado
    form.instance.usuario = self.request.user
    url = super().form_valid(form)
    # código a fazer depois de salvar objeto no banco
    self.object.atributo = “algo”
    # Salva o objeto novamente
    self.object.save()
    return url

É possível acessar o objeto que foi criado pelo self.object. O método save() agora existe para salvar as alterações que você fez, por exemplo.

Como listar somente as Classes que são do “User”

Vamos alterar a view “AnimalList” dentro de “adocao/views.py” para listar somente os objetos que o próprio usuário que está logado cadastrou. No momento, nossa view é simples:

class AnimalList(LoginRequiredMixin, ListView):
    model = Animal
    template_name = "adocao/listas/list_animal.html"

As views que herdam a classe “ListView” tem um método que é chamado para listar todos os objetos daquela classe no banco. Nós podemos sobrescrever ele para colocar uma condição diferente do listar todos.

Método para alterar a listagem padrão de objetos

Crie o método “get_queryset” e altere o “object_list”:

def get_queryset(self):
    # O object_list armazena uma lista de objetos de um ListView
    self.object_list = Animal.objects.filter(usuario=self.request.user)
    return self.object_list

Pode ver alguma de suas listas como tem um for lá para o “object_list”.

Permitir que somente o usuário dono do objeto altere ou exclua o objeto

Uma maneira de garantir que o usuário não vai alterar o ID da sua URL para tentar ver outro registro é alterando o método padrão da sua classe que herdou um DeleteView ou UpdateView. Esse método é o “get_object”. É bem parecido com o da lista, porém ele recebe um ID pela URL para buscar exatamente um objeto e não uma lista deles.

Vamos fazer um procedimento que vai resultar uma tela de erro 404 se o usuário tentar burlar nosso site. No “adocao/views.py” faça a importação:

# Método que busca um objeto. Se não existir, da um erro 404
from django.shortcuts import get_object_or_404

Crie o método a seguir no “AnimalUpdate”:

# Altera a query para buscar o objeto do usuário logado
def get_object(self, queryset=None):
    self.object = get_object_or_404(Animal, pk=self.kwargs['pk'], usuario=self.request.user)
    return self.object

O método “get_object_or_404” precisa de, pelo menos, dois parâmetros: a classe em que será feita a busca e os atributos que ela vai procurar. Neste caso procuramos pela chave primária (pk) e pelo usuário logado. Tente acessar o cadastro de algum animal com outro usuário e terá esse erro.

pk e usuario são atributos de Animal

self.kwargs[‘pk’] pega a chave primária da URL. Esse “pk” vem lá da URL:

path('editar/animal/<int:pk>/', …..)

Excluir somente objetos do usuário logado

O procedimento é exatamente o mesmo. Basta adicionar o método a seguir no seu “AnimalDelete”:

# Altera a query para buscar o objeto do usuário logado
def get_object(self, queryset=None):
    self.object = get_object_or_404(Animal, pk=self.kwargs['pk'], usuario=self.request.user)
    return self.object

Fazer consultas personalizadas – Documentação

https://docs.djangoproject.com/pt-br/2.2/ref/models/querysets/

É possível fazer consultas personalizadas no banco de dados. Para mais detalhes, veja a documentação acima.

Algumas consultas interessantes

Listar todos os objetos:

Classe.objects.all()

Contar todos os objetos:

Classe.objects.all().count()

Buscar um objeto:

Classe.objects.get(pk=5)

Fazer uma consulta que retorna um ou mais objetos:

Classe.objects.filter(estado=”PR”)

Consulta tudo que contém “Rafa”:

Classe.objects.get(nome__icontains=”Rafa”)

Criar um objeto:

Classe.objects.create(atributo1=”Rafael”, atr2=”Bla bla”, atr3=objeto)

Tudo isso é útil para se usar no “get_context_data” e enviar dados a mais para um template

Listar todos os animais na página inicial

No “get_context_data” do “PaginaInicialView” dentro do adocao/views.py crie uma nova entrada que vai listar os últimos 10 animais cadastrados:

context['ultimos_animais'] = Animal.objects.all().reverse()[:10]

Atualize o template para listar os objetos

No seu index.html

{% for animal in ultimos_animais %}
<div class="float-left m-2 p-3 animais-list">
  <img width="150" height="150" src="{{animal.foto}}" alt="">
  <div class="animal-desc">
    {{animal.tipo.descricao}}
    </div>
    <span>{{animal.raca.descricao}}</span>
</div>
{% empty %}
<span>Nenhum animal cadastrado.</span>
{% endfor %}

Como verificar o grupo do usuário no template

É possível ver todos os grupos do usuário no template.Você consegue “pegar” o grupo como objeto pelo comando:

request.user.groups.all.0

Para ver se o nome é “Administrador” é necessário pegar o “name” dele. Por exemplo:

{% if request.user.groups.all.0.name == "Administrador" %}
<h3>Olá Admin</h3>
{% else %}
<h3>Olá usuário comum</h3>
{% endif %}

Python e Django – Parte 02: Criação das classes (modelos) e das Views para inserir, alterar, excluir e listar objetos

Documentação das Views baseadas em classes

https://docs.djangoproject.com/pt-br/2.2/ref/class-based-views/generic-editing/

Criando um usuário administrador

Primeiro temos que criar um usuário que possa acessar o site de administração. Rode o seguinte comando:

$ python manage.py createsuperuser

Acesse: http://localhost:8000/admin/

Criando modelos

No arquivo models.py de alguma de suas aplicações/módulos, crie uma classe simples com os seguintes atributos:

from django.db import models
# Create your models here.
class Estado(models.Model):
sigla = models.CharField(max_length=2)
nome = models.CharField(max_length=50)

    def __str__(self):
        return self.sigla + " - " + self.nome
class Cidade(models.Model):
    nome = models.CharField(max_length=50)
    estado = models.ForeignKey(Estado, on_delete=models.PROTECT)

    def __str__(self):
        return self.nome + " - " + self.estado.sigla
class Pessoa(models.Model):
    nome = models.CharField(max_length=50, verbose_name="Qual seu nome?", help_text="Digite seu nome completo")
    nascimento = models.DateField(verbose_name='data de nascimento')
    email = models.CharField(max_length=100)
    cidade = models.ForeignKey(Cidade, on_delete=models.PROTECT)

    def __str__(self):
        return self.nome + ' - ' + str(self.nascimento)

A classe Cidade é uma extensão da classe “Model” que está dentro do pacote “models”. Dentro dela você pode criar vários atributos.

Existem diversos tipos (https://docs.djangoproject.com/pt-br/2.2/ref/models/fields/#field-types), alguns mais comuns são:

  • models.CharField(…) – Campo de texto comum (input do tipo texto)
  • models.TextField(…) – Campo de texto grande (textarea)
  • models.DateField(…) – vai ser um campo de data
  • models.DateTimeField(…) – vai ser um campo de data e hora
  • models.IntegerField(…) – valores inteiros
  • models.DecimalField(…) – valores decimais

Propriedades (https://docs.djangoproject.com/pt-br/2.2/ref/models/fields/#field-options):

  • max_length – tamanho máximo de caracteres.
  • verbose_name – Nome (label) que vai aparecer no formulário para identificar o campo/atributo. 
  • help_text – Texto extra de ajuda para ser mostrado com o “widget” do formulário. É útil para documentar mesmo que seu campo não seja usado em um formulário.
  • null – Se True, o Django pode usar valores nulos (null) no banco de dados. Padrão é False
  • blank – Se True, é permitido o campo estar em “branco” (vazio). O padrão é False.
  • default – O valor padrão para o campo.
  • unique – Se True, aquele atributo vai ser único no banco de dados. O padrão é False.

Para os campos de data, ainda deve-ser preencher dois atributos:

  • auto_now=True – Adiciona a data/hora toda vez que o objeto é salvo no banco. Geralmente, usado para verificar a última data/hora de modificação do objeto.
  • auto_now_add=True – Adiciona a data/hora toda vez que o objeto é criado no banco. Geralmente, usado para guardar a data que o objeto foi criado.

Campos relacionais (https://docs.djangoproject.com/pt-br/2.2/ref/models/fields/#foreignkey):

  • models.ForeignKey(Classe, on_delete=models.PROTECT) – chave estrangeira representada por um select no formulário. Precisa informar a classe do relacionamento e o modo de relação quando algum objeto da Classe for excluído (PROTECT, CASCADE, etc)

Opções adicionas de configuração de modelos (classe Meta): https://docs.djangoproject.com/pt-br/2.2/ref/models/options/

Sincronizando seu banco de dados com o models

Ao executar makemigrations, você está dizendo Django que você fez algumas mudanças em seus modelos (neste caso, você fez novas modificações) e que você gostaria que as alterações sejam armazenadas como uma migração. Para isso, execute:

$ python manage.py makemigrations seu_modulo_app

Agora rode o migrate para criar essas tabelas dos modelos no seu banco de dados:

$ python manage.py migrate

Acesse: http://localhost:8000/admin/

Ative os modelos criados no painel do administrador

No arquivo admin.py, importe todos os modelos do seu módulo e os ative no site administrativo:

from .models import *
admin.site.register(Estado)
admin.site.register(Cidade)
admin.site.register(Pessoa)

Acesse: http://localhost:8000/admin/

Criando uma método para cadastrar alguma coisa

No arquivo views.py é necessário importar todos os modelos, assim como fizemos no admin:

from .models import *

Também já iremos importar um método para redirecionar o usuário depois de efetuar o cadastro:

from django.urls import reverse_lazy

Por fim, vamos importar as Views (classes) que utilizaremos como “Pai” para nossas telas de cadastro (inserir, alterar e excluir):

from django.views.generic.edit import CreateView, UpdateView, DeleteView

Agora podemos criar nossas classes conforme o exemplo abaixo:

class EstadoCreate(CreateView):
model = Estado
fields = ['sigla', 'nome']
template_name = 'formulario.html'
success_url = reverse_lazy('index')
class CidadeCreate(CreateView):
model = Cidade
fields = ['nome', 'estado']
template_name = 'formulario.html'
success_url = reverse_lazy('index')

Agora basta fazer esse mesmo esquema para todos as classes que você deseja criar um formulário de cadastro no seu projeto.

Criando um formulário padrão para usar em diversos modelos

Você pode criar um arquivo na pasta “templates” chamado “formulario.html”, por exemplo. Dentro dele ajuste o layout como preferir e crie um formulário conforme abaixo:

<form method="post">
     {% csrf_token %}
     {{ form.as_p }}
     <button type="submit" class="btn btn-success">
            Cadastrar
     </button>
</form>

Não é necessário fazer validação de campos obrigatórios.

Criando a URL para cadastrar um modelo

No arquivo urls.py, crie um novo registro apontando para o método que você criou lá no views.py:

path('cadastrar/estado/', EstadoCreate.as_view(), name="cadastrar-estado"),
path('cadastrar/cidade/', CidadeCreate.as_view(), name="cadastrar-cidade"),

Utilizando o formulários do Bootstrap4

Existe um plugin (https://django-bootstrap4.readthedocs.io/en/latest/) que faz a geração do formulário e das mensagens de erro de validação conforme o Bootstrap 4. Para ativá-lo, vá no settings.py, procure por INSTALLED_APPS e adicione o módulo do plugin. Adicione, também, a constante no settings para definir o tipo padrão de templates logo depois do INSTALED_APPS.:

INSTALLED_APPS = [
    ...
    'crispy_forms',
]

CRISPY_TEMPLATE_PACK = 'bootstrap4'

No seu “formulario.html”, por exemplo, carregue o plugin depois de dar um load no static:

{% load crispy_forms_tags %}

No código HTML do formulário altere {{ form.as_p }} para {{ form|crispy }}

Agora atualize a página.

Criando uma tela para atualizar

O processo para atualizar registros é muito parecido com o CreateView. Portanto, altere apenas a classe que o método lá no views.py extende para UpdateView. O restante é a mesma coisa. Por exemplo:

class EstadoUpdate(UpdateView):
model = Estado
fields = ['sigla', 'nome']
template_name = 'formulario.html'
success_url = reverse_lazy('index')

Para criar a URL é necessário passar o ID do registro que será alterado e qual o tipo dele. Por padrão, todas as tabelas no Django criam um campo “id” do tipo inteiro. Então, crie uma nova url no seu urls.py:

path('atualizar/estado/<int:pk>/', EstadoUpdate.as_view(), name="atualizar-estado"),

Acesse http://localhost:8000/atualizar/estado/1/

Criando tela para excluir

Mesmo esquema, porém estendendo a classe DeleteView e não é necessário colocar o atributo “fields”:

class EstadoDelete(DeleteView):
model = Estado
template_name = 'formulario.html'
success_url = reverse_lazy('index')

Exemplo de url:

path('excluir/estado/<int:pk>/', EstadoDelete.as_view(), name="deletar-cidade"),

Usando o mesmo form, vai parecer que você está inserindo/salvando um registro. Então, crie um novo formulário personalizado com uma mensagem de exclusão:

<form method="post">
    {% csrf_token %}
    <p>Tem certeza que deseja excluir o registro "{{ object }}"?</p>
    <input type="submit" class="btn btn-danger" value="Sim, excluir.">
</form>

Listando objetos do banco de dados

https://docs.djangoproject.com/pt-br/2.2/ref/class-based-views/generic-display/

Importe o método ListView:

from django.views.generic.list import ListView

Crie um método no views.py que extende ListView e informe qual o modelo será usado e o template:

class EstadoList(ListView):
model = Estado
template_name = 'adocao/listar_estados.html'

Agora a tela de listagem você tem que fazer uma para cada por causa dos nomes dos atributos de cada modelo. Exemplo:

<table class="table table-striped">
    <tr>
        <th>ID</th>
        <th>Sigla</th>
        <th>Nome</th>
        <th>Opções</th>
    </tr>
    {% for estado in object_list %}
    <tr>
        <td>{{estado.pk}}</td>
        <td>{{estado.sigla}}</td>
        <td>{{estado.nome}}</td>
        <td>
            editar excluir
        </td>
    </tr>
    {% empty %}
    <tr>
        <td colspan="3">Nenhuma cidade cadastrada!</td>
    </tr>
    {% endfor %}
</table>

Por fim, a url para acessar a página criada:

path('listar/estados/', EstadoList.as_view(), name="listar-estados"),

Agora, para colocar os links para as páginas de “alterar” e “excluir”, modifique a tabela adicionando a URL no formato do Django, passando o “pk” como parâmetro:

<a href="{% url 'editar-estado' estado.pk %}" class="btn btn-warning">Editar</a>
<a href="{% url 'excluir-estado' estado.pk %}" class="btn btn-danger">Excluir</a>

Um parâmetro pode ser passado para uma URL da seguinte forma:

{% url 'editar-estado' objeto.atributo %}

Um link para adicionar um estado também pode ser adicionado no listar_estado.html:

<a href="{% url 'cadastrar-estado' %}">Adicionar estado</a>

Por fim, altere o EstadoCreate, EstadoUpdate e EstadoDelete para redirecionar o usuário para a lista e não mais para o index:

success_url = reverse_lazy("listar-estados")

Python e Django – Parte 01: Criação de um projeto, configuração e criação de uma URL


Trabalhar no ambiente virtual Django (Linux):
$ source /opt/virtualenv/django/bin/activate

Trabalhar no ambiente virtual Django (Windows):
workon django

Criando um projeto:
$ django-admin startproject Adocao

No Adocao/settings.py alterar configurações para o português do Brasil:

LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'America/Sao_Paulo'

Executar a criação de tabelas no banco e do conteúdo necessário para o gerenciamento do próprio Django

$ python manage.py migrate

Crie um Super Usuário para você (administrador):

$ python manage.py createsuperuser

Iniciar o servidor Django (padrão porta 8000)

$ python manage.py runserver

Se preferir, pode utilizar outra porta

$ python manage.py runserver 8080 (para definir, por exemplo, a porta 8080)

Outro IP

$ python manage.py runserver x.x.x.x:8000 (para rodar na rede local/Internet)

Ou de forma automática com seu IP da rede local

$ python manage.py runserver 0:8000 (para rodar na rede local/Internet)

Criando seu primeiro módulo (app) no projeto

$ python manage.py startapp cadastros

Registre seu app no seu projeto

É necessário ativar seu app no projeto lá no arquivo Adocao/settings.py. 

INSTALLED_APPS = [
'cadastros.apps.CadastrosConfig',
'django.contrib.admin',
...

Criando a primeira tela com classes (método mais utilizado desde a versão 2), conhecido como Class-based Views para realizar as tarefas do seu sistema, como inserir, cadastrar, exibir uma página, etc.

No arquivo Adocao/cadastros/views.py importe a classe genérica para exibir uma página simples e depois crie sua primeira classe para “renderizar” um template (HTML):

from django.views.generic import TemplateView
# Create your views here.

class IndexView(TemplateView):
    template_name = "index.html"

Como funcionam as classes dentro do “views”:

class NomeDaPaginaView(ClassePai):
template_name = "sua_pagina.html"

Criando um template em HTML para ser usado pelas Views

Primeiro altere a configuração do arquivo Adocao/Adocao/settings.py lá na configuração dos templates:

Procure por: ‘DIRS’: [],

E troque por: ‘DIRS’: [ os.path.join(BASE_DIR, ‘templates’) ],

Agora crie uma pasta chamada ‘templates‘ dentro da pasta da sua aplicação ‘animais’. Dentro dela você pode criar as páginas HTML que vai usar como suas telas (templates). Por exemplo: animais/templates/index.html

Definindo as URLS do seu sistema

Por padrão, os endereços ficam registrados nos arquivos urls.py. Cada app pode ter seus próprios endereços e o seu Projeto (Adocao) também pode ter as suas. 

Primeiro crie o arquivo “urls.py” dentro do seu app: animais/urls.py. 

Faça a importação da biblioteca que gerencia as urls e das classes/métodos criados nos views. 

from django.urls import path
from .views import IndexView

Crie uma url dentro do vetor de urls desse app. Os parâmetros são (nessa ordem): endereço, método/classe do views, nome da url no sistema.

urlpatterns = [
path('', IndexView.as_view(), name="index"),
]

Exemplo para criar novas URLS no seu projeto:

path('endereço_de_url/algo_mais/', NomeDaSuaView.as_view(), name="index"),

Adicione as URLS do app como URLS do projeto

Edite o arquivo Adocao/urls.py e inclua a biblioteca “include” depois de importar a biblioteca “path”.

from django.urls import path, include

Dentro da sua lista de urls, adicione um nome padrão para importar todas as suas urls do app:

urlpatterns = [
# Vai incluir todas as URLS do app animais neste padrão
path('', include('animais.urls')),
  path('admin/', admin.site.urls),
]

Se deixar ‘’ (aspas vazias) não precisa digitar nada na URL pra aceitar este padrão.

Definindo o diretório STATIC para armazenar seu CSS, imagens, JS, etc.

Dentro do diretório Adocao, raiz do projeto e não junto com settings.py, crie uma pasta chamada “static” e coloque lá todo seu css, js, imagens, etc.

Somente os arquivos HTML ficam dentro da pasta template de cada app porque eles podem ser exclusivos daquele app. A ideia da pasta static é disponibilizar as imagens, js e css para todos os apps e não somente um.

No arquivo Adocao/settings.py acrescente uma configuração para o Django procurar a pasta static na raiz do seu projeto (você pode ter várias pastas statics no seu PC):

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

Na primeira linha de todo arquivo HTML você precisa importar a pasta static do seu projeto:

{% load static %}

Agora é só usar conforme o exemplo abaixo para referenciar o local dela:

<img strc="{% static "img/example.jpg" %}" alt="My image"/>

Sempre em vez de colocar o caminho real, deve ser utilizado o esquema do static acima para referenciar algo que tem lá.

Reaproveitando um template

No Django é possível reutilizar um arquivo html (template) reescrevendo apenas algumas partes dele. Para isso, crie blocos de código no seu arquivo de modelo. Por exemplo:

modelo.html

<!DOCTYPE html>
<html lang="pt-br">
  <head>
    <meta charset="utf-8">
    …
  </head>
  <body>

  {% block menu %}
    <div class=”header”>
...
    </div>
  {% endblock %}

  {% block conteudo %}
    <div class=”container”>
...
    </div>
  {% endblock %}

  {% block rodape %}
    <div class=”footer”>
...
    </div>
  {% endblock %}

  </body>
</html>

No seu arquivo que deve ser igual a este anterior, pasta “estender” ele como se fosse uma herança e depois só é necessário reescrever os blocos que você quer alterar. Exemplo:

pagina_inicial.html

{% extends 'modelo.html' %}
{% block conteudo %}
  <div class="container">
    <div class="row">
      <div class="col-sm pt-5">
        <h3>Mah oe :D</h3>
       </div>
    </div>
  </div>
{% endblock %}

Instalação e utilização de ambientes virtuais no Windows

Este tópico tem como objetivo guiar a instalação e criação de ambientes virtuais (virtualenv) no Windows.

Considerando que você já tem o Python instalado, bem como as variáveis de ambiente e o “pip”, siga o procedimento a seguir.

– Instalar pacote para criação de ambientes virtuais
pip install virtualenv

– Instalar pacote para gerenciamento dos ambientes virtuais
pip install virtualenvwrapper-win

– Crie um ambiente virtual
mkvirtualenv nome_do_ambiente

– Ative o ambiente virtual recém criado
workon nome_do_ambiente

Pronto. Agora é só instalar os pacotes que deseja ter nesse ambiente virtual que você acabou de criar e ativar. Você pode ter quantos ambientes desejar e eles, por padrão, ficam dentro no diretório Envs dentro da pasta do usuário. Por exemplo: C:\Users\rafael\Envs

O procedimento a seguir serve para instalação do Django e de mais três coisas úteis para ele: o bootstrap, o braces para controle de acesso e o crispy-forms para geração de formulários conforme os padrões do bootstrap. Não esqueça de ativar o ambiente virtual que você deseja instalar os pacotes: workon nome_do_ambiente.

– Instalação dos pacotes no ambiente virtual desejado.
pip install django
pip install django-bootstrap4
pip install django-braces
pip install django-crispy-forms

Convolução e Correlação

Este código faz a Correlação em uma imagem com uma máscara simples de pesos 1 e tamanho 3×3. É possível ver que a imagem resultante da convolução teve um leve “borramento”.

O tempo de execução do algoritmo para aplicar a máscara simples foi de 2.331 segundos. Com a imagem “percorrendo” a máscara, o tempo foi de 0.00454 segundos. Desta última forma, há maneiras implícitas de executar um for para percorrer algumas linhas e colunas da imagem, o que ajuda a tornar o processo muito mais rápido.

# -*- coding: utf-8 -*-
"""
@author: Rafael Zottesso
"""

# Apenas para contagem de tempo
import timeit

# Outros imports necessários
import numpy as np
import cv2

# Cria uma função para fazer a correlação simples, movendo a máscara sobre a imagem
def correlacao_comum(img, img_corr, mascara):

 # Percorre cada pixel da imagem
 for x in range(img.shape[0]):
 for y in range(img.shape[1]):

 # Usa o try porque algumas coordenadas não existem, assim não apresenta o erro. As bordas não estão sendo consideradas.
 try:
 
 # Cálculo da máscara coluna a coluna: multuplica o peso que está na máscara pela intensidade do pixel

 ### Máscara simples, primeira coluna ##
 m = img[x-1][y+1] * mascara[0][0]
 m += img[x-1][y] * mascara[1][0]
 m += img[x-1][y-1] * mascara[2][0]

 # Segunda coluna
 m += img[x][y+1] * mascara[0][1]
 m += img[x][y] * mascara[1][1]
 m += img[x][y-1] * mascara[2][1]
 
 # Terceira coluna
 m += img[x+1][y+1] * mascara[0][2]
 m += img[x+1][y] * mascara[1][2]
 m += img[x+1][y-1] * mascara[2][2]

 # Faz a média dos valores e guarda como intensidade do pixel
 img_corr[x][y] = m/9

 # Quando a coordenada não existir, passe para o próximo pixel
 except:
 continue

 return img_corr

# Função com a imagem percorrendo a máscara (contrário da outra)
def correlacao_rapida(img, img_corr, mascara):

 # criando uma nova imagem = tamanho da imagem + bordas da mascara
 img_corr_rap = np.zeros(np.array(img.shape) + np.array(mascara.shape) - 1)

 # Percorre a máscara
 for x in range(mascara.shape[0]):
 for y in range(mascara.shape[1]):

 # Copia os valores para a imagem nova, que é maior para armazenar o cálculo
 img_corr_rap[x:x+img.shape[0], y:y+img.shape[1]] += img * mascara[x,y]

 return img_corr_rap.astype('uint8')

# imread ( nome da imagem, [1=cor, 0=grayscape, -1=alpha])
# Cada coluna da imagem é armazenada em um subvetor, onde cada coluna é uma posição
img = cv2.imread('./Imagens/original.jpg', 0)

# Abre a imagem novamente para comparar com a original
img_corr = cv2.imread('./Imagens/original.jpg', 0)

# Cria uma máscara simples com o mesmo peso
mascara = np.array([ [1,1,1], [1,1,1], [1,1,1] ])

################### Comum ################
# Verifica o horário inicial da convolução
time_start = timeit.default_timer()

# Executa a função de correlação
img_corr_comum = correlacao_comum(img, img_corr, mascara)

# Verifica o tempo final da convolução
time_end = timeit.default_timer()

# Apresenta a duração do processo de convolução
time = time_end - time_start
print 'Tempo de processamento Comum:', time, 'segundos'

################ Rápida #######################

# Verifica o horário inicial da convolução
time_start = timeit.default_timer()

# Executa a função de correlação
img_corr_rapida = correlacao_rapida(img, img_corr, mascara)

# Verifica o tempo final da convolução
time_end = timeit.default_timer()

# Apresenta a duração do processo de convolução
time = time_end - time_start
print 'Tempo de processamento Rápida:', time, 'segundos'


# Mostrar imagem
# nome da janela, matriz
cv2.imshow('Original',img)

cv2.imshow('Correlação Másc. Simples',img_corr_comum)
cv2.imwrite('./Imagens/original_corr.jpg', img_corr_comum)

# Funções para funcionamento correto ao mostrar a imagem numa janela
cv2.waitKey(0)
cv2.destroyAllWindows()

Imagens resultantes

# Imagem original

original

# Após a convolução com a máscara imples

original_conv

Amostragem e Quantização

Para realizar este trabalho, foram utilizados os pacotes NumPy e OpenCV. O código está todo comentado e na sequência é possível ver as imagens resultantes.

Código

# -*- coding: utf-8 -*-
import numpy as np
import cv2

# Função: imread ( nome da imagem, [1=cor, 0=grayscape, -1=alpha])
# Cada coluna da imagem é armazenada em um subvetor, onde cada coluna é uma posição
img = cv2.imread('./Imagens/original.jpg', 0)

## Amostragem ##
# Reduzindo a imagem #
# Seleciona uma em cada 2 colunas, e de cada coluna uma a cada duas linhas
n = 2
img_red = img[::n,::n]

# Aumentando a imagem #
# Os pixels da imagem atual serão duplucados no eixo x e y. Assim, a imagem volta a ter o tamanho original, mas a partir da imagem reduzida
# Função: np.repeat(matriz, vezes, eixo). O eixo 0 é a altura e 1 a largura.
m = 2
img_aum = np.repeat(img_red, m, axis=0)
img_aum = np.repeat(img_aum, m, axis=1)

## Quantização ##
# 255 / 31 = 8,22...
# Assim, teremos uma imagem com 8 tons de cinza. A conta é feita desta forma para descartar a parte decimal dos números e alterar o vetor para que possua apenas 8 valores possíveis.
r = 31
img = np.uint8(img / r) * r

# Salvar imagem no disco #
#cv2.imwrite('C:/Diretório', img_aum)

# Mostra uma imagem
# Função: cv.imshow(nome da janela, matriz)
cv2.imshow('original',img)
cv2.imshow('reduzida',img_red)
cv2.imshow('aumentada',img_aum)

# Funções para o funcionamento correto do python no Windows.
cv2.waitKey(0)
cv2.destroyAllWindows()

Imagens Resultantes

# Original

DCIM100GOPROGOPR0157.

# Reduzida

reduzida

# Aumentada

aumentada

# Quantizada

quantizada