Question

J'ai consulté toute la documentation et le canal IRC (BTW, une grande communauté). Ils m'ont dit qu'il était impossible de créer un modèle et de limiter les choix dans un domaine où "l'utilisateur actuel" se trouvait dans une Clé étrangère. Je vais essayer d'expliquer cela avec un exemple:

class Project(models.Model):
  name = models.CharField(max_length=100)
  employees = models.ManyToManyField(Profile, limit_choices_to={'active': '1'})

class TimeWorked(models.Model):
  project = models.ForeignKey(Project, limit_choices_to={'user': user})
  hours = models.PositiveIntegerField()

Bien sûr, ce code ne fonctionne pas car il n'y a pas d'objet 'utilisateur', mais telle était mon idée et j'essayais d'envoyer l'objet 'utilisateur' au modèle pour limiter les choix lorsque l'utilisateur actuel a des projets. , Je ne veux pas voir de projets dans lesquels je ne suis pas.

Merci beaucoup si vous pouvez m'aider ou me donner un conseil, je ne veux pas que vous écriviez toute l'application, mais juste un conseil sur la façon de gérer cela. J'ai 2 jours avec cela dans la tête et je ne peux pas le comprendre: (

UPDATE : la solution est ici: http://collingrady.wordpress.com/2008/07/24/useful-form-tricks-in-django/ envoi de request.user à un modèle .

Était-ce utile?

La solution

Utilisez threadlocals si vous souhaitez obtenir un utilisateur actuel qui modifie ce modèle. Le middleware Threadlocals place l'utilisateur actuel dans une variable globale. Prenez ce middleware

from threading import local

_thread_locals = local()
def get_current_user():
    return getattr(getattr(_thread_locals, 'user', None),'id',None)

class ThreadLocals(object):
    """Middleware that gets various objects from the
    request object and saves them in thread local storage."""
    def process_request(self, request):
        _thread_locals.user = getattr(request, 'user', None)

Consultez la documentation sur l’utilisation des classes de middleware. Ensuite, n'importe où dans le code, vous pouvez appeler

user = threadlocals.get_current_user

Autres conseils

Le modèle lui-même ne sait rien de l'utilisateur actuel, mais vous pouvez lui donner une vue du formulaire qui exploite les objets modèles (et, dans le formulaire, réinitialisez choice pour le champ obligatoire).

Si vous en avez besoin sur le site d'administration, vous pouvez essayer raw_id_admin avec django-granular-permissions ( http://code.google.com/p/django-granular-permissions/ mais je n'ai pas pu le faire fonctionner rapidement mon django mais il semble être assez frais pour 1.0 donc ...).

Enfin, si vous avez grandement besoin d’une boîte de sélection dans l’administrateur, vous devrez alors pirater django.contrib.admin .

Cette limitation des choix à l'utilisateur actuel est une sorte de validation qui doit être effectuée de manière dynamique dans le cycle de demande, pas dans la définition de modèle statique.

En d'autres termes: au moment où vous créez une instance de ce modèle, vous serez dans une vue. À ce stade, vous aurez accès à l'utilisateur actuel et pourrez limiter les choix.

Ensuite, vous avez juste besoin d'un ModelForm personnalisé pour transmettre le request.user à, voir l'exemple ici: http://collingrady.wordpress.com/2008/ 07/24 / trucs-de-forme-utile-dans-django /

from datetime import datetime, timedelta
from django import forms
from mysite.models import Project, TimeWorked

class TimeWorkedForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(ProjectForm, self).__init__(*args, **kwargs)
        self.fields['project'].queryset = Project.objects.filter(user=user)

    class Meta:
        model = TimeWorked

alors à votre avis:

def time_worked(request):
    form = TimeWorkedForm(request.user, request.POST or None)
    if form.is_valid():
        obj = form.save()
        # redirect somewhere
    return render_to_response('time_worked.html', {'form': form})

En utilisant des vues génériques basées sur des classes dans Django 1.8.x / Python 2.7.x, voici ce que mes collègues et moi-même avons trouvé:

Dans models.py:

# ...

class Proposal(models.Model):
    # ...

    # Soft foreign key reference to customer
    customer_id = models.PositiveIntegerField()

    # ...

Dans forms.py:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.forms import ModelForm, ChoiceField, Select
from django import forms
from django.forms.utils import ErrorList
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from .models import Proposal
from account.models import User
from customers.models import customer



def get_customers_by_user(curUser=None):
    customerSet = None

    # Users with userType '1' or '2' are superusers; they should be able to see
    # all the customers regardless. Users with userType '3' or '4' are limited
    # users; they should only be able to see the customers associated with them
    # in the customized user admin.
    # 
    # (I know, that's probably a terrible system, but it's one that I
    # inherited, and am keeping for now.)
    if curUser and (curUser.userType in ['1', '2']):
        customerSet = customer.objects.all().order_by('company_name')
    elif curUser:
        customerSet = curUser.customers.all().order_by('company_name')
    else:
        customerSet = customer.objects.all().order_by('company_name')

    return customerSet


def get_customer_choices(customerSet):
    retVal = []

    for customer in customerSet:
        retVal.append((customer.customer_number, '%d: %s' % (customer.customer_number, customer.company_name)))

    return tuple(retVal)


class CustomerFilterTestForm(ModelForm):

    class Meta:
        model = Proposal
        fields = ['customer_id']

    def __init__(self, user=None, *args, **kwargs):
        super(CustomerFilterTestForm, self).__init__(*args, **kwargs)
        self.fields['customer_id'].widget = Select(choices=get_customer_choices(get_customers_by_user(user)))

# ...

Dans views.py:

# ...

class CustomerFilterTestView(generic.UpdateView):
    model = Proposal
    form_class = CustomerFilterTestForm
    template_name = 'proposals/customer_filter_test.html'
    context_object_name = 'my_context'
    success_url = "/proposals/"

    def get_form_kwargs(self):
        kwargs = super(CustomerFilterTestView, self).get_form_kwargs()
        kwargs.update({
            'user': self.request.user,
        })
        return kwargs

Dans les modèles / propositions / customer_filter_test.html:

{% extends "base/base.html" %}

{% block title_block %}
<title>Customer Filter Test</title>
{% endblock title_block %}

{% block header_add %}
<style>
    label {
        min-width: 300px;
    }
</style>
{% endblock header_add %}

{% block content_body %}
<form action="" method="POST">
    {% csrf_token %}
    <table>
        {{ form.as_table }}
    </table>
    <input type="submit" value="Save" class="btn btn-default" />
</form>
{% endblock content_body %}

Je ne suis pas sûr de bien comprendre exactement ce que vous voulez faire, mais je pense qu'il y a de bonnes chances que vous obteniez au moins une partie du chemin à l'aide d'un gestionnaire personnalisé . En particulier, n'essayez pas de définir vos modèles avec des restrictions pour l'utilisateur actuel, mais créez un gestionnaire qui ne renvoie que les objets correspondant à l'utilisateur actuel.

Hmmm, je ne comprends pas bien votre question. Mais si vous ne pouvez pas le faire lorsque vous déclarez le modèle, vous pouvez peut-être obtenir la même chose avec les méthodes de substitution de la classe d'objets dans laquelle vous envoyez. l'objet utilisateur, commencez peut-être par le constructeur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top