Django Form and two forms with foreign key - django

I have these models:
class Customers(models.Model):
ID = models.AutoField(primary_key=True)
...
def __str__(self):
return str(self.ID)
class CustomerAddresses(models.Model):
ID = models.AutoField(primary_key=True)
...
CustomerNoID = models.ForeignKey('Customers', on_delete=models.CASCADE)
def __str__(self):
return str(self.ID)
and my view:
def add_customer_view(request):
user_id = request.user.id
last_customerno = Customers.objects.filter(UserID=user_id).order_by('CustomerNo').last()
if not last_customerno:
# return '0001'
last_customerno = 1000
if last_customerno == 1000:
customerno_int = 1000
else:
customerno_int = last_customerno.CustomerNo + 1
# if this is a POST request we need to process the form data
if request.method == 'POST':
customer_form = CustomerForm(request.user.id, request.POST)
customer_address_form = CustomerAddressesForm(request.user.id, request.POST)
if customer_form.is_valid():
new_customer = customer_form.save(commit=False)
new_customer.save()
if customer_address_form.is_valid():
new_address = customer_address_form.save(commit=False)
new_address.CustomerNoID = new_customer
new_address.save()
return HttpResponseRedirect('/backend/kunder/')
else:
customer_form = CustomerForm(request.user.id, initial={'CustomerNo': customerno_int})
customer_address_form = CustomerAddressesForm(request.user.id)
return render(
request,
'backend/add_customer.html',
{
'title': 'WestcoastShop - Backend',
'customer_form': customer_form,
'customer_address_form': customer_address_form
}
)
But just the Customer is creating not the address I think the form is missing the CustomerNoID and I think I got the right way but after 6 hrs I give up maybe here is a smart guy how finds the error.
regards.

I changed the form and added the second one in a modal so I can save the two models nondependent.

Related

Updating cleaned_data based on form input?

I am trying to adjust the cleaned_data that I get from the modelform to save certain values to the model based on the users input. These inputs can vary greatly, please see the model below along with the forms and views.
Should I call the model methods into the model form or should I do all the calculations in the modelForm itself. The figures can change depending on the contract selected and the start date selected as it will count the number of days and base it on this price for the contract, however if it is a half day then it will just divide the number by 2.
I am still new to Django but trying to figure out where all this information should be put, I am certainly clueless on this and trying to learn Django myself through real lifelike applications instead so appreciate your help.
Model
class AdminData(models.Model):
year1 = models.IntegerField()
year3 = models.IntegerField()
year1_fortnight = models.IntegerField()
year3_fortnight = models.IntegerField()
#property
def fortnight_dayrate_year1(self):
return self.year1_fortnight / weeksinyear / 5
#property
def fortnight_dayrate_year3(self):
return self.year3_fortnight / weeksinyear / 5
#property
def day_rate_year1(self):
return self.year1 / weeksinyear / 5
#property
def day_rate_year3(self):
return self.year3 / weeksinyear / 5
class Price(models.Model):
year_choice = Choices('1-Year Weekly', '3-Year Weekly','1-Year Fortnightly', '3-Year Fortnightly')
day_choice = Choices('Full Day', 'Half Day')
name = models.CharField(max_length=100)
contract = StatusField(choices_name='year_choice')
time_daily = StatusField(choices_name='day_choice')
start_date = models.DateField(default=datetime.now)
end_date = models.DateField(default=datetime(2021,3,31))
weeksinyear = 52
hours = 6.5
epoch_year = date.today().year
year_start = date(epoch_year, 1, 4)
year_end = date(epoch_year, 3, 31)
#property
def day_count(self):
return year_end - self.start_date
# #property
# def price_year1_weekly(self):
# if self.contract == self.year_choice[0]
# return AdminData.year1 * self.day_count
def __str__(self):
return self.name
Forms.py
class PriceForm(forms.ModelForm):
class Meta:
model = Price
fields = ['name', 'contract','time_daily','start_date']
Views.py
def price_detail(request):
if request.method == 'POST':
form = PriceForm(request.POST)
if form.is_valid():
price_instance = form.cleaned_data
form.save()
return render(request,'confirmation.html',{'form_data': price_instance})
else:
form = PriceForm()
return render(request, 'main.html', {'form': form})
For at the time of transaction calculations, the views.py is a good place for this, ie. a purchase, where the price is agreed upon at that moment and will never change.
If the business logic requires that the data updates the transaction, then the model is better.
views.py
def price_detail(request):
form = PriceForm(request.POST or None)
if form.is_valid():
price_instance = form.save() // this returns a saved instance
... do calculations here ...
price_instance.calculated_field = 1 + 1 // example calculations
price_instance.confirmed = False // consider adding a confirmed boolean, to not allow users to alter the data in the next step.
price_instance.save()
return render(request, 'confirmation.html', {'price_instance': price_instance})
else:
return render(request, 'main.html', {'form': form})
An example of doing the calculations every time the model is saved by overriding the model's save() method.
models.py
class Price(models.Model):
year_choice = Choices('1-Year Weekly', '3-Year Weekly','1-Year Fortnightly', '3-Year Fortnightly')
day_choice = Choices('Full Day', 'Half Day')
name = models.CharField(max_length=100)
contract = StatusField(choices_name='year_choice')
time_daily = StatusField(choices_name='day_choice')
start_date = models.DateField(default=datetime.now)
end_date = models.DateField(default=datetime(2021,3,31))
weeksinyear = 52
hours = 6.5
epoch_year = date.today().year
year_start = date(epoch_year, 1, 4)
year_end = date(epoch_year, 3, 31)
#property
def day_count(self):
return year_end - self.start_date
def save(self, *args, **kwargs):
... do calculations here ...
self.calculated_field = 1 + 1 // calculations
super().save(*args, **kwargs)
def __str__(self):
return self.name

