Django ModelForm - Prevent save in View - django

I am trying to use a ModelForm to save a model.
forms.py
class PurchaseForm(forms.ModelForm):
weight = forms.IntegerField()
class Meta:
model = Purchase
fields = ["number", "pieces"]
views.py
if request.method == "POST":
form = PurchaseForm(request.POST)
if form.is_valid():
purchase = form.save(commit=False)
purchase.contract = Contract.objects.get(number=slug)
weight = form.cleaned_data.get('weight')
if check_weight(weight, purchase.contract):
weight_type = purchase.contract.supplier.market.weights
purchase.lbs, purchase.kgs = generate_weights(weight, weight_type)
purchase.save()
In the view above, I need to prevent the model from saving if the check_weight function returns False.
This function requires some data from the related object. I'm having some trouble figuring this out. What should I do?

If I'm understood your question correctly, this would work,
from django.http import HttpResponse
def my_form_view(request):
if request.method == "POST":
form = PurchaseForm(request.POST)
if form.is_valid():
purchase = form.save(commit=False)
purchase.contract = Contract.objects.get(number=slug)
weight = form.cleaned_data.get('weight')
if check_weight(weight, purchase.contract):
weight_type = purchase.contract.supplier.market.weights
purchase.lbs, purchase.kgs = generate_weights(weight, weight_type)
purchase.save()
return HttpResponse("save success")
return HttpResponse("'check_weight' returned False")
else: # if a GET (or any other method) we'll create a blank form
form = PurchaseForm()
return render(request, 'some_html_template.html', {'form': form})

Related

How do I pass field value as argument to next view Django?

I cannot find a way in the Django documentation to pass a value between different function views. I would like to create an object in my create_player_view, capture that new object pk and pass it to scoring_view. Doing this through the form action field has been unsuccessful as no data is passing between the views. What is a better way to do this?
I want a simple behavior that takes the Match ID created in create_player_view and passes it for update/use to scoring_view.
models
class Players(models.Model):
matchID = models.AutoField(primary_key=True)
player1Name = models.CharField(max_length=10)
player2Name = models.CharField(max_length=10)
def __str__(self):
return f'{self.matchID}: {self.player1Name} vs {self.player2Name}'
class Scores(models.Model):
matchID = models.OneToOneField(Players, on_delete=models.CASCADE, related_name='match')
p1_set_1_score = models.IntegerField(default=0)
p1_set_2_score = models.IntegerField(default=0)
p1_set_3_score = models.IntegerField(default=0)
p1_set_4_score = models.IntegerField(default=0)
p2_set_1_score = models.IntegerField(default=0)
p2_set_2_score = models.IntegerField(default=0)
p2_set_3_score = models.IntegerField(default=0)
p2_set_4_score = models.IntegerField(default=0)
def __str__(self):
return f'{self.matchID}: '
views
def create_player_view(request):
"""
allows users to name two
players competing vs one another
"""
if request.method == "POST":
form = PlayerForm(request.POST)
if form.is_valid():
form.save(commit=True)
return redirect('tennis:m_score') #is it possible to pass this view created instance?
else:
message = "Form could not be completed"
return render(request, "create_player.html", {"message":message})
else:
form = PlayerForm()
return render(request, "create_player.html",
{'form': form})
def scoring_view(request):
"""
View allows user to select the participating 2 players
and record their scores per set.
"""
if request.method == "POST":
form = ScoresForm(request.POST )#, instance=player_instance)
if form.is_valid():
form.save(commit=True)
return redirect('tennis:m_results')
else:
form = ScoresForm()
return render(request, "now_playing.html", {'form':form}) #todo add filtering
forms.py
class PlayerForm(ModelForm):
class Meta:
model = Players
exclude = ('matchID',)
labels = {
'playerName':('Player 1 Name', 'Player 2 Name'),
}
class ScoresForm(ModelForm):
class Meta:
model = Scores
fields = "__all__"
###urls.py
from django.urls import path
from tennis import views
app_name="tennis"
urlpatterns = [
path('players/', views.create_player_view, name="c_pl"),
path('scoring/<new_player>/', views.scoring_view, name="m_score"),
path('summary/', views.match_summary_view, name="m_results"),
]
Edit your views:
def create_player_view(request):
""""
allows users to name two
players competing vs one another
"""
if request.method == "POST":
form = PlayerForm(request.POST)
if form.is_valid():
new_player = = form.save(commit=True)
return redirect('tennis:m_score', new_player=new_player) # If you want to pass the pk instead of the object itself write: new_player=new_player.pk
else:
message = "Form could not be completed"
return render(request, "create_player.html", {"message":message})
else:
form = PlayerForm()
return render(request, "create_player.html",
{'form': form})
def scoring_view(request, new_player):
""""
View allows user to select the participating 2 players
and record their scores per set.
"""
if request.method == "POST":
# You can use the value of new_player as your needs
data = request.POST
data['matchID'] = new_player
form = ScoresForm(data)
if form.is_valid():
form.save(commit=True)
return redirect('tennis:m_results')
else:
form = ScoresForm()
return render(request, "now_playing.html", {'form':form}) #todo add filtering

