Updating cleaned_data based on form input? - django

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

Related

How to pass a calendar in a generic form with a request?

Can you please tell me how to transfer the calendar to the form with a get request, with clicking on the days of the week and transferring to the form? There is a filtering for all fields at the same time now, only with the date of trouble (
Approximately how such a calendar can be transmitted? Thanks in advance.
class Traveller(models.Model):
title = models.CharField(max_length=30,default='',null=False)
origin = models.ForeignKey(Origin,on_delete=models.CASCADE,max_length=100,verbose_name= 'Источник',default='')
destination = models.ForeignKey(Destination,on_delete=models.CASCADE, verbose_name="Местонахождение",default='')
transport = models.ForeignKey(Transport,on_delete=models.CASCADE, verbose_name="Транспорт",default='')
passengers = models.ForeignKey(Passengers,on_delete=models.CASCADE, verbose_name="Пассажиры",default='')
url = models.SlugField(max_length=130, unique=True)
def __str__(self):
return self.title
class Meta:
verbose_name = 'Путешествие'
verbose_name_plural = 'Путешествие'
def get_absolute_url(self):
return reverse("traveller", kwargs={"url": self.url})
`views:
class FullTraveller:
def get_origin(self):
return Origin.objects.all()
def get_destination(self):
return Destination.objects.all()
def get_transport(self):
return Transport.objects.all()
def get_passengers(self):
return Passengers.objects.all()
class TravellerView(FullTraveller, ListView):
template_name = 'index.html'
model = Traveller
queryset = Traveller.objects.all()
paginate_by = 1
class FilterTravelView(FullTraveller,ListView):
def get_queryset(self):
if self.request.GET.getlist("origin") and self.request.GET.getlist("destination") and self.request.GET.getlist(
"transport") and self.request.GET.getlist("destination"):
queryset = Traveller.objects.filter(origin__in=self.request.GET.getlist("origin"),
destination__in=self.request.GET.getlist("destination"),
transport__in=self.request.GET.getlist("transport"),
passengers__in=self.request.GET.getlist("passengers"))
else:
queryset = Traveller.objects.filter(Q(origin__in=self.request.GET.getlist("origin")) | Q(
destination__in=self.request.GET.getlist("destination")) | Q(
transport__in=self.request.GET.getlist("transport"))| Q(
passengers__in=self.request.GET.getlist("passengers")))
return queryset
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context["origin"] = ''.join([f"origin={x}&" for x in self.request.GET.getlist("origin")])
context["destination"] = ''.join([f"destination={x}&" for x in self.request.GET.getlist("destination")])
context["transport"] = ''.join([f"transport={x}&" for x in self.request.GET.getlist("transport")])
context["passengers"] = ''.join([f"passengers={x}&" for x in self.request.GET.getlist("passengers")])
return context
forrm in template
`
```
```
I tried various options with widgets, but it didn’t work to insert them into the template

pass data from models.py to views.py and show it to user

I want to give users ten point each time they fill out one Survey , so i have this code above and now how to add the 10 point to self user after he fill out one
models.py :
class User(AbstractUser):
user_pic = models.ImageField(upload_to='img/',default="",null=True, blank=True)
coins = models.IntegerField(default=10)
def get_image(self):
if self.user_pic and hasattr(self.user_pic, 'url'):
return self.user_pic.url
else:
return '/path/to/default/image'
def give_coins(user, count):
user.coins = F('coins') + count
user.save(update_fields=('coins',))
user.refresh_from_db(fields=('coins',))
class Survey(models.Model):
name = models.CharField(max_length=200)
published_on = models.DateTimeField('Published DateTime')
def __str__(self):
return self.name
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.published_on <= now
was_published_recently.admin_order_field = 'published_on'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
class Participant(models.Model):
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
participation_datetime = models.DateTimeField('Participation DateTime')
def __str__(self):
return "Participant "+str(self.participation_datetime)
class Question(models.Model):
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
question_text = models.CharField(max_length=200)
created_on = models.DateTimeField('Creation DateTime')
def __str__(self):
return self.question_text
views.py :
#register.inclusion_tag('survey/survey_details.html', takes_context=True)
def survey_details(context, survey_id):
survey = Survey.objects.get(id=survey_id)
return {'survey': survey}
#require_http_methods(["POST"])
def submit_survey(request):
form_data = request.POST.copy()
form_items = list(form_data.items())
print("form_items", form_items)
form_items.pop(0) # the first element is the csrf token. Therefore omit it.
survey = None
for item in form_items:
# Here in 'choice/3', '3' is '<choice_id>'.
choice_str, choice_id = item
choice_id = int(choice_id.split('/')[1])
choice = Choice.objects.get(id=choice_id)
if survey is None:
survey = choice.question.survey
choice.votes = choice.votes + 1
choice.save()
if survey is not None:
participant = Participant(survey=survey, participation_datetime=timezone.now())
participant.save()
return redirect('/submit_success/')
so what i must to do if i want to add 10 point to user after he complete one survey
If submit_survey is a call that requires authentication the user will be present on the request request.user.
Add the coins by adding request.user.give_coins(count=10) to the submit_query method.
you have 2 way
work with event driven tools(maybe hard but principled)
set give_coin befor participant.save() on submit_survey
anyway I din't notice, coin is on your absUser model but your Participant has nothing to do with it or relations

Having trouble to get the total price of the basket's items (Django)

So I'm trying to get the total amount of the basket but having trouble doing so.
Am I calling it wrong? I'm new so...
Html(here is the way i calling it):
<p>Total:{{basket.get_basket_total}}</p>
models:
class Products(models.Model):
products_name = models.CharField(max_length=30)
pub_date = models.DateTimeField(auto_now=True)
price = models.DecimalField(max_digits=5, decimal_places=2)
note = models.CharField(max_length=200)
inventory = models.IntegerField(default=1)
product_pic = models.ImageField(upload_to ='images/', default='images/broken/broken.png')
def __str__(self):
if (self.inventory<=0):
return self.products_name + ' (Out of Stock)'
return self.products_name
class Basket(models.Model):
products = models.ForeignKey(Products, on_delete=models.SET_NULL, null=True, blank=True)
pub_date = models.DateTimeField(auto_now=True)
amount = models.IntegerField(default=1)
def __str__(self):
return str(self.products)
#property
def get_total(self):
total = self.products.price * self.amount
return total
#property
def get_basket_total(self):
basket_items = self.basket_set.all()
total = sum([item.get_total for item in basket_items])
return total
View(and it doesnt let me to add this view bec it is mostly code so i am writing this):
View(and it doesnt let me to add this view bec it is mostly code so i am writing this):
View(and it doesnt let me to add this view bec it is mostly code so i am writing this):
def products(request):
products_list = Products.objects.order_by('-pub_date')
context = {'products_list': products_list}
return render(request, 'productapp/products.html', context)
def basket(request):
basket_list = Basket.objects.order_by('-pub_date')
context = {'basket_list': basket_list}
return render(request, 'productapp/basket.html', context)
def home(request):
products_list = Products.objects.order_by('-pub_date')
context = {'products_list': products_list}
return render(request, 'pages/index.html', context)
def image(request):
images = Products()
variables = RequestContext(request,{'product_pic':images})
return render(None,'image.html',variables)
def addtobasket(request, id):
if request.method == 'POST':
product = Products.objects.get(id=id)
basket, created = Basket.objects.get_or_create(products=product)
basket.amount=request.POST['amount']
basket.save()
return HttpResponseRedirect(reverse("productapp:basket"))
def removefrombasket(request, id):
if request.method == 'POST':
product = Basket.objects.get(id=id)
product.delete()
return HttpResponseRedirect(reverse("productapp:basket"))
You better do:
sum(basket.values_list('price', flat=True)
So you get all inside the query
With values_list you get all the fields of the item in it. Flat = True makes it a list.
So you get something like:
[15,18,22,31]
and you sum it all

Django Form and two forms with foreign key

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.

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)