How to set initial value in the form

Hey guys how can i set initial value in my form field, let say the user click "BidForm" in the search form, i want the BidForm value will be the value of ProjectName in the other form...
here's my code in my search views
def search_views(request):
project_list = ProjectNameInviToBid.objects.all()
query = request.GET.get('query')
if query:
project_list = project_list.filter(ProjectName__icontains=query)
context = {
'project_list': project_list
}
return render(request, 'content/search_views.html', context)
and my other views
def project_name_details(request, sid):
majordetails = ProjectNameInviToBid.objects.get(id=sid)
if request.method == 'POST':
form = invitoBidForm(request.POST, request.FILES)
form.fields['ProjectName'].initial = majordetails
if form.is_valid():
form.save()
messages.success(request, 'File has been Uploaded')
else:
form = invitoBidForm()
args = {
'majordetails': majordetails,
'form': form
}
return render(request,'content/invitoBid/bacadmininvitoBid.html', args)
my form.py
class invitoBidForm(ModelForm):
class Meta:
model = InviToBid
fields = ('ProjectName','NameOfFile', 'Contract_No', 'Bid_Opening',
'Pre_Bid_Conference', 'Non_Refundable_Bidder_Fee',
'Delivery_Period',
'Pdf_fileinvi',)
and my models.py
class ProjectNameInviToBid(models.Model):
ProjectName = models.CharField(max_length=255, verbose_name='Project Name', null=True)
DateCreated = models.DateField(auto_now=True)
def __str__(self):
return self.ProjectName
class InviToBid(models.Model):
today = date.today()
ProjectName = models.ForeignKey('ProjectNameInviToBid', on_delete=models.CASCADE)
NameOfFile = models.CharField(max_length=255, verbose_name='Name of File')
Contract_No = models.IntegerField(verbose_name='Contract No')
def __str__(self):
return self.NameOfFile
First, I shall praise your documentation. Most people fail to provide the important code.
You can add something like this to your code here that will do what you require.
An example from my own code
if request.method == 'GET' and request.user.is_authenticated:
study = Study.objects.get(pk=studyID)
form = ContactForm(initial={'from_email': request.user.email, 'subject': "Study: " + study.name ,'message': study_message.format(request.user.get_short_name(), request.user.get_full_name())})
How you should change your code
Change your code in your other views from this:
else:
form = invitoBidForm()
to
else:
form = invitoBidForm(initial={'ProjectName': <wherever your project name comes from>})

Django adding data form multiple forms of one model to database