How to check if `MultiSelectField` is empty or not in Django?

In my model I have a field department which is a MultiSelectField and I give the blank=True to that field for some reasons. Now I want to check if user fills the field or not. I have tried to get data from request.POST and gave it a condition using len() function like this if len(field) == 0: but I got an error. Everything works just fine until I added teacher_year = request.POST['teacher_year']
models.py
class CustomUser(AbstractUser):
teacher_department = MultiSelectField(choices=department_choice, blank=True)
forms.py
class TeacherRegisterForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ['teacher_year', ...]
views.py
def teacherRegisterView(request):
form = TeacherRegisterForm()
template_name = "attendance/login-register/teacher_register.html"
if request.method == "POST":
form = TeacherRegisterForm(request.POST)
teacher_year = request.POST['teacher_year']
if len(teacher_year) == 0:
messages.warning(request, "Just a remind! You didn't select deparment!")
return redirect('teacher_register')
elif form.is_valid():
form.save()
messages.success(request, "Your account was created! You can log in now.")
return redirect('/')
return render(request, template_name, {'form': form})
the error I got
django.utils.datastructures.MultiValueDictKeyError: 'teacher_year'
MultiValueDict is inherited from normal dict. So you can use get() method with it:
teacher_year = request.POST.get('teacher_year') # if request.POST doesn't contain teacher_year it returns None
if teacher_year:
...

Django change choice before validation

I am trying to update a choice field before it is validated in Django. The reason for this is the choice field in question value is the Id of a model that i want to update.
def fuelLogSystemOne(request):
entries = FuelLogSystemOneMod.objects.all().order_by('date')
products = productsMod.objects.all()
if request.method == 'POST':
form = forms.AddFuelLogOneForm(request.POST, request.FILES)
productid = form['product'].value()
product = productsMod.objects.get(id=productid)
product_id = request.POST.get('product')
form.fields['product'].choices = [(product.product_type, product.product_type)]
if form.is_valid():
bucketsRemoved = form['buckets_added'].value()
product.stock -= bucketsRemoved
product.save(['stock'])
instance = form.save(commit=False)
instance.staff = request.user
instance.save()
return redirect('home')
else:
form = forms.AddFuelLogOneForm()
return render(request,'systems/fuellogsystemone.html',{'form':form,'entry':entries,'products':products})
The below part is where i am trying to change the form data before it gets validated so it doesn't say 'Select a valid choice. 1 is not one of the available choices'
product_id = request.POST.get('product')
form.fields['product'].choices = [(product.product_type, product.product_type)]
But when I first submit the form it is still saying 'Select a valid choice.'
At what point does Django validate the form because I am changing the form before the is_valid() method and it still hits this error?
This should be in your form, you have to override the init method, and pass the product id during form initialization in the views
forms.py
class AddFuelLogOneForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
product = kwargs.pop('product', None)
self.fields['product'].choices = [(product.product_type, product.product_type)]
views.py
def fuelLogSystemOne(request):
entries = FuelLogSystemOneMod.objects.all().order_by('date')
products = productsMod.objects.all()
if request.method == 'POST':
product_id = request.POST.get('product')
productid = form['product'].value()
product = productsMod.objects.get(id=productid)
product_id = request.POST.get('product')
form = forms.AddFuelLogOneForm(request.POST, request.FILES, product=product)
if form.is_valid():
bucketsRemoved = form['buckets_added'].value()
product.stock -= bucketsRemoved
product.save(['stock'])
instance = form.save(commit=False)
instance.staff = request.user
instance.save()
return redirect('home')
else:
form = forms.AddFuelLogOneForm()
return render(request,'systems/fuellogsystemone.html',{'form':form,'entry':entries,'products':products})

