Django Form If condition in view.py with 2 instance - django

TO SAVE DATA that is inputted in form in Django i tried tomake it like this
I put this in my model.py
class Item(models.Model):
CATEGORY = (
('Gudang Kering', 'Gudang Kering'),
('Gudang Basah','Gudang Basah'),
)
name = models.CharField(max_length=200,null= True)
stock = models.IntegerField(default='0', blank=False, null=True)
category = models.CharField(max_length=200,null= True,choices=CATEGORY)
reorderlevel = models.IntegerField(default='0', blank=False, null=True)
maxreorderlevel = models.IntegerField(default='0', blank=False, null=True)
description = models.CharField(max_length=200,null= True, blank= True)
date_created = models.DateTimeField(auto_now_add= True)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Issue(models.Model):
STATUS = (
('Pending', 'Pending'),
('Granted','Granted'),
('Denied','Denied'),
)
customer = models.ForeignKey(Customer, null=True, on_delete= models.SET_NULL)
item = models.ForeignKey(Item, null=True, on_delete= models.SET_NULL)
quantity = models.IntegerField(default='0', blank=False, null=True)
date_created = models.DateTimeField(auto_now_add=True, auto_now=False)
status = models.CharField(max_length=200,null= True, choices=STATUS)
Then in view.py i define the form like this
def updateIssue(request, pk):
issue = Issue.objects.get(id=pk)
item = Item.objects.all()
form = UpdateIssueForm(instance=issue)
if request.method == 'POST':
form = UpdateIssueForm(request.POST,instance=issue)
#print ('printing:',request.POST)
if form.is_valid():
instance = form.save(commit=False)
if instance.status == 'Granted':
item.stock -= instance.quantity
instance.save()
item.save()
else:
instance.save()
return redirect('/')
context = {'form':form}
return render(request,'accounts/issue_form.html',context)``
The Goal
if instance == "Granted"
the item.stock will be decreased on the amount of instance.quantity
and will be saved.
else
instance will just be saved without affecting the stock from the 2nd model
The error
item = Item.objects.all()
even when called the item.stock have 0 attribute even when i have input data in database for that table

There is no need to get Item since we can access the Item related to Issue using the Issue object like issue.item. This is just an example from docs:
Article model has a field reporter which is a ForeignKey realted to Reporter model. Using Article object the Reporter object is accessed.
>>> new_article = r.article_set.create(headline="John's second story", pub_date=date(2005, 7, 29))
>>> new_article
<Article: John's second story>
>>> new_article.reporter
<Reporter: John Smith>
>>> new_article.reporter.id
1
Like so, we can access the Item using Issue
def updateIssue(request, pk):
issue = Issue.objects.get(id=pk) # we have our Issue here
form = UpdateIssueForm(instance=issue)
if request.method == 'POST':
form = UpdateIssueForm(request.POST,instance=issue)
if form.is_valid():
instance = form.save(commit=False)
if instance.status == 'Granted':
issue.item.stock -= instance.quantity # access Item by using Issue object's related field with name item
issue.item.save() # save the Item first
instance.save() # then the Issue
else:
instance.save()
return redirect('/')
context = {'form':form}
return render(request,'accounts/issue_form.html',context)

Related

Django ValueError: Cannot assign * must be a * instance

I am getting this error but I don't know why.
models.py
class Year(models.Model):
year = models.CharField(max_length=5, unique=True)
class Meta:
ordering = ['-year']
def __str__(self):
return self.year
class Photo(models.Model):
title = models.CharField(max_length=64)
description = models.CharField(max_length=255)
created = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='photos/')
thumbnail = ResizedImageField(blank=True, size=[360, 360], force_format='JPEG', upload_to='thumbnails/')
submitter = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
year = models.ForeignKey(Year, blank=True, on_delete=models.CASCADE)
views.py
def photo_create_view(request):
form = AddPhotoForm()
if request.method == 'POST':
image = request.FILES['image']
thumbnail = request.FILES['image']
title = request.POST.get('title')
description = request.POST.get('description')
year = request.POST.get('year')
people = request.POST.get('people')
tags = request.POST.get('tags')
photo = Photo(image=image, thumbnail=thumbnail, title=title, description=description, year=year,
people=people, tags=tags, submitter=request.user,)
photo.save()
return redirect('/photo/?page=1')
return render(request, 'photoapp/create.html', context={'form':form})
Cannot assign "123": "Photo.year" must be a "Year" instance. I have checked the Year table and year.id 123 exists. What am I missing?
year_id = int(request.POST.get('year'))
Photo(year_id=year_id, ...)
It's got to be the physical Year object
year = Year.objects.get_or_create(year=request.POST.get('year'))
Notes:
You could also use .get() or .filter().first(), must be the object and not a QuerySet
If you use a form you can get away with just the Pk in the request.POST
My own two sense: I don't think there's a benefit of having Year as it's own table, but maybe you're just using placeholders

