29 votes

Comment puis-je MODIFIER django pour créer la permission "view" ?

J'ai récemment commencé à utiliser django pour administrer une grande application existante qui s'est développée de manière organique au fil des ans en utilisant twisted.web. J'ai commencé à expérimenter avec django et son interface d'administration automatique et j'ai été très satisfait des résultats.

Une chose qui semble manquer pour mes besoins est la possibilité de donner aux utilisateurs un accès en lecture seule aux données. Par exemple, nous avons un rôle dans lequel les personnes sont autorisées à se connecter et à créer des bons de commande. Ils doivent également être en mesure de visualiser, mais pas de modifier d'autres données sur les clients ou les produits.

Comment créer des autorisations "view" dans l'administration de django pour que les utilisateurs puissent modifier les données de certaines tables, tout en ayant un accès en lecture seule à d'autres ?

Mise à jour : Django Admin semble me donner le CUD d'une interface CRUD. Comment puis-je obtenir la partie en lecture seule avec les autorisations et les groupes associés ?

Mise à jour 2010-Feb-12 : Django 1.2 inclura désormais la lecture seule. Détails ci-dessous.


J'ai répondu à ma propre question, je suppose. Déplacement du contenu vers une vraie réponse ci-dessous.

33voto

Great Turtle Points 1774

Voici comment j'ai modifié Django 1.0.2 pour ajouter les permissions 'view'. Désolé, il n'y a pas de différence disponible.

[X] 1. Ajout de "view" à la liste des autorisations par défaut

#./contrib/auth/management/__init__.py
def _get_all_permissions(opts):
    "Returns (codename, name) for all permissions in the given opts."
    perms = []
    for action in ('add', 'change', 'delete', 'view'):
        perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
    return perms + list(opts.permissions)

[X] 2. Test de l'ajout de l'autorisation "view" à tous les modèles

run manage.py syncdb

J'ai confirmé que la permission d'affichage est maintenant ajoutée pour toutes les tables dans la table auth_permissions.

[X] 3. Ajouter "get_view_permission" à la classe de modèle par défaut.

Ajouté get_view_permission à la classe de modèle. Vous pouvez trouver ceci dans le fichier ./db/models/options.py Ceci est utilisé par la classe admin dans l'étape suivante.

def get_view_permission(self):
    return 'view_%s' % self.object_name.lower()

[X] 4. Ajouter "has_view_permission" à la classe d'administration par défaut

Juste pour être cohérent, je vais ajouter "has_view_permission" au système. On dirait que ça devrait être quelque part dans contrib/admin/options.py . Je me suis assuré que si l'utilisateur a l'autorisation de modifier, alors les autorisations de visualisation sont automatiquement impliquées.

# /contrib/admin/options.py
# Added has_view_permissions
def has_view_permission(self, request, obj=None):
    """
    Returns True if the given request has permission to change or view
    the given Django model instance.

    If `obj` is None, this should return True if the given request has
    permission to change *any* object of the given type.
    """
    opts = self.opts
    return self.has_change_permission(request, obj) or \
        request.user.has_perm(opts.app_label + '.' + opts.get_view_permission())

# modified get_model_perms to include 'view' too.
# No idea where this may be used, but trying to stay consistent
def get_model_perms(self, request):
        """
        Returns a dict of all perms for this model. This dict has the keys
        ``add``, ``change``, and ``delete`` and ``view`` mapping to the True/False
        for each of those actions.
        """
        return {
            'add': self.has_add_permission(request),
            'change': self.has_change_permission(request),
            'delete': self.has_delete_permission(request),
            'view': self.has_view_permission(request),
        }

# modified response_add function to return the user to the mode list
# if they added a unit and have view rights
... 
    else:
        self.message_user(request, msg)

        # Figure out where to redirect. If the user has change permission,
        # redirect to the change-list page for this object. Otherwise,
        # redirect to the admin index.
        #if self.has_change_permission(request, None):
        if self.has_change_permission(request, None) or self.has_view_permission(request, None):
            post_url = '../'
        else:
            post_url = '../../../'
        return HttpResponseRedirect(post_url)

 # modified the change_view function so it becomes the details 
 # for users with view permission

    #if not self.has_change_permission(request, obj):
    if not (self.has_change_permission(request, obj) or (self.has_view_permission(request, obj) and not request.POST)):
        raise PermissionDenied

  # modified the changelist_view function so it shows the list of items
  # if you have view permissions
def changelist_view(self, request, extra_context=None):
    "The 'change list' admin view for this model."
    from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
    opts = self.model._meta
    app_label = opts.app_label
    #if not self.has_change_permission(request, None):
    if not (self.has_change_permission(request, None) or self.has_view_permission(request, None)):
        raise PermissionDenied

[X] 5. Mise à jour du modèle par défaut pour lister les modèles si l'utilisateur a le droit de les visualiser

J'ai modifié le modèle par défaut dans contrib/admin/templates/admin/index.html. Cela pourrait également être géré en copiant le fichier dans le répertoire local des modèles à la place. J'ai fait des changements dans les deux afin d'avoir une copie si une mise à jour ultérieure écrase mes changements.

 {% for model in app.models %}
            <tr>
            {% if model.perms.change %}
                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
            {% else %}
                {% if model.perms.view %}
                    <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
                {% else %}
                    <th scope="row">{{ model.name }}</th>
                {% endif %}
            {% endif %}

