viernes, 29 de abril de 2011

Generic views con ForeignKey(User)

Con generic views podemos facer os accesos máis comúns á base de datos (engadir, borrar, editar, consultas...). A veces haberá que facer pequenos engadidos de código para conseguir axustes. Hoxe vamos ver cómo subir archivos ó servidor sin perder o trazo dos donos deses archivos.

models.py


Queremos aceptar un archivo que o usuario sube, e que o usuario lle dea unha descripción ó archivo. Comprobar que ese archivo sea seguro (que non nos suban un script, por exemplo) é outra tarea distinta que queda nas mans do programador.

from django import forms
from django.db import models
from django.forms import ModelForm
from django.contrib.auth.models import User
import uuid

def set_path(my_model, file_name):
'''Sets the file_path for the uploaded file'''
return "uploads/{0}".format(uuid.uuid1())

# Create your models here.
class OurModel(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User, editable=False)
file_path = models.FileField(upload_to=set_path, blank=True)

def __unicode__(self):
return self.name

class OurModelForm(ModelForm):

class Meta:
model = OurModel
exclude = ("user",)


urls.py



Estando dentro da nosa aplicación, empezaremos necesitando a vista de list_detail.object_detail e a de create_update.create_object. Como imos a modificar aparte de crear o obxeto, a vista xenérica de create_object hai que desplazala a unha función de views.py (será add).

from django.conf.urls.defaults import *
from models import OurModel, OurModelForm

import views

urlpatterns = patterns('',
url(r'^(?P<object_id>\d+)/$',
"django.views.generic.list_detail.object_detail",
dict(queryset=OurModel.objects.all()),
name='ourmodel_detail'),
url(r'^add/$',
views.add,
name='ourmodel_add'),
)


views.py



Aquí creamos a función add que se chama desde urls.py. Nesta función trataremos as chamadas GET e POST, xa que o formulario ten o "action" cara sí mesmo. Si se chama vía GET, devolvemos a vista de create_object, si se chama vía POST, instanciamos o modelo cos datos que nos veñen do formulario, instanciamos un usuario (User) co usuario que está logueado e pasámoslle ambas instancias ó modelo, para que as grave.

O "truco" está en cargar o formulario e preparalo para grabar (commit=False), xa que a partir deste momento poderemos cargarlle tamén a instancia de "User". Despois da grabación, podemos redirixir o usuario cara calquer páxina, aquí mandámolo a un object_detail do recén grabado.

from django.views.generic.create_update import create_object
from django.views.generic.list_detail import object_detail
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User

from models import OurModel, OurModelForm

@login_required
def add(request):
if request.method == "POST":
form = OurModelForm(data=request.POST,
files=request.FILES)
if form.is_valid():
our_model = form.save(commit=False)
our_model.user = User.objects.get(pk = request.user.id)
our_model.save()

return object_detail(request,
OurModel.objects.all(),
object_id=align.id)

return create_object(request,
model=OurModel,
form_class=OurModelForm,
login_required=True)


templates



Necesitamos só dous templates, /our_app/ourmodel_detail.html e /our_app/ourmodel_form.html. Con un pequeno cambio: os formularios que suben archivos teñen unha propiedade añadida

<form enctype="multipart/form-data" method="post" action="."></form>


Listo!

Resultado



Cando un usuario rexistrado accede á páxina http://ourserver.com/ourapp/add/ por primeira vez (vía GET), o urls.py lévao á función def add de views.py. Nesa función sáltase toda a parte "non POST", e simplemente saca o generic view para create_update.create_object, que presenta o formulario indicado.

Si o usuario enche o formulario correctamente (se non o fai, o generic view automáticamente volve para atrás), chámase a función add de novo, pero agora vía POST e cos datos apropiados. Agora entramos no proceso propio de grabar o modelo na base de datos cos datos apropiados.

No hay comentarios: