sexta-feira, 24 de maio de 2013

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

Para isso é preciso de dois models, um model Pai que conterá N instancias de objetos de uma classe Filho, como por exemplo a relação de Conteúdo para Fotos. Assumindo este exemplo, deixe os arquivos como a seguir:

models.py
from django.db import models
# Create your models here.
class Conteudo(models.Model):
 """(Conteudo description)"""

 # ...
 # SEUS ATRIBUTOS AQUI
 # ...

 class Meta:
  verbose_name, verbose_name_plural = u"Conteúdo" , u"Conteúdos"


class Foto(models.Model):
 """(Foto description)"""
 conteudo= models.ForeignKey(Conteudo, verbose_name=u'Conteúdo')
 imagem = models.ImageField(upload_to="uploads/conteudos/imagem/%Y")

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

 def __unicode__(self):
  return "%s" % str(self.imagem)

forms.py
from django.forms.models import inlineformset_factory
from models import Conteudo, Foto
class ConteudoForm(forms.ModelForm):
 class Meta:
  model = Conteudo

FotoFormSet = inlineformset_factory(Conteudo, Foto, extra=1)


views.py
from models import *
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import Context, loader, RequestContext
from django.core.context_processors import csrf
from forms import ConteudoForm, FotoFormSet

def conteudo_enviar(request):
 ret = ''
 if request.POST:
  c = {}
  c.update(csrf(request))

  r = request.POST
  f = request.FILES
  form = ConteudoForm(r,f)
  formset = FotoFormSet(r,f)

  if form.is_valid() and request.FILES:
   try:
    form.save()
    formset.instance = get_object_or_404(Conteudo, id=form.instance.id)
    formset.save()
    ret = u'Conteúdo enviado com sucesso.'

    # ZERANDO O FORM
    form = ConteudoForm()
    formset = FotoFormSet()

   except:
    ret = u'Erro ao enviar o conteúdo'
  elif request.FILES:
   for field in form:
    if field.errors:
     ret += "%s: %s" % (field.label, striptags(str(field.errors)) )
  else:
   ret += "Imagem: pelo menos uma imagem do conteúdo deve ser enviada"
 else:
  form = ConteudoForm()
  formset = FotoFormSet()

 VARS = {
  'form':form,
  'formset':formset,
  'ret':ret,
 }
 return render_to_response('conteudo_template.html', VARS, context_instance=RequestContext(request))

conteudo_template.html

<script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
<script type="text/html" id="foto-template">
 <div id="foto-<%= id %>" class="imagem">
  <input id="id_foto_set-<%= id %>-id" type="hidden" name="foto_set-<%= id %>-id">
     <label for="id_foto-<%= id %>-title">Imagem:</label>
     <input id="id_foto_set-<%= id %>-imagem" class="file" type="file" name="foto_set-<%= id %>-imagem">
     <input type="hidden" name="foto-<%= id %>-acao" id="id_foto-<%= id %>-acao">
     <input type="hidden" name="foto-<%= id %>-id" id="id_foto-<%= id %>-id">
     {% if not request.META.HTTP_USER_AGENT|isIE %}
   <div class="filename"></div>
   <div class="button-container">
   <input type="button" name="filebutton" class="filebutton" value="Procurar">
   </div>
  {% endif %}
  </div>
</script>

