Dites que j'ai ce qui suit dans mon models.py
:
class Company(models.Model):
name = ...
class Rate(models.Model):
company = models.ForeignKey(Company)
name = ...
class Client(models.Model):
name = ...
company = models.ForeignKey(Company)
base_rate = models.ForeignKey(Rate)
C'est-à-dire qu'il y en a plusieurs Companies
, chacun ayant une plage de Rates
et Clients
. Chacun Client
doit avoir une base Rate
choisie parmi ses parents Company's Rates
, pas une autre Company's Rates
.
Lors de la création d'un formulaire pour ajouter un Client
, je voudrais supprimer les Company
choix (car cela a déjà été sélectionné via un bouton "Ajouter un client" sur la Company
page) et limiter les Rate
choix à cela Company
également.
Comment procéder à ce sujet dans Django 1.0?
Mon forms.py
dossier actuel est juste passe-partout pour le moment:
from models import *
from django.forms import ModelForm
class ClientForm(ModelForm):
class Meta:
model = Client
Et views.py
c'est aussi basique:
from django.shortcuts import render_to_response, get_object_or_404
from models import *
from forms import *
def addclient(request, company_id):
the_company = get_object_or_404(Company, id=company_id)
if request.POST:
form = ClientForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(the_company.get_clients_url())
else:
form = ClientForm()
return render_to_response('addclient.html', {'form': form, 'the_company':the_company})
Dans Django 0.96, j'ai pu pirater cela en faisant quelque chose comme ceci avant de rendre le modèle:
manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]
ForeignKey.limit_choices_to
semble prometteur mais je ne sais pas comment passer the_company.id
et je ne sais pas si cela fonctionnera de toute façon en dehors de l'interface d'administration.
Merci. (Cela semble être une demande assez basique mais si je devais repenser quelque chose, je suis ouvert aux suggestions.)
Réponses:
ForeignKey est représenté par django.forms.ModelChoiceField, qui est un ChoiceField dont les choix sont un modèle QuerySet. Voir la référence pour ModelChoiceField .
Donc, fournissez un QuerySet à l'
queryset
attribut du champ . Cela dépend de la façon dont votre formulaire est créé. Si vous créez un formulaire explicite, vous aurez des champs nommés directement.Si vous prenez l'objet ModelForm par défaut,
form.fields["rate"].queryset = ...
Cela se fait explicitement dans la vue. Pas de piratage autour.
la source
__init__
méthode du formulaire ?En plus de la réponse de S.Lott et comme devenirGuru mentionné dans les commentaires, il est possible d'ajouter les filtres de jeu de requêtes en remplaçant la
ModelForm.__init__
fonction. (Cela pourrait facilement s'appliquer aux formulaires standard), il peut aider à la réutilisation et garder la fonction d'affichage bien rangée.Cela peut être utile pour la réutilisation, par exemple si vous avez des filtres communs nécessaires sur de nombreux modèles (normalement je déclare une classe de formulaire abstraite). Par exemple
En dehors de cela, je ne fais que reformuler le contenu du blog Django, dont il existe de nombreux bons.
la source
C'est simple et fonctionne avec Django 1.4:
Vous n'avez pas besoin de le spécifier dans une classe de formulaire, mais vous pouvez le faire directement dans ModelAdmin, car Django inclut déjà cette méthode intégrée sur ModelAdmin (à partir des documents):
Une manière encore plus astucieuse de le faire (par exemple, en créant une interface d'administration frontale accessible aux utilisateurs) consiste à sous-classer le ModelAdmin, puis à modifier les méthodes ci-dessous. Le résultat net est une interface utilisateur qui leur montre UNIQUEMENT du contenu qui leur est lié, tout en vous permettant (à un super-utilisateur) de tout voir.
J'ai remplacé quatre méthodes, les deux premières empêchent un utilisateur de supprimer quoi que ce soit, et il supprime également les boutons de suppression du site d'administration.
Le troisième remplacement filtre toute requête qui contient une référence à (dans l'exemple «utilisateur» ou «porc-épic» (juste à titre d'illustration).
La dernière substitution filtre tout champ de clé étrangère dans le modèle pour filtrer les choix disponibles de la même manière que l'ensemble de requêtes de base.
De cette façon, vous pouvez présenter un site d'administration frontal facile à gérer qui permet aux utilisateurs de jouer avec leurs propres objets, et vous n'avez pas à vous rappeler de taper les filtres ModelAdmin spécifiques dont nous avons parlé ci-dessus.
supprimer les boutons «supprimer»:
empêche l'autorisation de suppression
filtre les objets visibles sur le site d'administration:
filtre les choix pour tous les champs de clé étrangère sur le site d'administration:
la source
Pour ce faire avec une vue générique, comme CreateView ...
la partie la plus importante de cela ...
, lisez mon article ici
la source
Si vous n'avez pas créé le formulaire et souhaitez modifier l'ensemble de requêtes, vous pouvez le faire:
C'est assez utile lorsque vous utilisez des vues génériques!
la source
J'ai donc vraiment essayé de comprendre cela, mais il semble que Django ne rend toujours pas cela très simple. Je ne suis pas du tout stupide, mais je ne vois aucune solution (quelque peu) simple.
Je trouve généralement assez moche de devoir remplacer les vues Admin pour ce genre de choses, et chaque exemple que je trouve ne s'applique jamais entièrement aux vues Admin.
C'est une circonstance tellement courante avec les modèles que je fabrique que je trouve épouvantable qu'il n'y ait pas de solution évidente à cela ...
J'ai ces cours:
Cela crée un problème lors de la configuration de l'administrateur pour la société, car il comporte des lignes pour le contrat et l'emplacement, et les options m2m du contrat pour l'emplacement ne sont pas correctement filtrées selon la société que vous modifiez actuellement.
En bref, j'aurais besoin d'une option d'administration pour faire quelque chose comme ceci:
En fin de compte, je me fiche de savoir si le processus de filtrage a été placé sur la base CompanyAdmin, ou s'il a été placé sur ContractInline. (Le placer sur l'inline est plus logique, mais il est difficile de référencer le contrat de base en tant que «soi».)
Y a-t-il quelqu'un qui sait quelque chose d'aussi simple que ce raccourci si nécessaire? À l'époque où j'ai créé des administrateurs PHP pour ce genre de choses, cela était considéré comme une fonctionnalité de base! En fait, il était toujours automatique et devait être désactivé si vous ne le vouliez vraiment pas!
la source
Une manière plus publique consiste à appeler get_form dans les classes Admin. Cela fonctionne également pour les champs non-base de données. Par exemple, ici, j'ai un champ appelé '_terminal_list' sur le formulaire qui peut être utilisé dans des cas spéciaux pour choisir plusieurs éléments de terminal dans get_list (request), puis filtrer en fonction de request.user:
la source