Ticket #342: readonly-admin.7.diff

File readonly-admin.7.diff, 24.9 KB (added by Alex, 6 years ago)

Pretty printing

  • django/contrib/admin/helpers.py

    diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
    index 40437c0..8d93b46 100644
    a b  
    1 
    21from django import forms
    32from django.conf import settings
    4 from django.utils.html import escape
    5 from django.utils.safestring import mark_safe
    6 from django.utils.encoding import force_unicode
    73from django.contrib.admin.util import flatten_fieldsets
    84from django.contrib.contenttypes.models import ContentType
    9 from django.utils.translation import ugettext_lazy as _
     5from django.db import models
     6from django.db.models.fields import FieldDoesNotExist
     7from django.db.models.fields.related import ManyToManyRel
     8from django.forms.util import flatatt
     9from django.utils import dateformat
     10from django.utils.encoding import force_unicode, smart_unicode
     11from django.utils.html import escape
     12from django.utils.safestring import mark_safe
     13from django.utils.text import capfirst
     14from django.utils.translation import get_date_formats, ugettext_lazy as _
     15
    1016
    1117ACTION_CHECKBOX_NAME = '_selected_action'
    1218
    class ActionForm(forms.Form): 
    1622checkbox = forms.CheckboxInput({'class': 'action-select'}, lambda value: False)
    1723
    1824class AdminForm(object):
    19     def __init__(self, form, fieldsets, prepopulated_fields):
     25    def __init__(self, form, fieldsets, prepopulated_fields, readonly_fields):
    2026        self.form, self.fieldsets = form, normalize_fieldsets(fieldsets)
    2127        self.prepopulated_fields = [{
    2228            'field': form[field_name],
    2329            'dependencies': [form[f] for f in dependencies]
    2430        } for field_name, dependencies in prepopulated_fields.items()]
     31        self.readonly_fields = readonly_fields
    2532
    2633    def __iter__(self):
    2734        for name, options in self.fieldsets:
    28             yield Fieldset(self.form, name, **options)
     35            yield Fieldset(self.form, name,
     36                readonly_fields=self.readonly_fields, **options)
    2937
    3038    def first_field(self):
    3139        try:
    class AdminForm(object): 
    4957    media = property(_media)
    5058
    5159class Fieldset(object):
    52     def __init__(self, form, name=None, fields=(), classes=(), description=None):
     60    def __init__(self, form, name=None, readonly_fields=(), fields=(), classes=(),
     61        description=None):
    5362        self.form = form
    5463        self.name, self.fields = name, fields
    5564        self.classes = u' '.join(classes)
    5665        self.description = description
     66        self.readonly_fields = readonly_fields
    5767
    5868    def _media(self):
    5969        if 'collapse' in self.classes:
    class Fieldset(object): 
    6373
    6474    def __iter__(self):
    6575        for field in self.fields:
    66             yield Fieldline(self.form, field)
     76            yield Fieldline(self.form, field, self.readonly_fields)
    6777
    6878class Fieldline(object):
    69     def __init__(self, form, field):
     79    def __init__(self, form, field, readonly_fields):
    7080        self.form = form # A django.forms.Form instance
    7181        if isinstance(field, basestring):
    7282            self.fields = [field]
    7383        else:
    7484            self.fields = field
     85        self.readonly_fields = readonly_fields
    7586
    7687    def __iter__(self):
    7788        for i, field in enumerate(self.fields):
    78             yield AdminField(self.form, field, is_first=(i == 0))
     89            if field in self.readonly_fields:
     90                yield AdminReadonlyField(self.form, field, is_first=(i == 0))
     91            else:
     92                yield AdminField(self.form, field, is_first=(i == 0))
    7993
    8094    def errors(self):
    81         return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]).strip('\n'))
     95        return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields if f not in self.readonly_fields]).strip('\n'))
    8296
    8397class AdminField(object):
    8498    def __init__(self, form, field, is_first):
    class AdminField(object): 
    100114        attrs = classes and {'class': u' '.join(classes)} or {}
    101115        return self.field.label_tag(contents=contents, attrs=attrs)
    102116
     117class AdminReadonlyField(object):
     118    def __init__(self, form, field, is_first):
     119        self.field = field
     120        self.form = form
     121        self.is_first = is_first
     122        self.is_checkbox = False
     123        self.is_readonly = True
     124   
     125    def label_tag(self):
     126        attrs = {}
     127        if not self.is_first:
     128            attrs["class"] = "inline"
     129        contents = force_unicode(escape(forms.forms.pretty_name(self.field))) + u":"
     130        return mark_safe('<label %(attrs)s>%(contents)s</label>' % {
     131            "attrs": flatatt(attrs),
     132            "contents": contents,
     133        })
     134   
     135    def contents(self):
     136        from django.contrib.admin.templatetags.admin_list import _boolean_icon
     137        from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
     138        attr = getattr(self.form.instance, self.field)
     139        allow_tags = False
     140        boolean = False
     141        try:
     142            f = self.form.instance._meta.get_field_by_name(self.field)[0]
     143        except FieldDoesNotExist:
     144            value = attr
     145            if callable(attr):
     146                value = attr()
     147            allow_tags = getattr(attr, "allow_tags", False)
     148            boolean = getattr(attr, "boolean", False)
     149            if boolean:
     150                allow_tags = True
     151                result_repr = _boolean_icon(value)
     152            else:
     153                result_repr = smart_unicode(value)
     154        else:
     155            value = attr
     156            if value is None:
     157                result_repr = EMPTY_CHANGELIST_VALUE
     158            elif isinstance(f.rel, ManyToManyRel):
     159                result_repr = ", ".join(map(result_repr, value.all()))
     160            elif isinstance(f, models.DateField) or isinstance(f, models.TimeField):
     161                date_format, datetime_format, time_format = get_date_formats()
     162                if isinstance(f, models.DateTimeField):
     163                    result_repr = capfirst(dateformat.format(value, datetime_format))
     164                elif isinstance(f, models.TimeField):
     165                    result_repr = capfirst(dateformat.time_format(value, time_format))
     166                else:
     167                    result_repr = capfirst(dateformat.format(value, date_format))
     168            elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):
     169                result_repr = _boolean_icon(value)
     170            elif isinstance(f, models.DecimalField):
     171                result_repr = ("%%.%sf" % f.decimal_places) % value
     172            elif f.flatchoices:
     173                result_repr = dict(f.flatchoices).get(value, EMPTY_CHANGELIST_VALUE)
     174            else:
     175                result_repr = smart_unicode(value)
     176       
     177        if allow_tags:
     178            return mark_safe(result_repr)
     179        return escape(result_repr)
     180
    103181class InlineAdminFormSet(object):
    104182    """
    105183    A wrapper around an inline formset for use in the admin system.
    106184    """
    107     def __init__(self, inline, formset, fieldsets):
     185    def __init__(self, inline, formset, fieldsets, readonly_fields):
    108186        self.opts = inline
    109187        self.formset = formset
    110188        self.fieldsets = fieldsets
     189        self.readonly_fields = readonly_fields
    111190
    112191    def __iter__(self):
    113192        for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()):
    114             yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
     193            yield InlineAdminForm(self.formset, form, self.fieldsets,
     194                self.opts.prepopulated_fields, original, self.readonly_fields)
    115195        for form in self.formset.extra_forms:
    116             yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
     196            yield InlineAdminForm(self.formset, form, self.fieldsets,
     197                self.opts.prepopulated_fields, None, self.readonly_fields)
    117198
    118199    def fields(self):
    119200        fk = getattr(self.formset, "fk", None)
    class InlineAdminForm(AdminForm): 
    133214    """
    134215    A wrapper around an inline form for use in the admin system.
    135216    """
    136     def __init__(self, formset, form, fieldsets, prepopulated_fields, original):
     217    def __init__(self, formset, form, fieldsets, prepopulated_fields, original,
     218        readonly_fields):
    137219        self.formset = formset
    138220        self.original = original
    139221        if original is not None:
    140222            self.original_content_type_id = ContentType.objects.get_for_model(original).pk
    141223        self.show_url = original and hasattr(original, 'get_absolute_url')
    142         super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
     224        super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields,
     225            readonly_fields)
    143226
    144227    def __iter__(self):
    145228        for name, options in self.fieldsets:
    146             yield InlineFieldset(self.formset, self.form, name, **options)
     229            yield InlineFieldset(self.formset, self.form, name, self.readonly_fields, **options)
    147230
    148231    def has_auto_field(self):
    149232        if self.form._meta.model._meta.has_auto_field:
    class InlineFieldset(Fieldset): 
    194277        for field in self.fields:
    195278            if fk and fk.name == field:
    196279                continue
    197             yield Fieldline(self.form, field)
     280            yield Fieldline(self.form, field, self.readonly_fields)
    198281
    199282class AdminErrorList(forms.util.ErrorList):
    200283    """
  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    index 7193bee..8d605ea 100644
    a b class BaseModelAdmin(object): 
    6666    radio_fields = {}
    6767    prepopulated_fields = {}
    6868    formfield_overrides = {}
     69    readonly_fields = ()
    6970
    7071    def __init__(self):
    7172        self.formfield_overrides = dict(FORMFIELD_FOR_DBFIELD_DEFAULTS, **self.formfield_overrides)
    class BaseModelAdmin(object): 
    174175            return [(None, {'fields': self.fields})]
    175176        return None
    176177    declared_fieldsets = property(_declared_fieldsets)
     178   
     179    def get_readonly_fields(self, request, obj=None):
     180        return self.readonly_fields
    177181
    178182class ModelAdmin(BaseModelAdmin):
    179183    "Encapsulates all admin options and functionality for a given model."
    class ModelAdmin(BaseModelAdmin): 
    324328        if self.declared_fieldsets:
    325329            return self.declared_fieldsets
    326330        form = self.get_form(request, obj)
    327         return [(None, {'fields': form.base_fields.keys()})]
     331        fields = form.base_fields.keys() + list(self.get_readonly_fields(request, obj))
     332        return [(None, {'fields': fields})]
    328333
    329334    def get_form(self, request, obj=None, **kwargs):
    330335        """
    class ModelAdmin(BaseModelAdmin): 
    339344            exclude = []
    340345        else:
    341346            exclude = list(self.exclude)
     347        exclude.extend(kwargs.get("exclude", []))
     348        exclude.extend(self.get_readonly_fields(request, obj))
    342349        # if exclude is an empty list we pass None to be consistant with the
    343350        # default on modelform_factory
     351        exclude = exclude or None
    344352        defaults = {
    345353            "form": self.form,
    346354            "fields": fields,
    347             "exclude": (exclude + kwargs.get("exclude", [])) or None,
     355            "exclude": exclude,
    348356            "formfield_callback": curry(self.formfield_for_dbfield, request=request),
    349357        }
    350358        defaults.update(kwargs)
    class ModelAdmin(BaseModelAdmin): 
    764772                formset = FormSet(instance=self.model(), prefix=prefix)
    765773                formsets.append(formset)
    766774
    767         adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), self.prepopulated_fields)
     775        adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)),
     776            self.prepopulated_fields, self.get_readonly_fields(request)
     777        )
    768778        media = self.media + adminForm.media
    769779
    770780        inline_admin_formsets = []
    771781        for inline, formset in zip(self.inline_instances, formsets):
    772782            fieldsets = list(inline.get_fieldsets(request))
    773             inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets)
     783            readonly = list(inline.get_readonly_fields(request))
     784            inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
     785                fieldsets, readonly)
    774786            inline_admin_formsets.append(inline_admin_formset)
    775787            media = media + inline_admin_formset.media
    776788
    class ModelAdmin(BaseModelAdmin): 
    853865                formset = FormSet(instance=obj, prefix=prefix)
    854866                formsets.append(formset)
    855867
    856         adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
     868        adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj),
     869            self.prepopulated_fields, self.get_readonly_fields(request, obj))
    857870        media = self.media + adminForm.media
    858871
    859872        inline_admin_formsets = []
    860873        for inline, formset in zip(self.inline_instances, formsets):
    861874            fieldsets = list(inline.get_fieldsets(request, obj))
    862             inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets)
     875            readonly = list(inline.get_readonly_fields(request, obj))
     876            inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
     877                fieldsets, readonly)
    863878            inline_admin_formsets.append(inline_admin_formset)
    864879            media = media + inline_admin_formset.media
    865880
    class InlineModelAdmin(BaseModelAdmin): 
    11511166            exclude = []
    11521167        else:
    11531168            exclude = list(self.exclude)
     1169        exclude.extend(kwargs.get("exclude", []))
     1170        exclude.extend(self.get_readonly_fields(request, obj))
    11541171        # if exclude is an empty list we use None, since that's the actual
    11551172        # default
     1173        exclude = exclude or None
    11561174        defaults = {
    11571175            "form": self.form,
    11581176            "formset": self.formset,
    11591177            "fk_name": self.fk_name,
    11601178            "fields": fields,
    1161             "exclude": (exclude + kwargs.get("exclude", [])) or None,
     1179            "exclude": exclude,
    11621180            "formfield_callback": curry(self.formfield_for_dbfield, request=request),
    11631181            "extra": self.extra,
    11641182            "max_num": self.max_num,
    class InlineModelAdmin(BaseModelAdmin): 
    11701188        if self.declared_fieldsets:
    11711189            return self.declared_fieldsets
    11721190        form = self.get_formset(request).form
    1173         return [(None, {'fields': form.base_fields.keys()})]
     1191        fields = form.base_fields.keys() + list(self.get_readonly_fields(request, obj))
     1192        return [(None, {'fields': fields})]
    11741193
    11751194class StackedInline(InlineModelAdmin):
    11761195    template = 'admin/edit_inline/stacked.html'
  • django/contrib/admin/templates/admin/includes/fieldset.html

    diff --git a/django/contrib/admin/templates/admin/includes/fieldset.html b/django/contrib/admin/templates/admin/includes/fieldset.html
    index 8ee24b1..bcde368 100644
    a b  
    11<fieldset class="module aligned {{ fieldset.classes }}">
    2   {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
    3   {% if fieldset.description %}<div class="description">{{ fieldset.description|safe }}</div>{% endif %}
    4   {% for line in fieldset %}
    5       <div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
    6       {{ line.errors }}
    7       {% for field in line %}
    8       <div{% if not line.fields|length_is:"1" %} class="field-box"{% endif %}>
    9           {% if field.is_checkbox %}
    10               {{ field.field }}{{ field.label_tag }}
    11           {% else %}
    12               {{ field.label_tag }}{{ field.field }}
    13           {% endif %}
    14           {% if field.field.field.help_text %}<p class="help">{{ field.field.field.help_text|safe }}</p>{% endif %}
    15       </div>
    16       {% endfor %}
    17       </div>
    18   {% endfor %}
     2    {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
     3    {% if fieldset.description %}
     4        <div class="description">{{ fieldset.description|safe }}</div>
     5    {% endif %}
     6    {% for line in fieldset %}
     7        <div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
     8            {{ line.errors }}
     9            {% for field in line %}
     10                <div{% if not line.fields|length_is:"1" %} class="field-box"{% endif %}>
     11                    {% if field.is_checkbox %}
     12                        {{ field.field }}{{ field.label_tag }}
     13                    {% else %}
     14                        {{ field.label_tag }}
     15                        {% if field.is_readonly %}
     16                            {{ field.contents }}
     17                        {% else %}
     18                            {{ field.field }}
     19                        {% endif %}
     20                    {% endif %}
     21                    {% if field.field.field.help_text %}
     22                        <p class="help">{{ field.field.field.help_text|safe }}</p>
     23                    {% endif %}
     24                </div>
     25            {% endfor %}
     26        </div>
     27    {% endfor %}
    1928</fieldset>
  • django/contrib/admin/validation.py

    diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
    index 726da65..ace2297 100644
    a b def validate(cls, model): 
    122122            if '__' in field:
    123123                continue
    124124            get_field(cls, model, opts, 'ordering[%d]' % idx, field)
     125   
     126    if hasattr(cls, "readonly_fields"):
     127        check_isseq(cls, "readonly_fields", cls.readonly_fields)
     128        for idx, field in enumerate(cls.readonly_fields):
     129            try:
     130                field = opts.get_field_by_name(field)[0]
     131            except models.FieldDoesNotExist:
     132                raise ImproperlyConfigured("'%s.readonly_fields[%d]' refers to a "
     133                    "field, '%s', not defined on %s."
     134                    % (cls.__name__, idx, field, model.__name__))
     135           
    125136
    126137    # list_select_related = False
    127138    # save_as = False
  • docs/ref/contrib/admin/index.txt

    diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
    index 0f746bf..36a7d9e 100644
    a b into a ``Input`` widget for either a ``ForeignKey`` or ``ManyToManyField``:: 
    540540    class ArticleAdmin(admin.ModelAdmin):
    541541        raw_id_fields = ("newspaper",)
    542542
     543.. attribute:: ModelAdmin.readonly_fields
     544
     545By default any field Django's admin displays is shown as editable.  Any fields
     546in this option (which should be a ``list`` or ``tuple``) will be displayed as
     547just showing the data they contain, without the ability to be edited.  Note
     548that fields in this option shouldn't be in the ``fields`` or ``exclude``
     549options, they can however be in the ``fieldsets`` option to control where they
     550appear.
     551
    543552.. attribute:: ModelAdmin.save_as
    544553
    545554Set ``save_as`` to enable a "save as" feature on admin change forms.
    model instance:: 
    744753                instance.save()
    745754            formset.save_m2m()
    746755
     756.. method:: ModelAdmin.get_readonly_fields(self, request, obj=None)
     757
     758The ``get_readonly_fields`` method is given the ``HttpRequest`` and the
     759``obj`` being edited (or ``None`` on a add form) and is expected to return a
     760``list`` or ``tuple`` of field names that will be displayed as read-only, as
     761described above in the ``ModelAdmin.readonly_fields`` section.  Note that this
     762method will be called several times during a given request, therefore if it
     763performs and very expensive calculations it may be wise to cache them.
     764
    747765.. method:: ModelAdmin.get_urls(self)
    748766
    749767.. versionadded:: 1.1
  • tests/regressiontests/admin_validation/models.py

    diff --git a/tests/regressiontests/admin_validation/models.py b/tests/regressiontests/admin_validation/models.py
    index eb53a9d..760469b 100644
    a b Exception: <class 'regressiontests.admin_validation.models.TwoAlbumFKAndAnE'> ha 
    110110
    111111>>> validate_inline(TwoAlbumFKAndAnEInline, None, Album)
    112112
     113>>> class SongAdmin(admin.ModelAdmin):
     114...     readonly_fields = ("title",)
     115
     116>>> validate(SongAdmin, Song)
     117
     118>>> class SongAdmin(admin.ModelAdmin):
     119...     readonly_fields = ("title", "nonexistant")
     120
     121>>> validate(SongAdmin, Song)
     122Traceback (most recent call last):
     123    ...
     124ImproperlyConfigured: 'SongAdmin.readonly_fields[1]' refers to a field, 'nonexistant', not defined on Song.
     125
    113126# Regression test for #12203/#12237 - Fail more gracefully when a M2M field that
    114127# specifies the 'through' option is included in the 'fields' or the 'fieldsets'
    115128# ModelAdmin options.
  • tests/regressiontests/admin_views/models.py

    diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
    index 50bc05e..7b81bb0 100644
    a b  
    11# -*- coding: utf-8 -*-
     2import datetime
    23import tempfile
    34import os
    4 from django.core.files.storage import FileSystemStorage
    5 from django.db import models
     5
    66from django.contrib import admin
     7from django.core.files.storage import FileSystemStorage
    78from django.core.mail import EmailMessage
     9from django.db import models
     10
    811
    912class Section(models.Model):
    1013    """
    class CategoryInline(admin.StackedInline): 
    420423class CollectorAdmin(admin.ModelAdmin):
    421424    inlines = [WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, FancyDoodadInline, CategoryInline]
    422425
     426class Post(models.Model):
     427    title = models.CharField(max_length=100)
     428    content = models.TextField()
     429    posted = models.DateField(default=datetime.date.today)
     430
     431class PostAdmin(admin.ModelAdmin):
     432    readonly_fields = ('posted',)
     433
    423434admin.site.register(Article, ArticleAdmin)
    424435admin.site.register(CustomArticle, CustomArticleAdmin)
    425436admin.site.register(Section, save_as=True, inlines=[ArticleInline])
    admin.site.register(Recommendation, RecommendationAdmin) 
    443454admin.site.register(Recommender)
    444455admin.site.register(Collector, CollectorAdmin)
    445456admin.site.register(Category, CategoryAdmin)
     457admin.site.register(Post, PostAdmin)
    446458
    447459# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
    448460# That way we cover all four cases:
  • tests/regressiontests/admin_views/tests.py

    diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
    index 167498a..3e19bf3 100644
    a b from django.contrib.admin.models import LogEntry, DELETION 
    1010from django.contrib.admin.sites import LOGIN_FORM_KEY
    1111from django.contrib.admin.util import quote
    1212from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
     13from django.utils import dateformat
    1314from django.utils.cache import get_max_age
    1415from django.utils.html import escape
     16from django.utils.translation import get_date_formats
    1517
    1618# local test models
    1719from models import Article, BarAccount, CustomArticle, EmptyModel, \
    1820    ExternalSubscriber, FooAccount, Gallery, ModelWithStringPrimaryKey, \
    1921    Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, \
    2022    Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, \
    21     Category
     23    Category, Post
    2224
    23 try:
    24     set
    25 except NameError:
    26     from sets import Set as set
    2725
    2826class AdminViewBasicTest(TestCase):
    2927    fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml']
    class NeverCacheTests(TestCase): 
    16331631        "Check the never-cache status of the Javascript i18n view"
    16341632        response = self.client.get('/test_admin/jsi18n/')
    16351633        self.failUnlessEqual(get_max_age(response), None)
     1634
     1635
     1636class ReadonlyTest(TestCase):
     1637    fixtures = ['admin-views-users.xml']
     1638
     1639    def setUp(self):
     1640        self.client.login(username='super', password='secret')
     1641
     1642    def tearDown(self):
     1643        self.client.logout()
     1644
     1645    def test_readonly_get(self):
     1646        response = self.client.get('/test_admin/admin/admin_views/post/add/')
     1647        self.assertEqual(response.status_code, 200)
     1648        self.assertNotContains(response, 'name="posted"')
     1649        # 3 fields + 2 submit buttons
     1650        self.assertEqual(response.content.count("input"), 5)
     1651        self.assertContains(response,
     1652            dateformat.format(datetime.date.today(), get_date_formats()[0]))
     1653   
     1654    def test_readonly_post(self):
     1655        data = {
     1656            "title": "Django Got Readonly Fields",
     1657            "content": "This is an incredible development."
     1658        }
     1659        response = self.client.post('/test_admin/admin/admin_views/post/add/', data)
     1660        self.assertEqual(response.status_code, 302)
     1661        self.assertEqual(Post.objects.count(), 1)
     1662        p = Post.objects.get()
     1663        self.assertEqual(p.posted, datetime.date.today())
     1664       
     1665        data["posted"] = "10-8-1990" # some date that's not today
     1666        response = self.client.post('/test_admin/admin/admin_views/post/add/', data)
     1667        self.assertEqual(response.status_code, 302)
     1668        self.assertEqual(Post.objects.count(), 2)
     1669        p = Post.objects.order_by('-id')[0]
     1670        self.assertEqual(p.posted, datetime.date.today())
Back to Top