sexta-feira, 23 de agosto de 2013

Como utilizar os inlines no front para os ModelForms (class based view)

Assim como prometido, mesmo que com uma "pequena" demora, segue a continuação do post
Como utilizar os inlines no front para os ModelForms (function based view). Faremos algo bem similar com alguns detalhes a mais.

Objetivo é fornecer um formulário de cadastro e este pode fazer uploads de fotos. Quando o email já existir no banco de dados, faremos que as fotos do segundo envio seja direcionadas para o primeiro cadastro, do contrário, uma nova instancia para todos os objetos envolvidos.

models.py

from django.db import models

# Create your models here.

class Cadastro(models.Model):
 """(Cadastro description)"""
 nome = models.CharField(max_length=255)
 email = models.EmailField(verbose_name='E-mail')
 telefone = models.CharField(max_length=20)
 aceite = models.BooleanField(default=True)
 data = models.DateField(auto_now_add=True)
 hora = models.TimeField(auto_now_add=True)

 class Meta:
  verbose_name, verbose_name_plural = u"Cadastro" , u"Cadastros"
  ordering = ('-data',)

 def __unicode__(self):
  return "%s" % self.nome

class Foto(models.Model):
 """(Foto description)"""
 cadastro = models.ForeignKey(Cadastro)
 foto = models.ImageField(upload_to="uploads/fotos/foto/%Y")
 data = models.DateField(auto_now_add=True)
 hora = models.TimeField(auto_now_add=True)
 aprovado = models.BooleanField(default=False)

 class Meta:
  verbose_name, verbose_name_plural = u"Foto" , u"Fotos"
  ordering = ('-data',)

 def __unicode__(self):
  return "%s" % self.id

 def thumb_admin(self):
  from sorl.thumbnail import get_thumbnail
  im = get_thumbnail(self.foto, '120x120', crop='center', quality=99)
  if im:
   return  '<a href="http://www.blogger.com/media/%s" onclick="window.open(this.href);return false;"><img alt="Imagem" src="%s" /></a>' % (self.foto, str(im.url))
  return  'Sem foto'
 thumb_admin.is_safe = True
 thumb_admin.allow_tags = True
 thumb_admin.short_description = 'Thumb'

admin.py

from django import forms
from django.contrib import admin
from .models import *

class FotoInline(admin.TabularInline):
 model = Foto
 readonly_fields = ['foto',]
 extra = 5


class CadastroAdmin(admin.ModelAdmin):
 inlines = [
  FotoInline,
 ]
 search_fields = ('nome', 'email',)
 list_display = ('nome', 'email','telefone','data', 'hora',)
 list_filter = ['data',]
 date_hierarchy = 'data'
 readonly_fields = ['nome', 'email','telefone','aceite']
 save_on_top = True

admin.site.register(Cadastro, CadastroAdmin)



class FotoAdmin(admin.ModelAdmin):
 
 list_display = ('cadastro', 'data', 'hora','thumb_admin','aprovado')
 list_filter = ['data','aprovado']
 date_hierarchy = 'data'
 list_editable = ['aprovado']
 readonly_fields = ['cadastro','foto',]
 save_on_top = True

admin.site.register(Foto, FotoAdmin)

forms.py

# coding: utf-8
from django import forms
from django.utils.translation import ugettext_lazy as _
from .models import *
from util import util as U

from django.forms.models import inlineformset_factory

class CadastroForm(forms.ModelForm):
 class Meta:
  model = Cadastro


class FotoForm(forms.ModelForm):

 aprovado = forms.BooleanField(initial=False, required=False)
 aceite = forms.BooleanField(initial=True)

 class Meta:
  model = Foto


 def dados(self):
  return {'form':self.cleaned_data, 'data':datetime.now()}

 def clean(self):
  cleaned_data = super(FotoForm, self).clean()
  #if cleaned_data.get("senha") != cleaned_data.get("confirme"):
  # self._errors["confirme"] = self.error_class(['Senha nao confere'])
  return self.cleaned_data


FotoFormSet = inlineformset_factory(Cadastro, Foto, extra=5)

urls.py

# coding: utf-8
from django.conf.urls.defaults import patterns, include, url

from . import views

urlpatterns = patterns('fotos.views',
 url(r'^$', views.CadastroView.as_view(), name='cadastro_form'),
)

form.html

<html>
 <head>
 <meta charset="utf-8">
 <title></title>
 </head>
 <body>
  <form action="" method="post" enctype="multipart/form-data">
   {% csrf_token %}
   {{ form.errors }}

   <p>Nome:{{ form.nome }}</p>
   <p>Telefone: {{ form.telefone }}</p>
   <p>E-mail: {{ form.email }}</p>
   <p>Foto: {{ form.foto }}</p>
   <p>Aceite: {{ form.aceite }}</p>

   {{ foto_formset.management_form }}
   {% for form in foto_formset %}
    {{ form.id }}
    <div class="form-row inline {{ foto_formset.prefix }}">
     {{ form.foto.label_tag }}
     {{ form.foto }}
     {{ form.foto.errors }}
    </div>
   {% endfor %}

   <input type="submit" name="" value="Enviar">

  </form>
 </body>
</html>

views.py

class CadastroView(CreateView):
 #template_name = 'form.html'
 template_name = 'index.html'
 model = Cadastro
 form_class = CadastroForm
 success_url = '/envie/?sucesso=1#sucesso'

 def form_valid(self, form):
  context = self.get_context_data()
  foto_form = context['foto_formset']

  email = form.cleaned_data['email']

  if foto_form.is_valid():
   print "erros: %s" % foto_form.errors
   if Cadastro.objects.filter(email=email):
    foto_form.instance = Cadastro.objects.get(email=email)
   else:
    self.object = form.save()
    foto_form.instance = self.object
   foto_form.save()
   return HttpResponseRedirect('/envie/?sucesso=1#sucesso')
  else:
   addDebug("erros: %s" % foto_form.errors)
   return self.render_to_response(self.get_context_data(form=form))

 def form_invalid(self, form):
  return self.render_to_response(self.get_context_data(form=form))

 def get_context_data(self, **kwargs):
  context = super(CadastroView, self).get_context_data(**kwargs)
  r = self.request.POST
  f = self.request.FILES  

  if r and f:
   context['foto_formset'] = FotoFormSet(self.request.POST,f)
  else:
   context['foto_formset'] = FotoFormSet()
  return context

cadastro.js

jQuery(document).ready(function($) {

 $('.bt-mais').click(function(event) {
  if($('.enviar-foto-fake').length < 5){
   $('.enviar-foto-fake').last().clone().insertAfter($('.enviar-foto-fake').last());
   $('.enviar-foto-fake').last().find('div p.nome-foto').text('Você pode enviar até cinco fotos');
   $('.enviar-foto-fake').last().find('input').attr({
    id: 'id_foto_set-'+($('.enviar-foto-fake').length-1)+'-foto',
    name: 'foto_set-'+($('.enviar-foto-fake').length-1)+'-foto'
   });
   $('#id_foto_set-TOTAL_FORMS').val($('.enviar-foto-fake').length);
  }

  if ($('.enviar-foto-fake').length == 5) {
   $(this).hide();
  };

 })
});

hasta!

Nenhum comentário:

Postar um comentário