Как запросить поле ForeignKey, указывающее на другое поле ForeignKey в Django
У меня есть модель (Letter) с внешним ключом, указывающая на другую модель (Company) с внешним ключом. Ниже приведена простая схема из models.py
from django.contrib.auth.models import User
class Company (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, editable=False)
date_created = models.DateField(default=timezone.now, null=True)
company_name = models.CharField(max_length=100, null=True)
class Letter(models.Model):
company = models.ForeignKey(Company, related_name = "company_letter", on_delete=models.CASCADE, null=True)
subject = models.CharField(max_length=5000, null=True)
body = models.TextField()
Я создал форму, в которой пользователи могут создавать Письма с моделью через ModelForm. В настоящее время, когда пользователь получает форму для создания письма, в поле Company появляются все компании всех пользователей. См. рисунок ниже:
Я хотел бы, чтобы в выпадающем списке отображались только те компании, которые создал пользователь, а не все компании от всех пользователей. Или чтобы можно было выбрать первую компанию, которую создал пользователь.
В форме можно указать вошедшего пользователя и соответствующим образом отфильтровать. В конструкторе формы мы таким образом ограничиваем набор запросов с:
class LetterForm(forms.ModelForm):
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields['company'].widget.attrs = {'class': 'input',}
self.fields['subject'].widget.attrs = {'class': 'input', 'placeholder': 'RE: …'}
self.fields['body'].widget.attrs = {'class': 'textarea',}
if user is not None:
self.fields['company'].queryset = Company.objects.filter(user=user)
# …
и в представлении мы передаем вошедшего пользователя в конструктор формы:
from django.contrib.auth.decorators import login_required
@login_required
def letter_form(request):
if request.method == 'POST':
form = LetterForm(request.POST, request.FILES, user=request.user)
form.instance.user = request.user
if form.is_valid():
form.save()
return redirect('letter')
else:
form = LetterForm(user=request.user)
# …
Note: You can limit views to a view to authenticated users with the
@login_requireddecorator [Django-doc].
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL[Django-doc] to refer to the user model, than to use theUsermodel [Django-doc] directly. For more information you can see the referencing theUsermodel section of the documentation.
Если вы используете ModelForm для Letter, то это может выглядеть следующим образом:
class LetterForm(forms.ModelForm):
class Meta:
model = Letter
fields = ["company", "subject", "body"]
# you need to init the form with the right user instance
def __init__(self, user=None, *args, **kwargs):
# call the default __init__ behavior
super().__init__(*args, **kwargs)
# this is the trick, you will filter the companies queryset here
if user:
self.fields['company'].queryset = Company.objects.filter(user=user)
Так что вам нужно передать пользователя в форму из вашего представления:
что-то вроде:
def my_view(request):
# assuming the user follow the standard Django user implementation
# and you user is logged in
form = LetterForm(request.POST or None, user=request.user)
if form.is_valid():
form.save()
# then redirect the user to whatever success page
# render the form
return render(request, "your_template.html", {"form": form})