Usando Django data / hora de widgets no formulário personalizado

votos
158

Como posso usar os bacana JavaScript data e hora widgets que o administrador padrão usa com a minha exibição personalizada?

Eu olhei através da documentação formulários Django , e menciona brevemente django.contrib.admin.widgets, mas eu não sei como usá-lo?

Aqui é o meu modelo que eu quero que ele aplicado sobre.

<form action=. method=POST>
    <table>
        {% for f in form %}
           <tr> <td> ` f`.`name `</td> <td>` f `</td> </tr>
        {% endfor %}
    </table>
    <input type=submit name=submit value=Add Product>
</form>

Além disso, eu acho que deve ser notado que eu realmente não tenho escrito uma visão de mim mesmo para esta forma, eu estou usando uma visão genérica. Aqui é a entrada do url.py:

(r'^admin/products/add/$', create_object, {'model': Product, 'post_save_redirect': ''}),

E eu sou relevantemente novo para a coisa toda Django / MVC / MTV, por isso, vá com calma ...

Publicado 02/09/2008 em 00:22
fonte usuário
Em outras línguas...                            


16 respostas

votos
149

A crescente complexidade desta resposta ao longo do tempo, e os muitos hacks necessários, provavelmente deveria adverti-lo contra fazer isso em tudo. É contando com indocumentados detalhes de implementação interna do admin, é provável que quebrar novamente em futuras versões do Django, e não é mais fácil de implementar do que apenas encontrar um outro widget de calendário JS e usando isso.

Dito isto, aqui está o que você tem que fazer se você está determinado a fazer este trabalho:

  1. Definir a sua própria subclasse ModelForm para o seu modelo (melhor para colocá-lo em forms.py em seu aplicativo), e dizer-lhe para usar o AdminDateWidget / AdminTimeWidget / AdminSplitDateTime (substitua 'mydate' etc com os nomes dos campos apropriados de seu modelo):

    from django import forms
    from my_app.models import Product
    from django.contrib.admin import widgets                                       
    
    class ProductForm(forms.ModelForm):
        class Meta:
            model = Product
        def __init__(self, *args, **kwargs):
            super(ProductForm, self).__init__(*args, **kwargs)
            self.fields['mydate'].widget = widgets.AdminDateWidget()
            self.fields['mytime'].widget = widgets.AdminTimeWidget()
            self.fields['mydatetime'].widget = widgets.AdminSplitDateTime()
    
  2. Mude seu URLconf para passar 'form_class': ProductForm em vez de 'modelo': O produto à vista create_object genérica (que vai significar "a partir my_app.forms importar ProductForm" em vez de "de my_app.models importar produto", é claro).

  3. Na cabeça do seu modelo, incluem `` form`.`media para a saída os links para os arquivos Javascript.

  4. E a parte hacky: O administrador widgets de data / hora presumir que a i18n JS material foi carregado, e também exigem core.js, mas não fornecem qualquer um automaticamente. Assim, no seu modelo acima `` form`.`media você vai precisar de:

    <script type="text/javascript" src="/my_admin/jsi18n/"></script>
    <script type="text/javascript" src="/media/admin/js/core.js"></script>
    

    Você também pode querer usar o seguinte CSS admin (graças Alex por mencionar isso):

    <link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>
    

Isto implica que a mídia de administração do Django (ADMIN_MEDIA_PREFIX) está em / media / admin / - você pode mudar isso para a sua configuração. Idealmente, você usaria um processador de contexto para passar esses valores para o seu modelo em vez de codificá-lo, mas isso é para além do âmbito desta questão.

Isso também exige que o URL / my_admin / jsi18n / ser ligado manualmente até o ponto de vista django.views.i18n.javascript_catalog (ou null_javascript_catalog se você não estiver usando I18N). Você tem que fazer isso sozinho em vez de ir através da aplicação de administração assim que é acessível, independentemente de se você está conectado ao admin (graças Jeremy para apontar isto). Exemplo de código para o seu URLconf:

(r'^my_admin/jsi18n', 'django.views.i18n.javascript_catalog'),

Por último, se você estiver usando o Django 1.2 ou posterior, você precisa de algum código adicional em seu modelo para ajudar os widgets encontrar seus meios de comunicação:

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>

Graças Lupe Fiasco para esta adição.

Respondeu 02/09/2008 em 07:10
fonte usuário

votos
62

Como a solução é hackish, Acho que usando o seu próprio widget de data / hora com algum JavaScript é mais viável.

Respondeu 16/09/2008 em 14:39
fonte usuário

votos
12

Sim, eu acabei substituindo o / admin / jsi18n / url.

Aqui está o que eu adicionei em meu urls.py. Certifique-se de que é acima do / admin / url

    (r'^admin/jsi18n', i18n_javascript),

E aqui é a função i18n_javascript eu criei.

from django.contrib import admin
def i18n_javascript(request):
  return admin.site.i18n_javascript(request)