[X] 6. Confirmer que l'utilisateur peut "voir" mais pas "modifier" le modèle

Trouvé contrib/admin/templatetags/admin_modify.py semble contrôler l'apparition ou non des boutons "save / save and continue". J'ai modifié le champ "save", qui est par défaut toujours vrai, pour vérifier le contexte et les autorisations. L'utilisateur devrait être en mesure d'enregistrer s'il a des autorisations de modification ou d'ajout.

 'show_save': (change and context['has_change_permission']) or (context['add'] and context['has_add_permission'])

[X] 7. Suppression du bouton "Enregistrer et ajouter un autre" si l'utilisateur visualise un élément.

Modifié à nouveau contrib/admin/templatetags/admin_modify.py. Je ne sais pas ce que signifie "save_as" et j'ai peut-être cassé quelque chose, mais cela semble fonctionner.

    #'show_save_and_add_another': context['has_add_permission'] and
    #                    not is_popup and (not save_as or context['add']) ,
    'show_save_and_add_another': not is_popup and
        (( change and context['has_change_permission']) or (context['add'] and context['has_add_permission']))
        and
        (not save_as or context['add']),

[X] 8. Modifier la permission "view" pour que le formulaire soit en lecture seule.

Si l'utilisateur a le droit de "voir" et de "modifier", alors ne faites rien. La modification a priorité sur la visualisation.

Si l'utilisateur a le droit de "visualiser" sans "modifier", modifiez les formulaires par défaut et ajoutez les attributs DISABLED ou READONLY aux éléments de formulaire. Tous les navigateurs ne prennent pas en charge cette fonctionnalité, mais pour mes besoins, je peux exiger que les utilisateurs utilisent le bon navigateur. Exemple de désactivation / lecture seule

Il s'est avéré que tous les navigateurs n'acceptent pas l'option "readonly", ce qui fait que certains contrôles sont en lecture seule et d'autres sont désactivés. Cela permet aux utilisateurs de copier les données des contrôles de texte si nécessaire.

#/django/contrib/admin/templates/admin/change_form.html

{# JavaScript for prepopulated fields #}
{% prepopulated_fields_js %}

</div>
</form></div>
{% if has_view_permission and not has_change_permission %}
    <script type="text/javascript">
    jQuery('input:text').attr('readonly', 'readonly');
    jQuery('textarea').attr('readonly', 'readonly');
    jQuery('input:checkbox').attr('disabled', true);
    jQuery('select').attr('disabled', true);
    jQuery('.add-another').hide();
    </script>
{% endif %}

9voto

jasuca Points 1

Cet extrait fera de superuser le seul à avoir un accès en écriture.

class AdminOwn(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if request.user.is_superuser:
            return self.readonly_fields
        #get all fields as readonly
        fields = [f.name for f in self.model._meta.fields]
        return fields

4voto

Vinay Sajip Points 41286

C'est juste là dans l'administration. Vous pouvez définir des autorisations pour les utilisateurs et les groupes dans l'administration pour ajouter, modifier et supprimer des modèles spécifiques.

Mise à jour : Désolé, j'ai mal compris la question parce que j'ai mal interprété le mot vue pour lui donner le sens Django plutôt que "lecture seule". Si vous voulez la lecture seule en utilisant l'administrateur, je pense que vous devrez faire un peu de travail. Voir ce fil où James Bennett (responsable de la publication de Django) déclare :

Comme vous le constaterez en cherchant dans le archives de cette liste, ce n'est pas quelque chose que l'interface d'administration de Django n'est pas conçue pour le supporter, et donc toute solution devra venir entièrement de l'écriture de votre propre code.

y

L'administration de Django fonctionne avec trois permissions : "ajouter", "modifier" et et "delete". Il n'existe pas de permission " voir mais aucune modification", d'où il n'y a aucun moyen d'appliquer une telle restriction sans faire un codage personnalisé codage personnalisé.

Le travail supplémentaire consistera à ajouter une autorisation de "lecture seule" pour certains modèles et à modifier les modèles d'administration de base afin de vérifier si l'utilisateur dispose de cette autorisation et, le cas échéant, de désactiver certains contrôles (tels que les boutons de sauvegarde) et de rendre les autres en lecture seule. Cela empêchera les bricolages occasionnels, mais vous devrez peut-être aussi modifier la logique côté serveur pour vérifier la même autorisation, afin d'éviter tout POST effectué de manière sournoise pour contourner les autorisations.

3voto

Great Turtle Points 1774

La possibilité d'ajouter des champs en lecture seule dans la vue d'administration est désormais incluse dans la version 1.2 de Django.

Voir le billet numéro 342 http://code.djangoproject.com/ticket/342

Voir le numéro de changeset 11965 http://code.djangoproject.com/changeset/11965

Voir la documentation http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields

2voto

hogasa Points 41

Vous pouvez créer une permission "readonly" dans votre modèle et utiliser le code de jasuca avec une modification :

models.py :

class MyModel(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=256, null=True, blank=True)

    class Meta:
        permissions = (
            ('readonly_mymodel','Readonly MyModel'),
        )

admin.py :

class MyModelAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if not request.user.is_superuser and request.user.has_perm('mymodel.readonly_mymodel'):
            return [f.name for f in self.model._meta.fields]
        return self.readonly_fields

Dans l'administration de l'application, vous devez donner les autorisations de "modification" et de "lecture seule" à l'utilisateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X