Multi select checkbox не работает при создании объекта в django
У меня есть приложение, в котором люди могут объявлять вещи, в decla они могут сказать, кто присутствовал, поэтому они должны платить, только оно не работает. Функция редактирования работает, а fileDecla - нет. Часть, которая не работает, это присутствующие люди. Когда я печатаю присутствующих (через print(request.POST)) перед сохранением декларации, она выдает всех выбранных людей, но потом не сохраняет их, а когда я печатаю(decla.present), я получаю --> None. (должны быть все присутствующие.
).Кто-то знает решение этой проблемы?
models.py
class Decla(models.Model):
owner = models.ForeignKey(Lid, on_delete=models.CASCADE)
event = models.ForeignKey(Event, on_delete=models.SET_NULL, null=True, blank=True)
content = models.TextField(max_length=50)
total = models.FloatField()
present = models.ManyToManyField(Lid, related_name="present_leden")
receipt = models.ImageField(
upload_to="declas/", null=True, blank=True
) ## this will need to be put back to nothing when it ends
verwerkt = models.BooleanField(default=False)
views.py
@login_required(login_url="login")
def fileDecla(request):
form = DeclaForm()
if request.method == "POST":
print(1, request.POST)
form = DeclaForm(request.POST, request.FILES)
if form.is_valid():
# print(form)
decla = form.save(commit=False)
decla.owner = request.user.lid
# i tried this line bellow but it didnt work
# decla.present.set(request.POST["present"])
decla.save()
messages.info(request, "Decla was created")
return redirect("agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
@login_required(login_url="login")
def editDecla(request, pk):
decla = Decla.objects.get(id=pk)
form = DeclaForm(instance=decla)
if request.method == "POST":
print(request.POST)
form = DeclaForm(request.POST, request.FILES, instance=decla)
if form.is_valid():
decla = form.save()
messages.info(request, "Decla was edited")
return redirect(request.GET["next"] if "next" in request.GET else "agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
forms.py
from django import forms
from django.forms import ModelForm
from django.forms.widgets import NumberInput, CheckboxSelectMultiple
from .models import Decla
class DeclaForm(ModelForm):
class Meta:
model = Decla
fields = "__all__"
exclude = ["owner", "id"]
widgets = {
"present": CheckboxSelectMultiple(),
}
def __init__(self, *args, **kwargs):
super(DeclaForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
if not name in ["verwerkt", "present"]:
field.widget.attrs.update({"class": "input"})
# also tried this
# elif name == "present":
# field.widget.attrs.update({"class": "CheckboxSelectMultiple"})
else:
field.widget.attrs.update({"class": "checkbox"})
Вот кое-что из документов:
Другой побочный эффект использования commit=False проявляется, когда ваша модель имеет отношение отношение "многие-ко-многим" с другой моделью. Если ваша модель имеет многие-ко-многим и вы указываете commit=False при сохранении форму, Django не может немедленно сохранить данные формы для отношения "многие-ко-многим". Это происходит потому, что невозможно сохранить данные отношения "многие-ко-многим" для экземпляра, пока этот экземпляр не существует в базе данных.
Чтобы обойти эту проблему, каждый раз, когда вы сохраняете форму, используя commit=False, Django добавляет метод save_m2m() в ваш ModelForm подкласса ModelForm. После того, как вы вручную сохранили экземпляр, созданный формы, вы можете вызвать save_m2m(), чтобы сохранить данные формы "многие ко многим".
.
Согласно этому, добавление save_m2m()
после вызова decla.save()
решит вашу проблему:
@login_required(login_url="login")
def fileDecla(request):
form = DeclaForm()
if request.method == "POST":
print(1, request.POST)
form = DeclaForm(request.POST, request.FILES)
if form.is_valid():
# print(form)
decla = form.save(commit=False)
decla.owner = request.user.lid
# i tried this line bellow but it didnt work
# decla.present.set(request.POST["present"])
decla.save()
form.save_m2m()
messages.info(request, "Decla was created")
return redirect("agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
Однако это кажется беспорядочным решением. Более подробную информацию смотрите в this antipattern.
Мое предложение состоит в следующем:
@login_required(login_url="login")
def fileDecla(request):
form = DeclaForm()
if request.method == "POST":
print(1, request.POST)
form = DeclaForm(request.POST, request.FILES)
if form.is_valid():
# This seems like a much cleaner solution and it should resolve your problem
form.instance.owner = request.user.lid
decla = form.save()
messages.info(request, "Decla was created")
return redirect("agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
Отказ от ответственности: код не проверен. Дайте мне знать, если у вас есть какие-либо ошибки.