Добавление переменной Django Form без ввода поля
Я пытаюсь добавить переменную в форму Django, при этом переменная не должна быть полем формы. Мне нужен набор флажков, которые будут отмечены, если пользователь подписан на рассылку. Когда форма загружается, опции не загружаются успешно. При загрузке формы все подписки отмечаются. Функция обновления работает должным образом, и в базе данных отражаются правильные варианты после отправки. Пожалуйста, помогите мне выяснить, почему при загрузке формы не проверяются соответствующие подписки пользователей.
models.py
class Subscription(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(null=False, blank=False)
def __str__(self):
return self.name
class UserSubscription(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
subscription = models.ForeignKey(Subscription, on_delete=models.CASCADE)
start_date = models.DateTimeField(auto_now_add=True)
end_date = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.user.username + " " + self.subscription.name
views.py
@login_required(login_url='login')
def managesubscription(request):
userSubscriptions = UserSubscription.objects.filter(user=request.user)
subscriptions = Subscription.objects.all()
if request.method == 'POST':
form = ManageSubscriptionForm(request.POST, userSubscriptions=userSubscriptions)
if form.is_valid():
subscriptions = form.cleaned_data['subscriptions']
UserSubscription.objects.filter(user=request.user).delete()
for subscription in subscriptions:
print(subscription)
UserSubscription.objects.create(user=request.user, subscription=subscription)
messages.info(request, 'Subscriptions Updated')
return redirect('dashboard')
form = ManageSubscriptionForm(userSubscriptions=userSubscriptions, initial={'subscriptions': subscriptions, 'userSubscriptions': userSubscriptions})
return render(request, 'account/managesubscriptions.html', {'form': form})
forms.py
class ManageSubscriptionForm(forms.ModelForm):
subscriptions = forms.ModelMultipleChoiceField(
queryset=Subscription.objects.all(),
widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-input'}),
)
def __init__(self, *args, userSubscriptions, **kwargs):
self.userSubscriptions = userSubscriptions
print("here", userSubscriptions)
super().__init__(*args, **kwargs)
class Meta:
model = Subscription
fields = ['subscriptions']
managesubscriptions.html
<body>
<br>
<div class="container bg-white shadow-md p-5 form-layout">
<h3>Update Subscriptions</h3>
{% csrf_token %}
<br><br>
<form method="POST" autocomplete="off">
{% csrf_token %}
{% for subscription in form.subscriptions %}
<div class="form-check">
<input class="form-check-input" type="checkbox" name="subscriptions" value="{{ subscription.id }}" id="subscription{{ subscription.id }}"
{% if subscription.id in userSubscriptions %} checked {% endif %}> {{ subscription }}
</div>
{% endfor %}
<br />
<button type="submit" class="btn btn-primary my-2">Update Subscriptions</button>
</form>
</div>
</body>
для начала нужно отфильтровать user_subscriptions, получив только те подписки, для которых пользователь уже зарегистрирован
usersubscriptions = UserSubscription.objects.filter(user=request.user).values_list('subscription_id', flat=True)
values_list
- это метод Django, который позволяет получить из набора запросов только определенные поля, а не весь объект. Он извлекает только поле subscription_id из каждого UserSubscription, найденного предыдущим фильтром.
flat=True
указывает, что результат должен быть простым списком значений, а не списком кортежей.
Без flat=True
результатом будут кортежи, содержащие по одному элементу (например, [(1,), (2,), (3,)]).
При flat=True
вы получите плоский список типа [1, 2, 3]. Извлекает подписки, выбранные в форме
selected_subscriptions = form.cleaned_data['subscriptions']
selected_subscription_ids = set(sub.id for sub in selected_subscriptions)
selected_subscription_ids
создает набор, содержащий уникальные идентификаторы подписок, выбранных пользователем.
sub.id for sub in selected_subscriptions
происходит из Python. По сути, он сканирует каждый объект Subscription в selected_subscriptions и извлекает его атрибут id.
et le set
позволяет преобразовать последовательность идентификаторов в ансамбль
Только удаление подписок, с которых снят флажок
UserSubscription.objects.filter(user=request.user).exclude(subscription_id__in=selected_subscription_ids).delete()
Определяет первоначально выбранные подписки
form = ManageSubscriptionForm(userSubscriptions=userSubscriptions, initial={'subscriptions': usersubscriptions})
в файле forms.py Для метода init:
def __init__(self, *args, subscriptions=None, **kwargs):
super().__init__(*args, **kwargs)
if subscriptions is not None:
self.fields['subscriptions'].queryset = subscriptions
super().__init__(*args, **kwargs)
вызывает конструктор родительского класса (forms.ModelForm). При этом форма инициализируется обычным образом, обрабатывая все аргументы и ключевые слова, переданные при создании экземпляра формы.
subscriptions
позволит передать определенный набор запросов для поля подписки при инициализации.
if subscriptions is not None
, т.е. если указано subscriptions
, то кверисет self.fields['subscriptions']
заменяется этим конкретным кверисетом. Это означает, что в форме будут отображаться только экземпляры подписки, указанные в этом наборе кверисетов.