How to display conditional form field that is dependent on an attribute of a selected foreign key on django model form

I want to conditionally display either frequency_input or duration_input fields based on the behavior.recording attribute of the selected behavior.
I have a Trial form that currently displays 3 fields:
behavior_name (foreign Key) dropdown
frequency_input
duration_input
Im not sure if i should the best method to solve this (Javascript or solve in the View)?
Trial Model
class Trial(models.Model):
behavior_name = models.ForeignKey(Behavior, on_delete=models.CASCADE)
client_session = models.ForeignKey(Client_Session, on_delete=models.CASCADE)
frequency_input = models.PositiveIntegerField(default=0, blank=True)
duration_input = models.DurationField(blank=True, default=timedelta(minutes=0))
class Meta:
verbose_name_plural = 'trials'
def __str__(self):
return str(self.id)
Behavior Model
RECORDING_CHOICES = (
('Rate','RATE'),
('Duration','DURATION'),
('Frequency','FREQUENCY')
)
class Behavior(models.Model):
name = models.CharField(max_length=200)
goal = models.CharField(max_length=200)
recording = models.CharField(max_length=10, choices=RECORDING_CHOICES, null=False)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='Active')
def __str__(self):
return self.name
Trial Form
class TrialForm(forms.ModelForm):
class Meta:
model = Trial
fields = ('behavior_name','frequency_input', 'duration_input')
Add Trial View
def add_trial(request, clientsession_id):
client_session = Client_Session.objects.get(id=clientsession_id)
if request.method != 'POST':
form = TrialForm()
else:
form = TrialForm(data=request.POST)
if form.is_valid():
add_trial = form.save(commit=False)
add_trial.client_session = client_session
add_trial.save()
return HttpResponse(status=204, headers={'HX-Trigger': 'trialupdated'})
context = {'client_session': client_session, 'form': form}
return render(request, 'sessions/add_trial.html', context)

model form is not saving in django it is telling user can not be nul

