Index: django/contrib/admin/templatetags/adminapplist.py
===================================================================
--- django/contrib/admin/templatetags/adminapplist.py	(revision 1270)
+++ django/contrib/admin/templatetags/adminapplist.py	(working copy)
@@ -23,6 +23,7 @@
                             'add': user.has_perm("%s.%s" % (app_label, m._meta.get_add_permission())),
                             'change': user.has_perm("%s.%s" % (app_label, m._meta.get_change_permission())),
                             'delete': user.has_perm("%s.%s" % (app_label, m._meta.get_delete_permission())),
+                            'view': user.has_perm("%s.%s" % (app_label, m._meta.get_view_permission())),
                         }
 
                         # Check whether user has any perm for this module.
Index: django/contrib/admin/views/main.py
===================================================================
--- django/contrib/admin/views/main.py	(revision 1270)
+++ django/contrib/admin/views/main.py	(working copy)
@@ -74,7 +74,7 @@
     IS_POPUP_VAR = 'pop'
 
     mod, opts = _get_mod_opts(app_label, module_name)
-    if not request.user.has_perm(app_label + '.' + opts.get_change_permission()):
+    if not (request.user.has_perm(app_label + '.' + opts.get_view_permission()) or request.user.has_perm(app_label + '.' + opts.get_change_permission())):
         raise PermissionDenied
 
     lookup_mod, lookup_opts = mod, opts
@@ -446,8 +446,11 @@
                     result_repr = '&nbsp;'
                 if j == 0: # First column is a special case
                     result_id = getattr(result, pk)
-                    raw_template.append('<th%s><a href="%s/"%s>%s</a></th>' % \
-                        (row_class, result_id, (is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr))
+                    if request.user.has_perm(app_label + '.' + opts.get_change_permission()):
+                        raw_template.append('<th%s><a href="%s/"%s>%s</a></th>' % \
+                            (row_class, result_id, (is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr))
+                    else:
+                        raw_template.append('<th%s>%s</th>' % (row_class, result_repr))
                 else:
                     raw_template.append('<td%s>%s</td>' % (row_class, result_repr))
             raw_template.append('</tr>\n')
Index: django/contrib/admin/templates/admin/index.html
===================================================================
--- django/contrib/admin/templates/admin/index.html	(revision 1270)
+++ django/contrib/admin/templates/admin/index.html	(working copy)
@@ -17,7 +17,7 @@
         <table>
         {% for model in app.models %}
             <tr>
-            {% if model.perms.change %}
+            {% if model.perms.view %}
                 <th><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
             {% else %}
                 <th>{{ model.name }}</th>
Index: django/core/meta/__init__.py
===================================================================
--- django/core/meta/__init__.py	(revision 1270)
+++ django/core/meta/__init__.py	(working copy)
@@ -268,6 +268,9 @@
     def get_delete_permission(self):
         return 'delete_%s' % self.object_name.lower()
 
+    def get_view_permission(self):
+        return 'view_%s' % self.object_name.lower()
+
     def get_rel_object_method_name(self, rel_opts, rel_field):
         # This method encapsulates the logic that decides what name to give a
         # method that retrieves related many-to-one objects. Usually it just
Index: django/core/management.py
===================================================================
--- django/core/management.py	(revision 1270)
+++ django/core/management.py	(working copy)
@@ -31,7 +31,7 @@
     "Returns (codename, name) for all permissions in the given opts."
     perms = []
     if opts.admin:
-        for action in ('add', 'change', 'delete'):
+        for action in ('add', 'change', 'delete', 'view'):
             perms.append((_get_permission_codename(action, opts), 'Can %s %s' % (action, opts.verbose_name)))
     return perms + list(opts.permissions)
 