Respondeu 02/01/2009 em 23:53
fonte usuário

votos
10

A partir de Django 1.2 RC1, se você estiver usando a data administrador truque selecionador widge Django, o seguinte tem que ser adicionado ao seu modelo, ou você verá o ícone de calendário url a ser referenciada através de "/ faltando-admin-media-prefix /".

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>
Respondeu 12/05/2010 em 12:03
fonte usuário

votos
10

Encontro-me fazer referência a este post muito, e descobriu que a documentação define um pouco maneira menos hacky para substituir widgets padrão.

( Não há necessidade de substituir o método __init__ do ModelForm )

No entanto, você ainda precisa conectar seu JS e CSS apropriadamente como Carl menciona.

forms.py

from django import forms
from my_app.models import Product
from django.contrib.admin import widgets                                       


class ProductForm(forms.ModelForm):
    mydate = forms.DateField(widget=widgets.AdminDateWidget)
    mytime = forms.TimeField(widget=widgets.AdminTimeWidget)
    mydatetime = forms.SplitDateTimeField(widget=widgets.AdminSplitDateTime)

    class Meta:
        model = Product

Referência Tipos de campo para encontrar os campos do formulário padrão.

Respondeu 08/09/2009 em 07:42
fonte usuário

votos
9

Meu código de cabeça para versão 1.4 (alguns novos e alguns removido)

{% block extrahead %}

<link rel="stylesheet" type="text/css" href="` STATIC_URL `admin/css/forms.css"/>
<link rel="stylesheet" type="text/css" href="` STATIC_URL `admin/css/base.css"/>
<link rel="stylesheet" type="text/css" href="` STATIC_URL `admin/css/global.css"/>
<link rel="stylesheet" type="text/css" href="` STATIC_URL `admin/css/widgets.css"/>

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="` STATIC_URL `admin/js/core.js"></script>
<script type="text/javascript" src="` STATIC_URL `admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="` STATIC_URL `admin/js/jquery.js"></script>
<script type="text/javascript" src="` STATIC_URL `admin/js/jquery.init.js"></script>
<script type="text/javascript" src="` STATIC_URL `admin/js/actions.js"></script>
<script type="text/javascript" src="` STATIC_URL `admin/js/calendar.js"></script>
<script type="text/javascript" src="` STATIC_URL `admin/js/admin/DateTimeShortcuts.js"></script>

{% endblock %}
Respondeu 12/07/2012 em 08:06
fonte usuário

votos
7

Complementando a resposta por Carl Meyer, gostaria de comentar que você precisa colocar esse cabeçalho em algum bloco válido (dentro do cabeçalho) no seu modelo.

{% block extra_head %}

<link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/media/admin/js/core.js"></script>
<script type="text/javascript" src="/media/admin/js/admin/RelatedObjectLookups.js"></script>

` form`.`media `

{% endblock %}
Respondeu 05/04/2009 em 21:02
fonte usuário

votos
6

(Eu estou tentando comentar sobre as pessoas que sugerem que rolar seu próprio widget Calendário, mas quer Eu não vejo o botão de comentário, ou eu não tenho rep suficiente.)

O que aconteceu com SECO ? Eu acho que seria melhor para voltar a usar o widget admin, mas talvez ele deve ser separado do admin, e mais fácil de usar. Obrigado por esta informação de qualquer maneira.

Respondeu 19/07/2010 em 21:38
fonte usuário

votos
5

I finalmente conseguiu obter este widget trabalhando no servidor dev, só para ter que quebrar na implantação. Eu finalmente decidiu que não valia a pena shoehorning em meu site, e escrevi o meu próprio widget. Não é tão flexível, mas ele provavelmente irá funcionar bem para muitos: http://www.copiesofcopies.org/webl/?p=81

Respondeu 26/04/2010 em 22:17
fonte usuário

votos
4

O abaixo também funciona como um último recurso se não o acima

class PaymentsForm(forms.ModelForm):
    class Meta:
        model = Payments

    def __init__(self, *args, **kwargs):
        super(PaymentsForm, self).__init__(*args, **kwargs)
        self.fields['date'].widget = SelectDateWidget()

Igual a

class PaymentsForm(forms.ModelForm):
    date = forms.DateField(widget=SelectDateWidget())

    class Meta:
        model = Payments

colocar isso em seu forms.py from django.forms.extras.widgets import SelectDateWidget

Respondeu 07/03/2010 em 17:09
fonte usuário

votos
3

O que sobre apenas atribuir uma classe para o widget e, em seguida, ligação essa classe para o datepicker JQuery?

Django forms.py:

class MyForm(forms.ModelForm):

  class Meta:
    model = MyModel

  def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['my_date_field'].widget.attrs['class'] = 'datepicker'

E alguns JavaScript para o modelo:

  $(".datepicker").datepicker();
Respondeu 04/02/2012 em 07:50
fonte usuário

votos
1

