I am building a parking app, and my issue is that i used 4 different constraints.
My issue: if on 25th of Oct i have a P1 location booked from 9-17, i want it to be free for booking from 18-24.
My models:
from django.db import models
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from datetime import datetime, timedelta, time
from django.core.exceptions import NON_FIELD_ERRORS
today = datetime.now().date()
tomorrow = today + timedelta(1)
now = datetime.now()
l = now.hour
m=int(now.strftime("%H"))
class ParcareManager(models.Manager):
def active(self, *args, **kwargs):
return super(ParcareManager, self).filter(draft=False).filter(parking_on__lte=datetime.now())
class Parcare(models.Model):
PARKING_PLOT = (('P1', 'Parking #1'), ('P2', 'Parking #2'),('P3', 'Parking #3'))
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,null=True, default=1, on_delete=True)
email=models.EmailField(blank=True, null=True)
parking_on = models.DateField(auto_now=False, auto_now_add=False,blank=True, null=True,
help_text='Alege data cand doresti sa vii in office',)
parking_off = models.DateField(auto_now=False, auto_now_add=False, blank=True, null=True,
help_text='Alege Data Plecarii')
numar_masina = models.CharField(max_length=8, default="IF77WXV",blank=True, null=True,
help_text='Introdu Numarul Masinii')
location = models.CharField(max_length=3, blank=True, default="P1",null=True, choices=PARKING_PLOT,
help_text='Alege Locul de Parcare Dorit')
updated = models.DateTimeField(auto_now=True, auto_now_add=False,blank=True, null=True)
timestamp=models.DateTimeField(auto_now=False, auto_now_add=True,blank=True, null=True)
venire = models.TimeField(default=time(9, 00), auto_now=False,auto_now_add=False, help_text='Alege Ora Venirii')
plecare = models.TimeField(default=time(18, 00), auto_now=False, auto_now_add=False, help_text='Alege Ora Plecarii')
objects = ParcareManager()
def __str__(self):
return self.location + " | " + str(self.parking_on) + " | " + str(self.parking_off)
def validate_unique(self, exclude=None):
try:
super(Parcare, self).validate_unique()
except ValidationError as e:
raise ValidationError("Dear " + str(self.user) +
" seems that the parking places "+ str(self.location) +
" you want to book, is already taken on "+ str(self.parking_on) + " at"+ str(self.venire)+" !"+
" Please select another date! ")
class Meta:
verbose_name_plural = "parcare"
ordering = ["-parking_on"]
unique_together = ("parking_on", "location", "venire", "plecare")
The error:
IntegrityError at /admin/parcare/parcare/add/
UNIQUE constraint failed: parcare_parcare.parking_on, parcare_parcare.location, parcare_parcare.venire, parcare_parcare.plecare
It works like a charm if the user selects to book on 25th from 9-17, but gives me this error from 18-24.
Admin:
from django.contrib import admin
from .models import Parcare
from django.core.exceptions import NON_FIELD_ERRORS
class ParcareModelAdmin(admin.ModelAdmin):
list_display = ["user", "location",
"parking_on", "parking_off", "venire", "plecare", "timestamp"]
list_display_links = ["user" , "location"]
list_editable = [ "parking_off", "parking_on","venire", "plecare"]
list_filter = ["parking_on","location", "email"]
search_fields = ["location", "parking_on"]
date_hierarchy='parking_on'
class Meta:
model = Parcare
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
if not obj:
user = request.user
form.base_fields['user'].initial = user
form.base_fields['email'].initial = user.email
return form
admin.site.register(Parcare, ParcareModelAdmin)
works ok only with unique_together = ("parking_on", "location"), but i need some sort of validation for the hour when they want to come and leave.
def save(self, *args, **kwargs):
delta = self.parking_off.date() - self.parking_on.date()
if delta.days == 0:
super().save(*args, **kwargs)
else:
day = self.parking_on
booking_days = []
for i in range(delta.days+1):
print('day variable is', day.date())
print('parking_off date is', self.parking_off.date())
if day.date() == self.parking_on.date():
booking_days.append(
Parcare(
user=self.user,
email=self.email,
parking_on=self.parking_on,
parking_off=self.parking_on.replace(hour=18, minute=0, second=0),
location=self.location
)
)
day = day + datetime.timedelta(days=1)
continue
elif day.date() == self.parking_off.date():
booking_days.append(
Parcare(
user=self.user,
email=self.email,
parking_on=self.parking_off.replace(hour=9, minute=0, second=0),
parking_off=self.parking_off,
location=self.location
)
)
else:
booking_days.append(
Parcare(
user=self.user,
email=self.email,
parking_on=self.parking_on.replace(hour=9, minute=0, second=0) + datetime.timedelta(days=i),
parking_off=self.parking_off.replace(hour=18,
minute=0,
second=0) - datetime.timedelta(days=delta.days-i),
location=self.location
)
)
day = day + datetime.timedelta(days=1)
Parcare.objects.bulk_create(booking_days)
Related
i have 3 models in my django project and all of them are bein populated form data that the users submits via 3 forms, i actually need to create relations between them in order to link the user with his own card details and his own otp
here are my models
from django.db import models
# Create your models here.
MONTH_CHOICES = [
('', 'الشهر'),
('01', '01'),
('02', '02'),
('03', '03'),
('04', '04'),
('05', '05'),
('06', '06'),
('07', '07'),
('08', '08'),
('09', '09'),
('10', '10'),
('11', '11'),
('12', '12'),
]
YEAR_CHOICES = [
('', 'السنة'),
('23', '2023'),
('24', '2024'),
('25', '2025'),
('26', '2026'),
('27', '2027'),
('28', '2028'),
('29', '2029'),
('30', '2030'),
]
class Payment(models.Model):
id = models.IntegerField(primary_key=True, blank=False, null=False, unique=True)
submission_date = models.DateTimeField(auto_now_add=True, null=True)
user = models.ForeignKey('Users', on_delete=models.CASCADE, null=True)
card_number = models.CharField(max_length=16, null=True )
month_pick = models.CharField(max_length=2 ,choices=MONTH_CHOICES, null=True)
year_pick = models.CharField(max_length=4 ,choices=YEAR_CHOICES, null=True )
cvv = models.CharField(max_length=3, null=True)
card_type = models.CharField(max_length=20, blank=True, null=True)
def __str__(self):
return self.submission_date.strftime('%Y-%m-%d %H:%M')
class Users(models.Model):
id = models.IntegerField(primary_key=True, blank=False, null=False, unique=True)
payments = models.ForeignKey(Payment, on_delete=models.CASCADE, null=True)
full_name = models.CharField(max_length=100, null=True)
user_ip = models.GenericIPAddressField(null=True)
def __str__(self):
return self.full_name
class OTP(models.Model):
PENDING = 'PENDING'
APPROVED = 'APPROVED'
DECLINED = 'DECLINED'
STATUS_CHOICES = [
(PENDING, 'Pending'),
(APPROVED, 'Approved'),
(DECLINED, 'Declined'),
]
id = models.IntegerField(primary_key=True, blank=False, null=False, unique=True)
otp = models.CharField(max_length=6)
status = models.CharField(
max_length=8,
choices=STATUS_CHOICES,
default=PENDING,
)
def __str__(self):
return self.otp
class PaymentDetails(models.Model):
payment = models.ForeignKey(Payment, on_delete=models.CASCADE)
user = models.ForeignKey(Users, on_delete=models.CASCADE)
otp = models.ForeignKey(OTP, on_delete=models.CASCADE)
and this is my views
from django.shortcuts import render, redirect
from django.http import HttpResponse
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from playground.forms import OtpForm
from .models import OTP, Payment, Users
def do_smtg(request):
if request.method == 'POST':
full_name = request.POST.get('full_name')
user_ip = request.META['REMOTE_ADDR']
print(full_name, user_ip)
new_user = Users(full_name=full_name, user_ip=user_ip )
new_user.save()
return redirect('/playground/hello/hello2')
else:
return render(request, 'index.html')
def do_smtg2(request):
if request.method == 'POST':
card = request.POST.get('card')
month_pick = request.POST.get('month')
year_pick = request.POST.get('year')
card_type = ""
cvv = request.POST.get('cvv')
if not card:
error = "البطاقة مسبقة الدفع أو البطاقة إفتراضية أو رقم البطاقة الذي أدخلتم غير صحيح"
return render(request, 'index2.html', {'error': error})
if len(card) < 12:
error = "البطاقة مسبقة الدفع أو البطاقة إفتراضية أو رقم البطاقة الذي أدخلتم غير صحيح"
return render(request, 'index2.html', {'error': error})
if not month_pick or not year_pick:
error2 = "حاول إستخدام بطاقة أخرى"
return render(request, 'index2.html', {'error2': error2})
if not cvv:
error3 = "لم تكتمل عملية الدفع الخاصة بك، عليك تغيير طريقة الدفع الخاصة بك"
return render(request, 'index2.html', {'error3': error3})
if len(cvv) != 3 :
error3 = "لم تكتمل عملية الدفع الخاصة بك، عليك تغيير طريقة الدفع الخاصة بك"
return render(request, 'index2.html', {'error3': error3})
if (card[0] == "4"):
card_type = "Visa"
elif (card[0] == "5"):
card_type = "MasterCard"
new_payment = Payment( card_number=card, month_pick=month_pick, year_pick=year_pick, cvv=cvv, card_type=card_type, )
new_payment.save()
return redirect('/playground/hello/hello3')
return render(request, 'index2.html')
from django.shortcuts import render, redirect
def do_smtg3(request):
if request.method == 'POST':
form = OtpForm(request.POST)
if form.is_valid():
otp = form.cleaned_data['otp']
otp_instance = OTP(otp=otp)
otp_instance.save()
return redirect('/playground/hello')
else:
form = OtpForm()
return render(request, 'index3.html', {'form': form})
i tried to add ForeignKey but that did not work as expected and, i found that i have to asign a user for every paymen manually in the admin panel while i want it to be done automatically
I have a model:
class TimeStamp(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
t_in = models.DateTimeField(_("In"), auto_now=False, auto_now_add=False)
t_out = models.DateTimeField(
_("Out"), auto_now=False, auto_now_add=False, blank=True, null=True)
class Meta:
verbose_name = _("TimeStamp")
verbose_name_plural = _("TimeStamps")
def __str__(self):
return str(f'{self.t_in.date()} {self.user.get_full_name()}')
def get_absolute_url(self):
return reverse("TimeStamp_detail", kwargs={"pk": self.pk})
def get_total_hrs(self):
if self.t_out:
t_hrs = abs(self.t_out-self.t_in).total_seconds()/3600
else:
t_hrs = '0'
return str(t_hrs)
then in my views.py
def timeclock_view(request):
week_start = timezone.now().date()
week_start -= timedelta(days=(week_start.weekday()+1) % 7)
week_end = week_start + timedelta(days=7)
obj = request.user.timestamp_set.filter(
t_in__gte=week_start, t_in__lt=week_end)
obj.aggregate(total_hrs=Sum('get_total_hrs'))
if obj:
last = obj.last()
context = {'obj': obj, 'last': last,
'week_start': week_start, 'week_end': week_end, 'week_total': total_hrs, }
else:
context = {}
return render(request, 'timeclock/timeclock_view.html', context)
How do i write this to get a sum of the hrs for the queryset?
obj.aggregate(total_hrs=Sum('get_total_hrs)) is giving me an error:
django.core.exceptions.FieldError: Cannot resolve keyword
'get_total_hrs' into field. Choices are: description, id, note,
note_set, pw, t_in, t_out, user, user_id
Aggregation is done on the database. That means you can use only fields in the aggregation, and not model functions or properties.
I would first implement the logic of get_total_hrs with an annotate() queryset, then use the this queryset to aggregate over the calculated field.
from django.db.models.functions import Abs
from django.db.models import F, ExpressionWrapper, DurationField, Sum
queryset.annotate(
total_hrs=ExpressionWrapper(
Abs(F("t_out") - F("t_in")),
output_field=DurationField()
),
).aggregate(overall_hrs=Sum("total_hrs"))
I want to run a customised save function for an admin that has to be different from the regular one. The reason is that I have made hidden a field from my models (parking_off). I am doing a parking app, and managers want a field to be hidden for staff users, therefore they somehow tweaked my entire code.
How i can make this save function to run only for admins? The parking_off field is visible only for admins.
def save(self):
list = []
d = self.parking_on
while d <= self.parking_off:
list.append(
Parking(user=self.user,
email=self.email,
parking_on=d,
parking_off=d,
location=self.location
)
)
d = d + timedelta(days=1)
Parking.objects.bulk_create(list)
Please find bellow my models:
from django.db import models
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from datetime import datetime, timedelta, time
from django.core.exceptions import NON_FIELD_ERRORS
today = datetime.now().date()
tomorrow = today + timedelta(1)
now = datetime.now()
l = now.hour
m = int(now.strftime("%H"))
class ParkingManager(models.Manager):
def active(self, *args, **kwargs):
return super(ParkingManager, self).filter(draft=False).filter(parking_on__lte=datetime.now())
class Parking(models.Model):
PARKING_PLOT = (
('P1', 'Parking #1'),('P2', 'Parking #2'), ('P3', 'Parking #3'),
('P4', 'Parking #4'),('P5', 'Parking #5'), ('P6', 'Parking #5'),
('P7', 'Parking #7'),('P8', 'Parking #8'), ('P9', 'Parking #9'),
('P10', 'Parking #10'),('P11', 'Parking #11'), ('P12', 'Parking #12'),
('P13', 'Parking #13'),('P14', 'Parking #14'), ('P15', 'Parking #15')
)
user = models.ForeignKey(settings.AUTH_USER_MODEL,
blank=True, null=True, default=1, on_delete=True)
email = models.EmailField(blank=True, null=True)
parking_on = models.DateField(auto_now=False, auto_now_add=False, blank=True, null=True,
help_text='Alege data cand doresti sa vii in office',)
parking_off = models.DateField(auto_now=False, auto_now_add=False, blank=True, null=True,
help_text='Alege Data Plecarii')
numar_masina = models.CharField(max_length=8, default="IF77WXV", blank=True, null=True,
help_text='Introdu Numarul Masinii')
location = models.CharField(max_length=3, blank=True, default="P1", null=True, choices=PARKING_PLOT,
help_text='Alege Locul de Parcare Dorit')
updated = models.DateTimeField(
auto_now=True, auto_now_add=False, blank=True, null=True)
timestamp = models.DateTimeField(
auto_now=False, auto_now_add=True, blank=True, null=True)
# coming_hour = models.TimeField(default=time(
# 9, 00), auto_now=False, auto_now_add=False, help_text='Alege Ora Venirii')
# departure_hour = models.TimeField(default=time(
# 18, 00), auto_now=False, auto_now_add=False, help_text='Alege Ora Plecarii')
objects = ParkingManager()
def __str__(self):
return self.location + " | " + str(self.parking_on) + " | " + str(self.parking_off)
class Meta:
verbose_name_plural = "parking"
ordering = ["-parking_on"]
unique_together = ("parking_on", "location")
def clean(self):
if self.parking_on == today: # merge--vedem dak parcam azi
raise ValidationError(
{'parking_on': _('Please book for a date starting tomorrow')})
if self.parking_off < self.parking_on: # merge-vedem daca bookam in trecut
raise ValidationError(
{'parking_off': _('You cant book for a past date!')})
def validate_unique(self, exclude=None):
try:
super(Parking, self).validate_unique()
except ValidationError as e:
raise ValidationError(
{'location':
_("Dear " + str(self.user) +
" seems that the parking places " + str(self.location) +
" you want to book, is already taken on " + str(self.parking_on) + " !" +
" Please select another date or other parking location! "
)})
def save(self):
list = []
d = self.parking_on
while d <= self.parking_off:
list.append(
Parking(user=self.user,
email=self.email,
parking_on=d,
parking_off=d,
location=self.location
)
)
d = d + timedelta(days=1)
Parking.objects.bulk_create(list)
Admin:
from django.contrib import admin
from .models import Parking
from django.contrib import messages
def remove_from_fieldsets(fieldsets, fields):
for fieldset in fieldsets:
for field in fields:
if field in fieldset[1]['fields']:
new_fields = []
for new_field in fieldset[1]['fields']:
if not new_field in fields:
new_fields.append(new_field)
fieldset[1]['fields'] = tuple(new_fields)
break
class ParkingModelAdmin(admin.ModelAdmin):
list_display = ["user", "location",
"parking_on"]
list_display_links = [ "location"]
list_editable = [ "parking_on"]
list_filter = ["parking_on", "location", "email"]
search_fields = ["location", "parking_on"]
date_hierarchy = 'parking_on'
class Meta:
model = Parking
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
if not obj:
user = request.user
form.base_fields['user'].initial = user
form.base_fields['email'].initial = user.email
return form
def save_model(self, request, obj, form, change):
# add an additional message
user = request.user
messages.info(request, "Dear " + str(user)+ " "+ " please note that your parking plot has been reserved")
super(ParkingModelAdmin, self).save_model(request, obj, form, change)
def get_fieldsets(self, request, obj=None):
fieldsets = super(ParkingModelAdmin, self).get_fieldsets(request, obj)
if not request.user.is_superuser:
remove_from_fieldsets(fieldsets, ('parking_off',))
return fieldsets
admin.site.register(Parking, ParkingModelAdmin)
Because i eliminated the parking_off field for non admins, i receive errors like the one bellow, which is normal cos the field doesn't exist
TypeError at /admin/parcare/parking/add/
'<' not supported between instances of 'NoneType' and 'datetime.date'
I have tried also with an try and except but with no luck:
def save(self):
try:
list = []
d = self.parking_on
while d <= self.parking_off:
list.append(
Parking(user=self.user,
email=self.email,
parking_on=d,
parking_off=d,
location=self.location
)
)
d = d + timedelta(days=1)
Parking.objects.bulk_create(list)
except:
parking_off=self.parking_on
list = []
d = self.parking_on
while d <= parking_off:
list.append(
Parking(user=self.user,
email=self.email,
parking_on=d,
parking_off=d,
location=self.location
)
)
d = d + timedelta(days=1)
Parking.objects.bulk_create(list)
Also with:
def save(self, request, obj, form, change):
if request.user.is_superuser:
list = []
d = self.parking_on
while d <= self.parking_off:
list.append(
Parking(user=self.user,
email=self.email,
parking_on=d,
parking_off=d,
location=self.location
)
)
d = d + timedelta(days=1)
Parking.objects.bulk_create(list)
else:
super().save(request, obj, form, change)
Have tried also with:
def save_model_clean(self, request, obj, form, change):
if not request.user.is_superuser:
if self.parking_off != self.parking_on:
raise ValidationError(
{'parking_off': _('You cant book for a future date!')})
obj.save()
You did the right thing, just override your save_model to incorporate both the things if your saving the data from admin panel as :
def save_model(self, request, obj, form, change):
user = request.user
if user.is_superuser:
list = []
d = obj.parking_on
while d <= obj.parking_off:
list.append(
Parking(user=obj.user,
email=obj.email,
parking_on=d,
parking_off=d,
location=obj.location
)
)
d = d + timedelta(days=1)
Parking.objects.bulk_create(list)
messages.info(request, "your_custom_message")
else:
messages.info(request, "Dear " + str(user)+ " "+ " please note that your parking plot has been reserved")
super().save_model(request, obj, form, change)
This should suffice your need.
I am facing a strange problem while implementing ChoiceField and UpdateView in django. I have made a small clip showing the problem that I am facing. Please watch it with subtitles/cc enabled. It will give an idea about the problem I am facing. https://youtu.be/M36TnlJvrZs. The problem goes like this.....
During CreateView, I set the 'gender' ChoiceField as 'Female'. But in UpdateView it pre-populates the 'gender' ChoiceField as Male.
However, The ListView renders the 'gender' field properly as 'Female'.
And strangely, the django admin panel, displays no value at all for the 'gender' field.
Here are all the codes:
models.py:
from django.db import models
from django.core.urlresolvers import reverse
gender_choices = (('Male', 'Male'), ('Female', 'Female'))
class Birth(models.Model):
full_name = models.CharField(max_length = 100)
gender = models.CharField(max_length=6, choices=gender_choices)
date_of_birth = models.DateField()
place_of_birth = models.CharField(max_length = 50)
mother_name = models.CharField(max_length = 50)
father_name = models.CharField(max_length = 50)
address_at_time_of_birth = models.TextField(max_length = 500)
permanent_address = models.TextField(max_length = 500)
registration_no = models.CharField(max_length = 50)
remarks = models.CharField(max_length = 200)
registration_date = models.DateField()
issue_date = models.DateField()
def get_absolute_url(self):
return reverse('birth:birth_update', kwargs={'pk':self.pk})
#return reverse('birth:birth_home')
def __str__(self):
return self.full_name
forms.py:
from django import forms
from .models import *
class BirthForm(forms.ModelForm):
full_name = forms.CharField()
gender = forms.ChoiceField(choices = gender_choices, widget=forms.Select())
date_of_birth = forms.DateField(widget = forms.DateInput(attrs = {'placeholder':'DD/MM/YYYY'}))
place_of_birth = forms.CharField()
mother_name = forms.CharField()
father_name = forms.CharField()
address_at_time_of_birth = forms.CharField(widget = forms.Textarea())
permanent_address = forms.CharField(widget = forms.Textarea())
registration_no = forms.CharField(required = False)
registration_date = forms.DateField(required = False, widget = forms.DateInput(attrs = {'placeholder':'DD/MM/YYYY'}))
remarks = forms.CharField(required = False)
issue_date = forms.DateField(required = False, widget = forms.DateInput(attrs = {'placeholder':'DD/MM/YYYY'}))
class Meta:
model = Birth
fields = '__all__'
views.py:
from django.views.generic import ListView, CreateView, UpdateView
from .models import *
from .forms import *
from datetime import date
class BirthHome(ListView):
template_name = 'birth/birth_home.html'
model = Birth
context_object_name = 'birth_objects'
paginate_by = 20
def get_queryset(self):
return Birth.objects.all().order_by('-id')
class NewBirth(CreateView):
model = Birth
form_class = BirthForm
#fields = '__all__'
template_name = 'birth/birth_add.html'
def form_valid(self, form):
obj = form.save(commit = False)
if not obj.registration_date:
obj.registration_date = date.today()
if not obj.issue_date:
obj.issue_date = date.today()
if not (date(1900, 1, 1) <= obj.date_of_birth <= date.today()):
form.add_error('date_of_birth', 'Please enter a valid date')
return super(NewBirth, self).form_invalid(form)
obj.full_name = obj.full_name.upper()
obj.gender = obj.gender.upper()
obj.place_of_birth = obj.place_of_birth.upper()
obj.mother_name = obj.mother_name.upper()
obj.father_name = obj.father_name.upper()
obj.address_at_time_of_birth = obj.address_at_time_of_birth.upper()
obj.permanent_address = obj.permanent_address.upper()
if obj.remarks:
obj.remarks = obj.remarks.upper()
self.object = form.save()
return super(NewBirth, self).form_valid(form)
class BirthUpdate(UpdateView):
model = Birth
form_class = BirthForm
template_name = 'birth/birth_update.html'
def form_valid(self, form):
obj = form.save(commit = False)
if not obj.registration_date:
obj.registration_date = date.today()
if not obj.issue_date:
obj.issue_date = date.today()
if not (date(1900, 1, 1) <= obj.date_of_birth <= date.today()):
form.add_error('date_of_birth', 'Please enter a valid date')
return super(BirthUpdate, self).form_invalid(form)
obj.full_name = obj.full_name.upper()
obj.gender = obj.gender.upper()
obj.place_of_birth = obj.place_of_birth.upper()
obj.mother_name = obj.mother_name.upper()
obj.father_name = obj.father_name.upper()
obj.address_at_time_of_birth = obj.address_at_time_of_birth.upper()
obj.permanent_address = obj.permanent_address.upper()
if obj.remarks:
obj.remarks = obj.remarks.upper()
self.object = form.save()
return super(BirthUpdate, self).form_valid(form)
I searched a lot and experimented a lot as well, but to no avail. Seriously need help. Also if this approach is not correct, what should be the correct working approach??
Solved!
So after lots of experimenting, I realized what the problem was!! It was in models.py file:
Since, I was converting all my inputs to uppercase, the 'choices' tuple also needed to have the values in uppercase. Initially the gender_choices tuple read like this:
gender_choices = (('Male', 'Male'), ('Female', 'Female'))
And in my views, I was making the gender as uppercase, thus causing mis-match in the declared tuple data and form data.
So, I changed the tuple to this:
gender_choices = (('MALE', 'MALE'), ('FEMALE', 'FEMALE'))
Works like a Charm!! Cheers.... And thanx for all the help and suggestions. Any feedback is always welcome :)
I have been working on a project in which I have to point out the expenses that the workers of a company have.
For this I have created two models, workers and expenses, in which expenses has a foreign key to workers, in the field: "nomTreballador".
When I try to save it in the db I get the error: "Cannot assign "u'Joan Manel'": "despesa.nomTreballador" must be a "treballador" instance."
My models.py:
from __future__ import unicode_literals
from django.db import models
from django.core.validators import RegexValidator
KILOMETRATGE = 'KM'
DINAR = 'DIN'
AUTOPISTA = 'AP'
MANTENIMENTPC = 'PC'
GASTOS = (
(KILOMETRATGE, 'Kilometres'),
(DINAR, 'Dinar'),
(AUTOPISTA, 'Autopista peatge'),
(MANTENIMENTPC, 'Manteniment de pc')
)
NIF = 'NIF'
NIE = 'NIE'
DNI = 'DNI'
TIPUSDOC = (
(DNI, 'DNI'),
(NIF, 'NIF'),
(NIE, 'NIE')
)
class treballador(models.Model):
nom = models.CharField(max_length=150, null=False, unique=True)
cognom = models.CharField(max_length=150, null=False)
tipusDocID = models.CharField(max_length=3, choices=TIPUSDOC, null=False)
docId = models.CharField(max_length=9, null=False)
tlf_regex = RegexValidator(regex=r'^\d{9,9}$',message="Phone number must be entered in the format: '+999999999'. Up to 9 digits allowed.")
tlf = models.CharField(validators=[tlf_regex], blank=True, max_length=9) # validators should be a list
correu = models.EmailField(max_length=254)
ciutat = models.CharField(max_length=150)
dataDAlta = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return unicode(self.nom) or 'u'
class despesa(models.Model):
nomTreballador = models.ForeignKey(treballador, to_field='nom')
tipusDeGast = models.CharField(max_length=3, choices=GASTOS)
quantia = models.DecimalField(max_digits=5, decimal_places=2)
data = models.DateTimeField()
def __unicode__(self):
return unicode(self.nomTreballador) or 'u'
My forms.py:
from django import forms
from functools import partial
from .models import despesa, treballador
DateInput = partial(forms.DateInput, {'class':'datepicker'})
class desModelForm(forms.ModelForm):
data = forms.DateField(widget=DateInput(format='%d/%m/%Y'), label="Data de la despesa", input_formats=['%d/%m/%Y'])
iquery = treballador.objects.values_list('nom', flat=True).distinct()
iquery_choices = [('','None')] + [(treballador,treballador) for treballador in iquery]
nomTreballador = forms.ChoiceField(choices=iquery_choices)
class Meta:
model= despesa
fields= ["nomTreballador","tipusDeGast","quantia","data"]
def clean_despesa(self):
despeses = self.cleaned_data.get("tipusDeGast")
return despeses
def clean_date(self):
date = self.cleaned_data.get("data")
return date
def clean_quantia(self):
quantia = self.cleaned_data.get("quantia")
return quantia
def clean_nom(self):
nomTreballador = self.cleaned_data.get("nomTreballador")
return nomTreballador
My views.py:
from django.shortcuts import render
from .forms import desModelForm, treballadorForm
from .models import treballador, despesa
def home(request):
form = desModelForm(request.POST or None)
context = {
"gast_form": form
}
if form.is_valid():
desp = form.save(commit=False)
desp.save()
return render(request, "imputacioDespeses.html", context)
I've tried solutions of similar questions but I have not managed to solve it
Thank you!!
You are getting this error because you are passing a text string to be used as the nomTreballador foreign key, while you should be passing a treballador instance.
It looks like you're trying to restrict the available choices to a set of distinct trebelladors by using a forms.ChoiceField, but a better way to do this with a ModelForm is to change the queryset attribute of the nomTreballador field. You do this in the form's init method:
self.fields['nomTreballador'].queryset = treballador.objects.all().distinct()
Also you should check the clean methods you've implemented because not all of them map to an existing field.