Comecei a trabalhar com o Django vindo de anos do Spring MVC e a implementação de formulários parece um pouco louca. Se você não estiver familiarizado, os formulários do Django começam com uma classe de modelo de formulário que define seus campos. O Spring começa da mesma forma com um objeto de suporte de formulário. Mas onde o Spring fornece um taglib para vincular elementos de formulário ao objeto de backup em seu JSP, o Django possui widgets de formulário vinculados diretamente ao modelo. Existem widgets padrão nos quais você pode adicionar atributos de estilo aos seus campos para aplicar CSS ou definir widgets completamente personalizados como novas classes. Tudo acontece no seu código python. Isso parece loucura para mim. Primeiro, você está colocando informações sobre sua visão diretamente em seu modelo e, em segundo lugar, está vinculando seu modelo a uma visão específica. Estou esquecendo de algo?
EDIT: Alguns exemplos de código conforme solicitado.
Django:
# Class defines the data associated with this form
class CommentForm(forms.Form):
# name is CharField and the argument tells Django to use a <input type="text">
# and add the CSS class "special" as an attribute. The kind of thing that should
# go in a template
name = forms.CharField(
widget=forms.TextInput(attrs={'class':'special'}))
url = forms.URLField()
# Again, comment is <input type="text" size="40" /> even though input box size
# is a visual design constraint and not tied to the data model
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
Spring MVC:
public class User {
// Form class in this case is a POJO, passed to the template in the controller
private String firstName;
private String lastName;
get/setWhatever() {}
}
<!-- JSP code references an instance of type User with custom tags -->
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!-- "user" is the name assigned to a User instance -->
<form:form commandName="user">
<table>
<tr>
<td>First Name:</td>
<!-- "path" attribute sets the name field and binds to object on backend -->
<td><form:input path="firstName" class="special" /></td>
</tr>
<tr>
<td>Last Name:</td>
<td><form:input path="lastName" size="40" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Save Changes" />
</td>
</tr>
</table>
</form:form>
Respostas:
Sim, as formas do Django são uma confusão da perspectiva do MVC, suponha que você esteja trabalhando em um grande jogo de super-heróis MMO e criando o modelo Hero:
Agora, você deve criar um formulário para ele, para que os jogadores do MMO possam inserir seus super poderes de herói:
Como o repelente de tubarões é uma arma muito poderosa, seu chefe pediu que você o limite. Se um herói tem o repelente de tubarões, ele não pode voar. O que a maioria das pessoas faz é simplesmente adicionar essa regra de negócios no formato clean e chamar isso de dia:
Esse padrão parece legal e pode funcionar em pequenos projetos, mas, na minha experiência, isso é muito difícil de manter em grandes projetos com vários desenvolvedores. O problema é que o formulário faz parte da exibição do MVC. Portanto, você deve se lembrar dessa regra de negócios toda vez que:
Meu argumento aqui é que o forms.py tem tudo a ver com o layout e a apresentação do formulário, você nunca deve adicionar lógica de negócios nesse arquivo, a menos que goste de mexer com o código espaguete.
A melhor maneira de lidar com o problema do herói é usar o método de limpeza de modelo mais um sinal personalizado. A limpeza do modelo funciona como a forma limpa, mas é armazenada no próprio modelo, sempre que o HeroForm é limpo, ele chama automaticamente o método de limpeza Hero. Essa é uma boa prática, porque se outro desenvolvedor escrever uma outra forma para o Herói, ele receberá a validação repelente / grátis.
O problema com a limpeza é que ele é chamado apenas quando um modelo é modificado por um formulário. Não é chamado quando você o salva manualmente () e pode acabar com um herói inválido no seu banco de dados. Para combater esse problema, você pode adicionar este ouvinte ao seu projeto:
Isso chamará o método clean em cada chamada save () para todos os seus modelos.
fonte
Você está misturando a pilha inteira, há várias camadas envolvidas:
um modelo do Django define a estrutura de dados.
um Django Form é um atalho para definir formulários HTML, validações de campo e traduções de valores Python / HTML. Não é estritamente necessário, mas muitas vezes útil.
um Django ModelForm é outro atalho, em suma uma subclasse de Form que obtém seus campos a partir de uma definição de modelo. Apenas uma maneira prática para o caso comum em que um formulário é usado para inserir dados no banco de dados.
e finalmente:
Algumas pessoas vêem isso como heresia; mas é importante lembrar que o MVC foi originalmente definido para aplicativos da GUI e é um ajuste bastante estranho para aplicativos da Web.
fonte
Estou respondendo a essa pergunta antiga porque as outras respostas parecem evitar o problema específico mencionado.
Os formulários do Django permitem que você escreva facilmente pouco código e crie um formulário com padrões saudáveis. Qualquer quantidade de personalização leva muito rapidamente a "mais código" e "mais trabalho" e anula um pouco o principal benefício do sistema de formulários
Bibliotecas de modelos como django-widget-tweaks facilitam a personalização de formulários. Esperamos que personalizações de campo como essa acabem sendo fáceis com uma instalação baunilha do Django.
Seu exemplo com django-widget-tweaks:
fonte
(Eu usei itálico para significar os conceitos do MVC para tornar isso mais legível.
Não, na minha opinião, eles não quebram o MVC. Ao trabalhar com Django Models / Forms, pense nisso como usar uma pilha MVC inteira como um Model :
django.db.models.Model
é o modelo base (mantém os dados e a lógica de negócios).django.forms.ModelForm
fornece um controlador para interagir comdjango.db.models.Model
.django.forms.Form
(conforme fornecido por herançadjango.forms.ModelForm
) é a Visualização com a qual você interage.ModelForm
é aForm
, então as duas camadas são fortemente acopladas. Na minha opinião, isso foi feito com brevidade em nosso código e para reutilização de código no código dos desenvolvedores do Django.Dessa forma,
django.forms.ModelForm
(com seus dados e lógica de negócios) se torna um Modelo si. Você pode referenciá-lo como (MVC) VC, que é uma implementação bastante comum no OOP.Veja, por exemplo, a
django.db.models.Model
classe do Django . Quando olhamos para osdjango.db.models.Model
objetos, vemos o Model , apesar de já ser uma implementação completa do MVC. Supondo que o MySQL seja o banco de dados back-end:MySQLdb
é o modelo (camada de armazenamento de dados e lógica de negócios sobre como interagir com / validar os dados).django.db.models.query
é o controlador (manipula a entrada da visualização e a traduz para o modelo ).django.db.models.Model
é a visualização (com a qual o usuário interage).Essa interação é igual aos seus "desenvolvedores do lado do cliente" ao trabalhar com
yourproject.forms.YourForm
(herdar dedjango.forms.ModelForm
) objetos:django.db.models.Model
, eles precisam saber como interagiryourproject.forms.YourForm
(seu Modelo ).MySQLdb
, seus "desenvolvedores do lado do cliente" não precisam saber nada sobreyourproject.models.YourModel
.fonte