the ModelMultipleChoiceField in modelForm not saved

I'm a Python/Django newbie and have been facing the following problem for several days now. I've got 2 ModelForms for a Model and the idea is that the data for one will help populate the multiplechoicefield of the second. The multiplechoice field for the second form populates ok but the problem is that the user's choices don't get saved. I've tried the save(commit=false) and save_m2m() but it hasn't fixed the issue.
models.py:
class Question(models.Model):
asker = models.ForeignKey(Student, related_name='asker+')
suggestedHelpers = models.ManyToManyField(Student, related_name='suggested')
chosenHelpers = models.ManyToManyField(Student, related_name='chosen')
class QuestionForm(ModelForm):
class Meta:
model = Question
exclude = ('chosenHelpers','suggestedHelpers', 'asker',)
class HelpersForm(ModelForm):
def suggesthelpers(self, question):
# populate chosenHelpers field according to data from QuestionForm
class Meta:
model = Question
exclude = ('suggestedHelpers', 'asker', 'questionSubj', 'Qtext',)
views.py
def askq_page(request):
question = Question(asker=Student.objects.get(user=request.user))
if request.method == 'POST':
form = QuestionForm(request.POST, instance=question)
if form.is_valid():
question = form.save()
# process data
question.save()
form2 = HelpersForm(instance=question)
form2.suggesthelpers(question)
variables = {'form':form2, 'qid':question.id}
return render_to_response('choosehelper.html', variables,context_instance=RequestContext(request))
else:
variables = RequestContext(request, {'form': QuestionForm()})
return render_to_response('askq.html', RequestContext(request, {'form': QuestionForm(instance=question)}))
def choosehelper_page(request, form='', qid=''):
question = Question.objects.get(id=qid)
if request.method == 'POST':
form2 = HelpersForm(request, instance=question)
# here lies the problem- the data gathered from form2 is not saved i.e. the multiple choices chosen by user are not returned
if form2.is_valid():
question = form2.save()
form2.save_m2m()
helpers = question.chosenHelpers.all()
for helper in helpers:
sentQ = ReceivedQ(question=question)
sentQ.student = helper
sentQ.save()
return render_to_response('questionsent.html', {'helpers': helpers, 'qid': question.id, 'qtext': q}, context_instance=RequestContext(request))
else:
form2 = HelpersForm(instance=question)
form2.suggesthelpers(question)
return render_to_response('choosehelper.html', RequestContext(request, {'form': form2, 'qid': qid}))

Saving modelform - won't validate

I'm doing something wrong here, but I can't find it.
I'm using a model form:
class ArtistInfo(ModelForm):
class Meta:
model = Onesheet
fields = (
'name',
'genre',
'location',
'biography',
)
And trying to save the data entered for an existing record.
def edit_artist_info(request, onesheet):
onesheet = Onesheet.objects.get(id = onesheet)
if request.method == 'POST':
form = ArtistInfo(request.POST, instance=onesheet)
if form.is_valid():
test = form.save(commit=False)
test.save()
HttpResponseRedirect('/')
form = ArtistInfo(instance=onesheet, label_suffix='')
variables = RequestContext(request, {
'onesheet':onesheet,
'form': form,
})
return render_to_response('edit_artist_info.html', variables)
But it's not saving. It just reloads the page with whatever the user changed, but if you actually refresh the page (grabbing the value from the DB), it's the old value.
Any ideas? If it's because the form isn't actually validating, I dont know why it's not validating.
try just
if request.method == 'POST':
form = ArtistInfo(request.POST, instance=onesheet)
if form.is_valid():
form.save()
return HttpResponseRedirect('/')
You were missing the return statement in your code, and the extra save() was unnecessary