I have one model Measurement, two forms MeassurementSystolicPressureForm and MeassurementDiastolicPressureForm. I want to make a view that allows user to add both of them to the database. Each has fields: username, measurement_date, value, measurement_type. When I fill forms on my webpage two records are added to the db, each has a good username and measurement_type, but measurement_date and value are the same for both records. Can you help me spotting what I'm doing wrong?
Here is my code:
models.py
class Measurement(models.Model):
value = models.IntegerField()
measurement_type = models.CharField(max_length=6, default='measurement', blank=True)
username = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
measurement_date = models.DateTimeField(default=datetime.now, editable=True)
forms.py
class MeassurementSystolicPressureForm(ModelForm):
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
class MeassurementDiastolicPressureForm(ModelForm):
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
views.py
def new_measurement(request):
if request.method == 'POST':
form_SP = MeassurementSystolicPressureForm(request.POST or None)
form_DP = MeassurementDiastolicPressureForm(request.POST or None)
if form_CS.is_valid() or form_CR.is_valid():
temp_S = form_SP.save(commit=False)
temp_S.username = request.user
temp_S.measurement_type = 'syspres'
temp_S.save()
temp_D = form_DP.save(commit=False)
temp_D.username = request.user
temp_D.measurement_type = 'diapres'
temp_D.save()
return redirect('/')
else:
form_SP = MeassurementSystolicPressureForm()
form_DP = MeassurementDiastolicPressureForm()
args = {'form_SP': form_SP, 'form_DP': form_DP}
return render(request, 'measurements.html', args)
If for example I submit data for:
Systolic Pressure:
value: 120
date: 2019-01-15 16:15:32
Diastolic Pressure:
value: 80
date: 2019-01-15 15:00:00`
In my database I have two records:
username: Julka, measurement_type:
syspres, value: 80, date: 2019-01-15 15:00:00
username: Julka, measurement_type: diapres, value: 80, date: 2019-01-15 15:00:00
I have no idea what to do.
In an HttpRequest object, the GET and POST attributes are instances of django.http.QueryDict. This type alone cannot determine which form was submitted. Your forms have the same fields, so then one form is valid, other form valid too. That's why you have measurement_date and value are the same for both records. To solve this problem, you can add additional hidden fields to your forms and look at them from which form was sent. Some like this:
class MeassurementSystolicPressureForm(ModelForm):
flag_Systolic = forms.IntegerField()
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
def __init__(self, *args, **kwargs):
super(MeassurementSystolicPressureForm, self).__init__(*args, **kwargs)
self.fields['flag_Systolic'].widget = forms.HiddenInput()
class MeassurementDiastolicPressureForm(ModelForm):
flag_Diastolic = forms.IntegerField()
class Meta:
model = Measurement
fields = ['value', 'measurement_date']
def __init__(self, *args, **kwargs):
super(MeassurementDiastolicPressureForm, self).__init__(*args, **kwargs)
self.fields['flag_Diastolic'].widget = forms.HiddenInput()
and in your views:
def new_measurement(request):
if request.method == 'POST':
if 'flag_Systolic' in request.POST:
form_SP = MeassurementSystolicPressureForm(request.POST)
if form_SP.is_valid():
temp_S = form_SP.save(commit=False)
temp_S.username = request.user
temp_S.measurement_type = 'syspres'
temp_S.save()
return redirect('/')
elif 'flag_Diastolic' in request.POST:
form_DP = MeassurementDiastolicPressureForm(request.POST)
if form_DP.is_valid():
temp_D = form_DP.save(commit=False)
temp_D.username = request.user
temp_D.measurement_type = 'diapres'
temp_D.save()
return redirect('/')
else:
form_SP = MeassurementSystolicPressureForm()
form_DP = MeassurementDiastolicPressureForm()
args = {'form_SP': form_SP, 'form_DP': form_DP}
return render(request, 'measurements.html', args)
I know maybe it is too late but it might be helpful for other people facing the same problem.
One easier solution would be creating the object in the View and passing it to both forms:
from .models import Measurement
def new_measurement(request):
user=request.user #the authenticated user
if request.method == 'POST':
measurement=Measurement(username=user)
form_SP = MeassurementSystolicPressureForm(request.POST or None, instance=measurement)
form_DP = MeassurementDiastolicPressureForm(request.POST or None, instance=measurement)
if form_CS.is_valid() or form_CR.is_valid():
form_CS.save()
form_CR.save()
return redirect('/')
else:
form_SP = MeassurementSystolicPressureForm()
form_DP = MeassurementDiastolicPressureForm()
args = {'form_SP': form_SP, 'form_DP': form_DP}
return render(request, 'measurements.html', args)

How to instantiate a field of a formset to pre-populate?

My views allows me now to see if I have two questions, it shows me 2 forms. I wish I could now instantiate my 2 forms with one question each. So that the user no longer has simply answer the question without selecting ...
My views. py :
def access(request, instance):
replies = Reply.objects.all()
pages = Page.objects.all()
numPages = Page.objects.get(pk=instance)
questions = Question.objects.filter(page=instance)
length_questions = len(questions)
logged_user = get_logged_user_from_request(request)
ReplyFormSet = modelformset_factory(model=Reply, form=ReplyForm, extra=length_questions, can_delete=True)
formset = ReplyFormSet(request.POST, queryset=Reply.objects.none())
if request.method == 'POST':
formset = ReplyFormSet(request.POST, queryset=Reply.objects.none())
if formset.is_valid():
new_instances = formset.save(commit=False)
for new_instance in new_instances:
new_instance.user = logged_user
new_instance.save()
return HttpResponseRedirect('/baseVisite/')
else:
messages.add_message(request, messages.INFO, 'Le formulaire est incorrecte !')
return render_to_response('polls/error.html', context_instance=RequestContext(request))
else:
formset = ReplyFormSet(queryset=Reply.objects.none())
return render_to_response('polls/access.html', {
'formset': formset,
'questions':questions,
'logged_user':logged_user,
'numPages' : numPages
})
my models.py :
class Page(models.Model):
title = models.CharField(max_length=30)
def __str__(self):
return self.title
class Question(models.Model):
label = models.CharField(max_length=30)
page = models.ManyToManyField(Page)
def __str__(self):
return self.label
class Reply(models.Model):
question = models.ForeignKey(Question)
user = models.ForeignKey(Personne)
answer = models.CharField(max_length=30)
creationDate = models.DateTimeField(default=django.utils.timezone.now)
def __str__(self):
return str(self.answer)
and my forms.py :
class ReplyForm(forms.ModelForm):
class Meta:
model = Reply
exclude = ('user','creationDate')
I would like to pre-populate fields "questions" with this filter --> Question.objects.filter(page=instance) Is it possible to put a filter like this?
You can use the queryset argument
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#changing-the-queryset

Django queryset calling only objects belonging to User

I'm unable to figure out how to only call a queryset of items that belong to a specific User in the django forms.
dropoffs/models.py
class DropoffItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
dropoff = models.ForeignKey('Dropoff', null=True, blank=True)
product = models.ForeignKey(Product)
location = models.CharField(max_length=120, choices=LOCATION_CHOICES, default="Customer")
def __str__(self):
return str('%s' + " " + "(" + '%s' + ")") %(self.product.title, self.product.sku)
def sku(self):
return self.product.sku
def title(self):
return self.product.title
def dropoff_id(self):
return str(self.dropoff.id)
forms.py
class AddPickupItemForm(forms.ModelForm):
dropoffitem = forms.ModelChoiceField(queryset=DropoffItem.objects.none())
class Meta:
model = PickupItem
# fields = ["product", "quantity"]
fields = ['dropoffitem']
def __init__(self, user, *args, **kwargs):
# self.request = kwargs.pop("request")
the_user = kwargs.pop('user', None)
super(AddPickupItemForm, self).__init__(*args, **kwargs)
if the_user is not None:
self.fields["dropoffitem"].queryset = DropoffItem.objects.filter(user=the_user)
views.py
def add_item_to_pickup_order(request):
request.session.set_expiry(120000)
try:
user = request.user
the_id = request.session['pickup_id']
pickup = Pickup.objects.get(id=the_id)
except:
user = request.user
new_pickup_order = Pickup(user=user)
new_pickup_order.save()
request.session['pickup_id'] = new_pickup_order.id
the_id = new_pickup_order.id
pickup = Pickup.objects.get(id=the_id)
try:
dropoffitem = DropoffItem.objects.filter(user=user)
except DropoffItem.DoesNotExist:
pass
except:
pass
form = AddPickupItemForm(request.POST, user=request.user)
if request.method == "POST":
dropoffitem_id = int(request.POST['dropoffitem'])
pickup_item = PickupItem.objects.create(pickup=pickup, dropoffitem_id=dropoffitem_id)
pickup_item.save()
return HttpResponseRedirect('%s'%(reverse('add_item_to_pickup_order')))
context = {
"pickup": pickup,
"form": form,
}
return render(request, 'pickups/create_pickup_order.html', context)
With the modifications to init, I'm getting a TypeError of: init() got multiple values for keyword argument 'user'.
Could that be because of how I'm requesting a 'session'?
class AddPickupItemForm(ModelForm):
def __init__(self,*args,**kwargs)
the_user = kwargs.pop('user',None)
super(AddPickupItemForm, self).__init__(*args,**kwargs)
if the_user is not None:
self.fields['dropoffitem'].queryset = DropOffItem.objects.filter(user=the_user)
In other words, pass your user to the form when instantiating, if you need to.