Solução e solução atualizados para SplitDateTime com required = False :

forms.py

from django import forms

class SplitDateTimeJSField(forms.SplitDateTimeField):
    def __init__(self, *args, **kwargs):
        super(SplitDateTimeJSField, self).__init__(*args, **kwargs)
        self.widget.widgets[0].attrs = {'class': 'vDateField'}
        self.widget.widgets[1].attrs = {'class': 'vTimeField'}  


class AnyFormOrModelForm(forms.Form):
    date = forms.DateField(widget=forms.TextInput(attrs={'class':'vDateField'}))
    time = forms.TimeField(widget=forms.TextInput(attrs={'class':'vTimeField'}))
    timestamp = SplitDateTimeJSField(required=False,)

form.html

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/admin_media/js/core.js"></script>
<script type="text/javascript" src="/admin_media/js/calendar.js"></script>
<script type="text/javascript" src="/admin_media/js/admin/DateTimeShortcuts.js"></script>

urls.py

(r'^admin/jsi18n/', 'django.views.i18n.javascript_catalog'),
Respondeu 02/12/2009 em 15:29
fonte usuário

votos
0

Meu Setup Django: 1,11 Bootstrap: 3.3.7

Como nenhuma das respostas são completamente claro, eu estou compartilhando meu código do modelo que apresenta nenhum erro em tudo.

Metade superior da modelo:

{% extends 'base.html' %}
{% load static %}
{% load i18n %}

{% block head %}
    <title>Add Interview</title>
{% endblock %}

{% block content %}

<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/forms.css' %}"/>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<script type="text/javascript" src="{% static 'js/jquery.js' %}"></script>

Metade de baixo:

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/actions.min.js' %}"></script>
{% endblock %}
Respondeu 11/03/2019 em 10:22
fonte usuário

votos
0

Para Django> = 2,0

Nota: A utilização de widgets de administração para os campos de data e hora não é uma boa idéia como admin folhas de estilo pode entrar em conflito com o seu site folhas de estilo no caso de você estiver usando inicialização ou quaisquer outros quadros CSS. Se você está construindo o seu site na inicialização usar meu inicialização-datepicker Widget django-inicialização-datepicker-plus .

Passo 1: Adicionar javascript-catalogURL para (não do aplicativo) do seu projeto urls.pyarquivo.

from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    path('jsi18n', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]

Passo 2: Adicionar recursos JavaScript / CSS necessários para seu modelo.

<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static '/admin/js/core.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static '/admin/css/widgets.css' %}">
<style>.calendar>table>caption{caption-side:unset}</style><!--caption fix for bootstrap4-->
` form`.`media `        {# Form required JS and CSS #}

Passo 3: Use widgets de administração para os campos de entrada de data e hora na sua forms.py.

from django.contrib.admin import widgets
from .models import Product

class ProductCreateForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = ['name', 'publish_date', 'publish_time', 'publish_datetime']
        widgets = {
            'publish_date': widgets.AdminDateWidget,
            'publish_time': widgets.AdminTimeWidget,
            'publish_datetime': widgets.AdminSplitDateTime,
        }
Respondeu 17/08/2018 em 10:36
fonte usuário

votos
0

Eu uso isso, é ótimo, mas eu tenho 2 problemas com o modelo:

  1. Eu vejo os ícones do calendário duas vezes para cada arquivada no modelo.
  2. E para TimeField eu tenho ' Digite uma data válida. '

    Aqui está uma imagem do Formulário

models.py

from django.db import models
    name=models.CharField(max_length=100)
    create_date=models.DateField(blank=True)
    start_time=models.TimeField(blank=False)
    end_time=models.TimeField(blank=False)

forms.py

from django import forms
from .models import Guide
from django.contrib.admin import widgets

class GuideForm(forms.ModelForm):
    start_time = forms.DateField(widget=widgets.AdminTimeWidget)
    end_time = forms.DateField(widget=widgets.AdminTimeWidget)
    create_date = forms.DateField(widget=widgets.AdminDateWidget)
    class Meta:
        model=Guide
        fields=['name','categorie','thumb']
Respondeu 21/07/2018 em 19:26
fonte usuário

votos
0

No Django 10. myproject / urls.py: no início do urlpatterns

  from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
.
.
.]

Na minha template.html:

{% load staticfiles %}

    <script src="{% static "js/jquery-2.2.3.min.js" %}"></script>
    <script src="{% static "js/bootstrap.min.js" %}"></script>
    {# Loading internazionalization for js #}
    {% load i18n admin_modify %}
    <script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/jquery.init.js" %}"></script>

    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/base.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/forms.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/login.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/widgets.css" %}">



    <script type="text/javascript" src="{% static "/admin/js/core.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/SelectFilter2.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/admin/RelatedObjectLookups.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/actions.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/calendar.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/admin/DateTimeShortcuts.js" %}"></script>
Respondeu 09/10/2016 em 17:39
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more