Entendendo Django

Agenda

  • Entendendo Projeto
  • Entendendo Apps
  • Adicionando Apps no Projeto

Projeto

"Projeto" é como Django chama a base do sistema.

Criado com django-admin startproject [PROJECT].

Projeto: startproject


    .
    ├── exemplo
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── manage.py
                        

manage.py vira o gerenciador do projeto.

Projeto > App

Dentro do projeto, para criar um app:

python manage.py startapp [app]

Projeto > App


    .
    ├── exemplo
    │   ├── __init__.py
    │   ├── __init__.pyc
    │   ├── settings.py
    │   ├── settings.pyc
    │   ├── urls.py
    │   └── wsgi.py
    ├── manage.py
    └── products
        ├── admin.py
        ├── __init__.py
        ├── migrations
        │   └── __init__.py
        ├── models.py
        ├── tests.py
        └── views.py
                        

Projeto > App > models.py

Definição do banco de dados para o app.


class Product(models.Model):

    """Product information"""

    name = models.CharField(max_length=40)
                        

Projeto > App > admin.py

Definição do admin (ou não) dos models.


class ProductAdmin(admin.ModelAdmin):
    pass

admin.site.register(Product, ProductAdmin)
                        

Projeto > App > forms.py

Definição de formulários/formulários baseados em models.


class ProductForm(forms.Form):
    name = forms.CharField(label='Your name', max_length=40)
                        

class ProductForm(ModelForm):
    class Meta:
        model = Product
                        

Projeto > App > views.py

Views do app.


def get_product(request, product_id):
    if request.method == 'GET':
        product = get_object_or_404(Product, pk=product_id)
        return render(request, 
                      'product_info.html',
                      {'product': product})
    else:
        return render(request, 
                      'invalid.html',
                      {'reason': 'Can\'t create products yet'})
                        

Projeto > App > templates/product_info.html

Na verdade, todos os templates da app ficam em templates.


{% extends 'base.html' %}
  • Product name: {{ product.name }}

O base.html pode estar no templates do projeto.

Projeto > App > urls.py

URLs internas do app.


from . import views

urlpatterns = [
    url(r'^(?P<product_id>[0-9]+)/$', views.get_product, name='get'),

]
                        

App completa!

... só que o Django ainda não sabe que ela existe.

Projeto > settings.py


[...]
INSTALLED_APPS = (
    [...]
    'products',
    [...]
)
                        

Agora o Django sabe que a App existe!

Só não sabe como chegar lá porque faltam as URLs.

Projeto > urls.py


[...]
urlpatterns = [
    [...]
    url(r'/products', include('products')),
    [...]
]
                        

Agora funciona como esperado:

  • Request de um browser chega no Django;
  • Consulta o urls.py base do projeto para encontrar o que será executado;
  • Consulta o urls.py da app (no caso) para encontrar a view que será executada;
  • Encontra a view dentro da app, que busca as informações no model;
  • Renderiza o template;
  • Retorna o template renderizado para o usuário.
Go deeper

Relationships

Projeto > App > models.py


class Product(models.Model):

    """Product information"""

    name = models.CharField(max_length=40)
    price = models.DecimalField(max_digits=6, decimal_places=2)


class Order(models.Model):

    """An order."""

    products = models.ManyToManyField(Product)
                    

Inserts


product = Product(name='fruit')
order = Order()
order.products.add(product)
product.save()
order.save()
                    

Queries


all_products = Product.objects.all()
                        

fruit = Product.objects.get(pk=1)
fruit = Product.objects.get(name='fruit')
                        

all_fruits = Order.objects.filter(products__name__like='fruit')
                        

Queries

get só pode retornar um elemento.

pk é uma variável mágica que aponta para o campo marcado como primary_key=True; se não houver um primary_key, o Django cria um IntegerField(auto_increment=True).

Reverse Queries

Quando é criada uma relação, o Django cria também uma relação reversa entre os models.


order = Order.objects.get(pk=1)
print order.products.all()
                        

print Products.order_set.all()
                        

O nome da relacionamento reverso pode ser alterado com related_name.

Fixtures

Fixtures são arquivos JSON que o Django consegue usar para preencher o banco de dados.


[
    {
        "pk": 1,
        "model": "Products",
        "fields": {
            "name": "fruit"
        }
    }
]
                        

Fixtures em Testes

Fixtures em testes se aplicam a suíte inteira.

Para definir que um teste usa fixtures, é usada a variável fixtures da classe.


class ProductTest(StaticLiveServerTestCase):
fixtures = ['products.json']
                        

Fixtures em Produção

Para criação das tabelas de banco de dados, usa-se python manage.py syncdb.

Se houverem fixtures a serem carregadas, essas serão injetadas no banco de dados durante o syncdb.

Signals

Signals (sinais) são eventos gerados dentro do Django para chamar funções de usuário em algumas condições (normalmente relacionadas com models).


from django.db.models.signals import pre_save
from django.dispatch import receiver
from models import Product

@receiver(post_save, sender=Product)
def after_saving_product(sender, instance, created, raw, using, update_fields):
    # ...
                        

Signals

  • sender = o model sendo afetado.
  • instance = registro sendo alterado.
  • created = se é um novo registro ou não.
  • raw = registro salvo exatamente como indicado (fixtures).
  • using = alías do database sendo usado.
  • update_fields = campos sendo salvos no save() (None se forem todos).

Templatetags

Funções especiais para templates para apresentação de valores.

Projeto > App > templatetags/

Dentro do diretório templatetags do App ficam os módulos com os tags.

(Lembrar de colocar o arquivo __init__.py para que o Python detecte o diretório como um módulo).

Projeto > App > templatetags/ filters.py


def free(value):
    if value == 0:
        return _('Free')
    return value
                        

Projeto > App > templates/ product_info.html


{{ product.price|free }}