<script type="text/javascript">
jQuery(document).ready(function($) {
  // Stuff to do as soon as the DOM is ready;
  $('.add-foto').click(function(ev){
  ev.preventDefault();
  var count = $('.fotos').children().length;
  var tmplMarkup = $('#foto-template').html();
  var compiledTmpl = _.template(tmplMarkup, { id : count });
  $('div.fotos').append(compiledTmpl);
  // update form count
  $('#id_foto_set-TOTAL_FORMS').attr('value', count+1);
  console.log(count+1);
 });
});
</script>
{{ formset.management_form }}
<div class="fotos">
 {% for foto_form in formset %}
  <div id="foto-{{ forloop.counter0 }}" class="imagem">
   {{ foto_form.id }}
   {% if request.META.HTTP_USER_AGENT|isIE %}
    {# IE HACK PARA INPUT FILE #}
    {{ foto_form }}
    {# <input type="file" id="id_imagem" name="imagem[]" class="file" style="right:0; height: 50px; width:478px; position:absolute;opacity:1.0;filter:alpha(opacity=100);"> #}
   {% else %}
    {{ foto_form }}
    <div class="filename"></div>
    <div class="button-container">
     <input type="button" name="filebutton" class="filebutton" value="Procurar">
    </div>
   {% endif %}
  </div>
 {% endfor %}
</div>
<div class="form-actions">
  <button class="medium green add-foto">Adicionar mais fotos</button>
</div>

Para as class-based views, mostrarei como fazer no próximo post. hasta!

sexta-feira, 17 de maio de 2013

Como criar uma aba no Facebook e pegar os dados dos usuário no aplicativo

Extraído de: http://blog.hubspot.com/blog/tabid/6307/bid/26330/How-to-Create-Custom-Tabs-for-Facebook-Business-Pages.aspx

Passo 1: Faça login como Desenvolvedor

Faça login como desenvolvedor no Facebook em : https://developers.facebook.com/apps

Passo 2: Crie e nomeie seu novo aplicativo

Clique em "Criar um novo aplicativo" no canto superior esquerdo. Você precisa fornecer um "Display Name", que é como seu "app", ou guia, será chamado. Você também precisa criar um "namespace", que é basicamente apenas um ID único para o seu aplicativo.
create new facebook app

Passo 3: Escolha uma imagem e atualizar informações básicas para a App


Escolha uma imagem e um ícone para o seu guia personalizado. Lembre-se, isso vai exibir no topo da sua página do Facebook, então pense nisso como um call-to-action. Escolha uma imagem que vai receber seus visitantes ao clicar!

Atualize suas informações básicas com o nome de domínio e categoria. Você também pode fazer upload de uma imagem personalizada para o seu aplicativo, clicando em "ícone de edição."

basic info


Passo 4: Criar o conteúdo que será exibido dentro da aba do aplicativo


Agora crie uma página da web fora do Facebook. Isto é o que será exibido dentro de sua guia personalizado Facebook. Para garantir o conteúdo da página exibida corretamente no Facebook, certifique-se que a largura da sua página web esteja configurado para 100%, 520px ou 810px. Certifique-se de todas as imagens, vídeos, etc, que você incluir em sua página são menos do que qualquer 520px ou 810px, dependendo de quão grande você escolheu para fazer o conteúdo da sua guia.

facebook screenshot


Para se certificar de que todos podem ver o sua nova guia da página do Facebook, você também precisará fornecer uma URL segura. Esta deve ser a mesma URL que você forneceu para o separador de página, mas com "https://" em vez de "http://" na frente. Se o seu site não suporta https, o aplicativo ainda funciona para quem tem a navegação segura desativada em suas configurações do Facebook, mas você deve obter um certificado SSL. 

Salve as alterações que você fez para o app.


Passo 5: Diga Facebook o conteúdo que você deseja exibir no seu guia Personalizar


Volte para suas configurações de aplicativos em developers.facebook.com, desça até a opção "Selecionar como seu aplicativo se integra com Facebook" seção, e escolha "Page Tab",  nomeie do seu guia que você gostaria, então copie a URL da página que você criou no passo 4, e cole a URL em "Página Tab URL".


page tab


Para se certificar de que todos podem ver o sua nova guia da página do Facebook, você também precisará fornecer uma URL segura. Esta deve ser a mesma URL que você forneceu para o separador de página, mas com "https://" em vez de "http://" na frente. Se o seu site não suporta https, o aplicativo ainda funciona para quem tem navegação segura desativada em suas configurações do Facebook, mas você deve olhar para obter um certificado SSL.

Salve as alterações que você fez para o app.

Passo 6: Adicione o seu guia para sua página do Facebook 


Este passo pode ser um pouco complicado, então leia com atenção. Para instalar sua guia nova em sua página de negócios, você precisa visitar um link com vários parâmetros de URL personalizada. O link é: 

http://www.facebook.com/dialog/pagetab?app_id=YOUR_APP_ID&amp;next=YOUR_URL 

Você vai precisar de substituir os termos em negrito na URL acima. "YOUR_APP_ID" e "YOUR_URL" com algumas informações que o Facebook oferece para o seu aplicativo, o ID do seu aplicativo e a url do seu site.

facebook summary


Passo 7: Página que será renderizada na aba e channel file

Channel File

Crie um arquivo com o conteúdo abaixo que será utilizado na página da sua aba:

<?php

  $cache_expire = 60*60*24*365;
  header("Pragma: public");
  header("Cache-Control: maxage=".$cache_expire);
  header('Expires: '.gmdate('D, d M Y H:i:s', time()+$cache_expire).' GMT');
?>
<script src="//connect.facebook.net/en_US/all.js"></script>

Se não tiver trabalhando com php, pode criar um arquivo apenas com o script do facebook, o php acima serve apenas para controle de cache, ou pode fazer da forma que sua linguagem assim permitir.

Conteúdo da aba:

Na sua página que se hospedará externamente ao facebook, insira os códigos abaixo, subistituindo os devidos valores:

Antes de fechar a tag HEAD:

<meta property="og:title" content="TITULO" />
<meta property="og:url" content="<?=$url?>/" />
<meta property="og:type"        content="company" />
<meta property="og:site_name"   content="TITULO DO SITE" />
<meta property="og:description" content="DESCRICAO" />
<meta property="fb:app_id"      content="ID DO APLICATIVO" />
<meta property="og:image"       content="https://URL DA THUMB/thumb.jpg" />

Logo depois da abertura da tag BODY:

<!-- Facebook JS SDK -->
<div id="fb-root"></div>
<script>
 // Additional JS functions here
 window.fbAsyncInit = function() {
  FB.init({
    appId      : 'ID DO APLICATIVO', // App ID
    channelUrl : '//CHANNEL FILE', // Channel File ex: 'SEU SITE/channel.php'
    status     : true, // check login status
    cookie     : true, // enable cookies to allow the server to access the session
    xfbml      : true  // parse XFBML
  });

  // Additional init code here
  FB.getLoginStatus(function(response) {
   if (response.status === 'connected') {
    // connected
    //alert('usuario já autorizou a aplicacao');
    //console.log(JSON.stringify(response));

    FB.api('/me', function(response){
     //DADOS ESTARÃO TODOS NO RESPONSE
     // Ex:
     // NOME = response.name
    });

   } else if (response.status === 'not_authorized') {
    // not_authorized
    login();
   } else {
    // not_logged_in
    login();
   }
  });
 };

 function login() {
  FB.login(function(response) {
   if (response.authResponse) {
    // connected
    FB.api('/me', function(response) {
     location.reload();
    });
   } else {
    // cancelled
    //alert("Usuário Cancelou");
   }
  },{scope: 'email'});
 }

 function postToWall() {
  FB.login(function(response) {
    if (response.authResponse) {
   FB.ui({
    method: 'feed',
    name: 'NOME',
    link: 'LINK DO SEU APLICATIVO', // EX: https://www.facebook.com/SUA PAGINA/app_(ID DO APLICATIVO)';
    picture: 'URL DA FOTO DO POST',
    caption: 'LEGENDA',
    description: 'DESCRICAO/TEXTO DO POST'
   },
   function(response) {
     if (response && response.post_id) {
    //alert('Post was published.');
     } else {
    //alert('Post was not published.');
     }
   });
    } else {
   //alert('User cancelled login or did not fully authorize.');
    }
  }, {scope: 'publish_stream'});
  return false;
 }

 // Load the SDK Asynchronously
 (function(d){
  var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement('script'); js.id = id; js.async = true;
  js.src = "//connect.facebook.net/en_US/all.js";
  ref.parentNode.insertBefore(js, ref);
 }(document));

Considerações:

  • O que acontece na verdade depois de tudo isso é que sua página será executada dentro de um iframe do facebook, e graças a isso, é possível fazer tudo que uma página normal faz: upload, persistência em banco de dados, ajax, etc.
  • O SSL se faz ncessário, pois caso não exista, apenas usuários que desabilitaram esta opção nas configurações do facebook poderão ver o aplicativo, sendo que muitos não fazem ideia de onde isso fica, e nem o que faz.
  • A função de login, solicita além dos dados publicos (nome, lista de amigos, etc) o eemail da pessoa. Para mais permissões, consulte https://developers.facebook.com/docs/reference/login/#permissions

quarta-feira, 8 de maio de 2013

GIT - Visão geral e comandos úteis

Git é um sistema de controle de versão distribuído grátis e de código aberto,  desenhado para lidar com tudo, desde pequenos até grandes projetos com rapidez e eficiência.

Para instalar:

Ou também pode ser usado os famosos apt-get, yum, ports, etc.

Fluxo

Seu repositório consiste em três "árvores" mantidas pelo git. A primeira delas é sua Working Directory que contém os arquivos vigentes que estão na máquina. A segunda é a Index que funciona como uma área temporária, que contém as mudanças propostas pelos comandos "add" e finalmente a HEAD que aponta para o último commit (confirmação) que você fez.


Comandos mais utilizados:

  • git init
    • Para criar um novo repositório
  • git clone usuário@servidor:/caminho/para/o/repositório
    • Para clonar um repositório em um servidor remoto
  • git add /caminho/para/o/arquivo
    • Para adicionar um arquivo que foi criado e ainda não está sob controle do git
  • git add .
    • Para adicionar todos os arquivos, novos e modificados
  • git commit -m 'comentario sobre sua mudança'
    • Para dar o commit nas alterações propostas pelo add
  • git pull origin master
    • Fazer o download das ultima revisão dos arquivos do repositorio (Head)
  • git push origin master
    • Enviar a árvore do repositório (Head) as mudanças do commit
  • git status
    • Verificar o status de cada arquivo/pasta no repositório
  • git remote add origin <servidor>
    • Se você não clonou um repositório existente e quer conectar seu repositório a um servidor remoto, você deve adicioná-lo

Na prática

  1. git clone usuário@servidor:/caminho/para/o/repositório
  2. git pull origin master
  3. Crie/modifique os arquivos
  4. git add .
  5. git commit -m 'comentario sobre sua mudança'
  6. git push origin master


Links Úteis