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

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

Related

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 Form If condition in view.py with 2 instance

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)

how to update a extended Django User model?

I have created the user authentication system which includes both the default User model and an extended User model. They are as below:
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
Photo = models.ImageField(upload_to='documents/%Y/%m/%d/', null=True)
uploaded_at = models.DateTimeField(auto_now_add=True, null=True)
dob = models.DateField(max_length=20, null=True)
country = models.CharField(max_length=100, null=True)
State = models.CharField(max_length=100, null=True)
District = models.CharField(max_length=100, null=True)
phone = models.CharField(max_length=10, null=True)
def get_absolute_url(self):
return reverse('profile', kwargs={'id': self.id})
forms.py
class UserProfileForm(forms.ModelForm):
Photo = forms.ImageField( max_length=100)
dob = forms.DateField(widget=forms.TextInput(attrs={'type': 'date'}))
country = forms.CharField(max_length=100)
State = forms.CharField(max_length=100)
District = forms.CharField(max_length=100)
phone = forms.CharField(max_length=10)
class Meta:
model = UserProfile
fields = ('Photo', 'dob', 'country', 'State', 'District', 'phone')
With the help of the above model and form, I am able to create user, and enter values for those custom model fields and see the user profile. So far so good.
However, I am facing issues while I update those custom fields. I have used the Django's in-built modules to update the default User fields(email). But I am not able to find a way to update those custom fields('dob', 'country', 'State', 'District', 'phone'). Below is the method from views.
views.py
#login_required(login_url="/login/")
def editUserProfile(request):
if request.method == "POST":
form = UserProfileUpdateForm(request.POST, instance=request.user) # default User profile update
obj = UserProfile.objects.get(id=request.user.id)
form1 = UserProfileForm(request.POST or None, instance=obj) # custom fields update.
if form.is_valid() and form1.is_valid():
obj.Photo = form1.cleaned_data['Photo']
obj.dob = form1.cleaned_data['dob']
obj.country = form1.cleaned_data['country']
obj.State = form1.cleaned_data['State']
obj.District = form1.cleaned_data['District']
obj.phone = form1.cleaned_data['phone']
form.save()
form1.save()
messages.success(request, f'updated successfully')
return redirect('/profile1')
else:
messages.error(request, f'Please correct the error below.')
else:
form = UserProfileUpdateForm(instance=request.user)
form1 = UserProfileUpdateForm(instance=request.user)
return render(request, "authenticate\\editProfilePage.html", {'form': form, 'form1': form1})
I have an update button on my profile page, on clicking I could only see the "email" field with pre-populated data to update(I can update this default field successfully).
I have seen other stackoverflow posts, but they are not helping.
I am not able to figure out the mistakes.
Please help
Thank you,
I think the problem is in this line
obj = UserProfile.objects.get(id=request.user.id)
here left id is id from UserProfile model. so it will be something like this
obj = UserProfile.objects.get(user__id=request.user.id)

Django Key Error on Form Submit When Overriding Get_Initial on CreateView

I have a generic CreateView that populates a form with some default values along with the primary key value of its parent object. The form is populated correctly, but on submit it throws a KeyError for lumberload_id.
Debugging shows that it overrides the get_initial method on both GET and POST meaning that it tries to access the lumberload object which no longer exists when submitting the form.
It seems to me that there is not a need to get_initial on post back since it has accomplished its job on GET. Is there a way to skip overriding get_initial on POST? I've failed trying to wrapping the override in:
if request.method == 'GET':
URL:
url(r'^lumber_load/(?P<pk>\d+)/addlog/$', views.LogDataCreate.as_view(), name='log-data-add'),
View:
class LogDataCreate(CreateView):
form_class = LogDataForm
model = LogData
# Set created_by to the current user.
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(LogDataCreate, self).form_valid(form)
# Set initial values of unit fields.
def get_initial(self):
return { 'lumberload': self.kwargs['lumberload_id'],'diameter_unit': '3', 'length_unit': '1' }
# Return to the load list when done creating a plot.
def get_success_url(self):
return reverse('geoapp:lumber_load_list')
Model:
class LogData(models.Model):
logdata_id = models.AutoField(primary_key=True)
lumberload = models.ForeignKey('LumberLoad', blank=True, null=True)
butt_diameter = models.DecimalField(null=True, max_digits=4, decimal_places=1, blank=True)
diameter_unit = models.ForeignKey('UnitLengthType', related_name='diameter_unit', null=True)
log_length = models.DecimalField(null=True, max_digits=3, decimal_places=1, blank=True)
length_unit = models.ForeignKey('UnitLengthType', related_name='length_unit', null=True)
speciestreetype = models.ForeignKey('SpeciesTreeType', blank=True, null=True)
recorded_date = models.DateField(blank=True, null=True)
created_by = models.ForeignKey(User)
class Meta:
db_table = 'log_data'
ordering = ["logdata_id"]
def __unicode__(self):
return unicode(self.logdata_id)
Try it this way:
def get_initial(self):
if self.request.method == 'GET':
return #initial data
else:
return {}