i crated a model name address and connected with user by foreign key so a user can have multiple address but it is not saving i want form to take that user id to save but i don't how to do that
here is my models.py
class Address(models.Model):
phoneNumberRegex = RegexValidator(regex = r"^\d{10,10}$")
pincodeRegex = RegexValidator(regex = r"^\d{6,6}$")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='address')
reciever_name = models.CharField(max_length=200, blank=False)
phone_no = models.CharField(validators = [phoneNumberRegex], max_length = 10, blank=False)
alt_phone_no = models.CharField(validators = [phoneNumberRegex], max_length = 10, blank=True)
state = models.CharField(max_length=50, choices=state_choice, blank=False)
pincode = models.CharField(validators = [pincodeRegex], max_length = 6, blank=False)
eighteen = models.CharField(blank=False, choices=eighteen_choice, default='Yes', max_length=4 )
city = models.CharField(max_length=100, blank=False)
address = models.CharField(max_length=500, blank=False)
locality = models.CharField(max_length=300, blank=True)
joined_date = models.DateTimeField(default=timezone.now,editable=False)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
my views.py
#login_required
def add_address(request, username):
if request.method == 'POST':
form = Addressform(request.POST)
if form.is_valid():
form.save()
return redirect('accounts:home')
else:
form = Addressform()
return render(request, 'add_address.html', {'form': form})
my form.py
class Addressform(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
exclude = ['user', 'joined_date', 'updated_at']
labels = {
'reciever_name':'Reciever Name',
'phone_no':'Phone No',
'alt_phone_no':'Alternate Phone No',
'state':'State/Union Territory',
'pincode':'Area Pincode',
'eighteen':'Is reciever is 18+',
'city':'City',
'address':'Address',
'locality':'Locality',
}
widgets = {
'eighteen': forms.RadioSelect()
}
what i want is in user field it take that user who his login automatically but i don't understand how i can achieve that
since you are excluding the user field from the form, it gets a null value on the post request. With a foreign key you cannot have a null field in the database. You have 2 options:
1) Add the request user
#login_required
def add_address(request, username):
if request.method == 'POST':
form = Addressform(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.user = request.user
form.save(commit=True)
return redirect('accounts:home')
else:
form = Addressform()
return render(request, 'add_address.html', {'form': form})
This will add the primary key of the user who is submitting the form as the foreign key of the address and hence associate the user with the address.
2) Allow user to select the user to associate with the address (not suggested)
The alternative method is to allow the user to select the user you want to associate with the address but it is not suggested as any user can associate any user with a particular address.
class Addressform(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
exclude = ['joined_date', 'updated_at']
labels = {
'reciever_name':'Reciever Name',
'phone_no':'Phone No',
'alt_phone_no':'Alternate Phone No',
'state':'State/Union Territory',
'pincode':'Area Pincode',
'eighteen':'Is reciever is 18+',
'city':'City',
'address':'Address',
'locality':'Locality',
}
widgets = {
'eighteen': forms.RadioSelect()
}

Django: how to add custom fields to data on form save?

I want to insert some custom variable eg Status into the model when the user submits the form. I want the field status to be updated to Pending when a new record is inserted. This should be done automatically when the user inserts a new form. I know how to insert the form with values set by the user how can i insert my own values instead.
My current form that inserts all data into db and it looks like this
def createProcess(request):
form = ProcessForm()
if request.method =='POST':
#print('Printing POST request : ', request.POST)
form = ProcessForm(request.POST)
if form.is_valid():
form.save() # above this i think i can add something to set the status
return redirect('process_list')
context = {'form' : form}
return render(request, 'process/create_process.html', context)
How can I customize the value of for eg the status field? I want the status field to automatically be updated without the user submitting any information.
This is the model
class ProcessInfo(models.Model):
process_name = models.CharField(max_length=120, null=True)
process_L2_process_name = models.CharField(default='L2 Process Name', max_length=120, null=True)
process_L3_process_name = models.CharField(default='L3 Process Name', max_length=120, null=True)
process_critical = models.BooleanField(default=True, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=200, null=True, choices=STATUS)
user_rel = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.process_name
You can make a form without the status field:
class ProcessForm(forms.ModelForm):
class Meta:
model = Process
exclude = ('status',)
in the view, you can then set the .status of the instance:
from django.contrib.auth.decorators import login_required
#login_required
def createProcess(request):
form = ProcessForm()
if request.method =='POST':
form = ProcessForm(request.POST)
if form.is_valid():
form.instance.status = 'pending'
form.instance.user_rel = request.user
form.save()
return redirect('process_list')
context = {'form' : form}
return render(request, 'process/create_process.html', context)
You can however also specify the default value for status in your model, and set the editable=… parameter [Django-doc] to False to prevent it showing up in the form, then it is autoamtically set to default value:
class ProcessInfo(models.Model):
# …
status = models.CharField(
max_length=200,
null=True,
choices=STATUS,
default='pending',
editable=False
)
def __str__(self):
return self.process_name

How to update two models with one form?

I want to be able to have a user update two models with one submit button. The first model will house all of the book titles (unique) and pages that users submit. The other will show which users submitted which books.
Ideally, I'd like to do something like this:
if request.method == "POST":
form = AddBookForm(request.POST)
if form.is_valid():
books = form.save(commit=False)
ub = UserBooks()
books.book_title = form.cleaned_data['book_title']
books.book_total_pages = form.cleaned_data['book_total_pages']
ub.user = request.user
ub.book_title = form.cleaned_data['book_title']
ub.save()
books.save()
return redirect('new_book')
But that's giving me the error:
Cannot assign "'Some Book Title'": "UserBooks.book_title" must be a
"Books" instance.
What would be the best way to update two models with one form?
Here are the other files.
models.py
class Books(models.Model):
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
book_title = models.CharField(max_length=100, unique=True)
book_total_pages = models.IntegerField()
class Meta:
ordering = ('-created',)
def __str__(self):
return '{0}'.format(self.book_title)
class UserBooks(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, blank=False)
book_title = models.ForeignKey(Books, on_delete=models.CASCADE, null=False, blank=False)
views.py
def new_book(request):
user = request.user
if request.method == "POST":
form = AddBookForm(request.POST)
if form.is_valid():
books = form.save(commit=False)
books.book_title = form.cleaned_data['book_title']
books.book_total_pages = form.cleaned_data['book_total_pages']
books.save()
return redirect('new_book')
else:
form = AddBookForm()
return render(request, 'main/addanewbook.html', {
'form': form,
'allBooks': allBooks,
'userbooks': userbooks,
})
forms.py
class AddBookForm(forms.ModelForm):
class Meta:
model = Books
fields = ('book_title', 'book_total_pages')
you need to change a bit in the view
if form.is_valid():
books = form.save(commit=False)
ub = UserBooks()
books.book_title = form.cleaned_data['book_title']
books.book_total_pages = form.cleaned_data['book_total_pages']
books = books.save()
ub.user = request.user
ub.book_title = books
ub.save()
return redirect('new_book')
this will do it