I want to create an error message for following form:
class ExaminationCreateForm(forms.ModelForm):
class Meta:
model = Examination
fields = ['patient', 'number_of_examination', 'date_of_examination']
Models:
class Patient(models.Model):
patientID = models.CharField(max_length=200, unique=True, help_text='Insert PatientID')
birth_date = models.DateField(auto_now=False, auto_now_add=False, help_text='YYYY-MM-DD')
gender = models.CharField(max_length=200,choices=Gender_Choice, default='UNDEFINED')
class Examination(models.Model):
number_of_examination = models.IntegerField(choices=EXA_Choices)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
date_of_examination = models.DateField(auto_now=False, auto_now_add=False, help_text='YYYY-MM-DD')
Every Patient has 2 Examinations (number of examination = Choices 1 or 2) and the error message should be activated when the date of the second examination < date of the first examination. Something like this:
Solution: `
def clean_date_of_examination(self):
new_exam = self.cleaned_data.get('date_of_examination')
try:
old_exam = Examination.objects.get(patient=self.cleaned_data.get('patient'))
except Examination.DoesNotExist:
return new_exam
if old_exam:
if old_exam.date_of_examination > new_exam:
raise forms.ValidationError("Second examination should take place after first examination")
return new_exam`
def clean_date_of_examination(self):
new_exam = self.cleaned_data.get('date_of_examination')
old_exam = Examination.objects.get(patient = self.cleaned_data.get('Patient'))
if old_exam:
if old_exam.date_of_examination > new_exam.date_of_examination:
raise forms.ValidationError("Second examination should take place after first examination")
return data
def clean_date_of_examination(self):
# Where 'data' is used?
date_of_exam = self.cleaned_data['date_of_examination']
try:
pat1 = Patient.object.get(examination__number_of_examination=1, date_of_examination=date_of_exam)
except Patiens.DoesNotExist:
# Patient 1 with given query doesn't exist. Handle it!
try:
pat2 = Patient.object.get(examination__number_of_examination=2, date_of_examination=date_of_exam)
except Patiens.DoesNotExist:
# Patient 2 with given query doesn't exist. Handle it!
if pat2.date_of_examination < pat1.date_of_examination:
raise forms.ValidationError("Second examination should take place after first examination")`
return data`
Related
I set up my URL like this :
path('voucher/<str:voucher_id>', views.update_voucher),
My process
def update_voucher(request, voucher_id):
put = QueryDict(request.body)
try:
customer_id = put.get('customer_id')
except:
return HttpResponse("Missing parameters")
updateVoucher = Voucher.objects.filter(code = voucher_id)
Its a PUT call taking parameters from both body and url. (voucher_id from URL) and (customer_id from body)
.
I call this URL http://127.0.0.1:5448/voucher/NewVoucher
I got this error:
ValueError: Field 'id' expected a number but got 'NewVoucher'.
The below is my model:
here.
class Voucher(models.Model):
code = models.CharField(unique=True, max_length=255)
delivery_type = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True, null=True)
start_at = models.DateTimeField()
end_at = models.DateTimeField()
discount_type = models.CharField(max_length=255)
discount_amount = models.FloatField(blank=True, null=True)
P/S: I am a maintainer - cant change method function, and cant change the way this URL take parameters from both URL and body
You are not passing voucher_id as integers. instead you are passing code "NewVoucher" which is a string as per this error.
ValueError: Field 'id' expected a number but got 'NewVoucher'.
You have to pass id in integers so it would look something like this
http://127.0.0.1:5448/voucher/1
So far as i've understood you are looking for filter based on voucher code i,e "NewVoucher".
then Your method should be changed as,
def update_voucher(request, voucher_code, *args, **kwargs):
voucher = get_object_or_404(Voucher, code=voucher_code)
customer_id = request.data.get("customer_id") # im not sure where you are using this customer_id
if not customer_id:
raise HttpResponse("Missing parameters")
# updateVoucher = Voucher.objects.filter(code = voucher_id) no need of this line as voucher variable contains it
# urls
path('voucher/<str:voucher_code>', views.update_voucher),
I'm writing a football scoring app for a local league using the same schema as the NFL's gameday DB. I created a function that will eventually run on it's own updating each player's scores.
The problem comes when the function to create a new points record is run it duplicates the entry for each player, there's no error shown or anything, everything runs as expected except for the duplicate values.
here are my views.py:
def updatepoints(request):
actual = get_object_or_404(CurrentWeek, status='active')
week = actual.week
season = actual.season
ptsexist = Puntos.objects.filter(week=week, season=season)
if ptsexist:
pts = Player.objects.raw('''SELECT DISTINCT player.player_id,(SELECT (SELECT SUM(play_player.passing_yds))+(SELECT SUM(play_player.passing_tds))+(SELECT SUM(play_player.passing_twoptm))+(SELECT SUM(play_player.passing_int))+(SELECT SUM(play_player.rushing_yds))+(SELECT SUM(play_player.rushing_tds))+(SELECT SUM(play_player.rushing_twoptm))+(SELECT SUM(play_player.fumbles_lost))+(SELECT SUM(play_player.receiving_yds))+(SELECT SUM(play_player.receiving_tds))+(SELECT SUM(play_player.receiving_twoptm))+(SELECT SUM(play_player.receiving_rec))+(SELECT SUM(play_player.kicking_fgm))+(SELECT SUM(play_player.kicking_xpmade))+(SELECT SUM(play_player.fumbles_rec_tds))+(SELECT SUM(play_player.kicking_rec_tds))) AS total,id_puntos FROM player INNER JOIN play_player ON player.player_id = play_player.player_id INNER JOIN game ON play_player.gsis_id = game.gsis_id LEFT JOIN points ON player.player_id = points.player_id AND points.temporada = game.season_year AND "DraftFantasy_puntos".semana = game.week WHERE game.week = %s AND game.season_year = %s AND game.season_type != 'Warmup' AND game.season_type != 'Postseason' GROUP BY player.player_id,points.id_points''', [week, season])
for obj in pts:
obj.id = obj.player_id
obj.points = obj.total
obj.idpoints = obj.id_points
form = UpdatePointsForm(request.POST)
pointsf = form.save(commit=False)
pointsf.id_points = obj.idpoints
pointsf.player_id = obj.player_id
pointsf.temporada = season
pointsf.semana = week
pointsf.puntos_ppr = obj.total
pointsf.save()
return HttpResponseRedirect("/dashboard/")
else:
return HttpResponseRedirect("/savepoints/")
def savepoints(request):
actual = get_object_or_404(CurrentWeek, status='active')
week = actual.week
season = actual.season
ptsn = Player.objects.raw('''SELECT DISTINCT player.player_id,(SELECT (SELECT SUM(play_player.passing_yds))+(SELECT SUM(play_player.passing_tds))+(SELECT SUM(play_player.passing_twoptm))+(SELECT SUM(play_player.passing_int))+(SELECT SUM(play_player.rushing_yds))+(SELECT SUM(play_player.rushing_tds))+(SELECT SUM(play_player.rushing_twoptm))+(SELECT SUM(play_player.fumbles_lost))+(SELECT SUM(play_player.receiving_yds))+(SELECT SUM(play_player.receiving_tds))+(SELECT SUM(play_player.receiving_twoptm))+(SELECT SUM(play_player.receiving_rec))+(SELECT SUM(play_player.kicking_fgm))+(SELECT SUM(play_player.kicking_xpmade))+(SELECT SUM(play_player.fumbles_rec_tds))+(SELECT SUM(play_player.kicking_rec_tds))) AS total FROM player INNER JOIN play_player ON player.player_id = play_player.player_id INNER JOIN game ON play_player.gsis_id = game.gsis_id WHERE game.week = %s AND game.season_year = %s AND game.season_type != 'Warmup' AND game.season_type != 'Postseason' GROUP BY player.player_id''', [week, season])
for obj in ptsn:
obj.id = obj.player_id
obj.points = obj.total
formn = PointsForm(request.POST)
pointsfn = formn.save(commit=False)
pointsfn.player_id = obj.player_id
pointsfn.temporada = season
pointsfn.semana = week
pointsfn.points = obj.total
pointsfn.save()
return HttpResponseRedirect("/ligas/")
the forms.py:
class PointsForm(forms.ModelForm):
class Meta:
model = Points
exclude = ["player_id",
"season",
"week",
"puntos"]
class UpdatePointsForm(forms.ModelForm):
class Meta:
model = Points
exclude = ["id_points",
"player_id",
"season",
"week",
"points"]
and the models.py:
class Points(models.Model):
id_points = models.AutoField(primary_key=True, null=False, max_length=15)
player_id = models.CharField(max_length=100)
season = models.IntegerField(max_length=10)
week = models.IntegerField(max_length=10)
puntos = models.IntegerField(max_length=50)
class CurrentWeek(models.Model):
id_week = models.AutoField(primary_key=True, null=False, max_length=15)
week = models.IntegerField(max_length=10)
season = models.IntegerField(max_length=5)
status = models.CharField(max_length=50, default="done")
I'm really stumped so any help will be much appreciated.
I want to auto increament the invoice number which is 3 digits char and 4 digits number.
class Invoice:
invoice_no = models.CharField(max_length=500, null=True, blank=True, validators=[RegexValidator(regex='^[a-zA-Z0-9]*$',message='Invoice must be Alphanumeric',code='invalid_invoice number'),])
I register this model in backend. But now when i click on create invoice in admin the invoice should be auto filled. When i again click on create new invoice in admin, the invoice_number should be incremented by one and should be auto field.
Ex for Invoice number MAG0001, MAG0002, MAG0003 etc and this should be auto field in admin when i click on create new invoice.
Define a function to generate invoice number.
def increment_invoice_number():
last_invoice = Invoice.objects.all().order_by('id').last()
if not last_invoice:
return 'MAG0001'
invoice_no = last_invoice.invoice_no
invoice_int = int(invoice_no.split('MAG')[-1])
new_invoice_int = invoice_int + 1
new_invoice_no = 'MAG' + str(new_invoice_int)
return new_invoice_no
Now use this function as default value in your model filed.
invoice_no = models.CharField(max_length=500, default=increment_invoice_number, null=True, blank=True)
This is just an idea. Modify the function to match your preferred invoice number format.
In above arulmr answer just edit char field
def increment_invoice_number():
last_invoice = Invoice.objects.all().order_by('id').last()
if not last_invoice:
return 'MAG0001'
invoice_no = last_invoice.invoice_no
invoice_int = int(invoice_no.split('MAG')[-1])
width = 4
new_invoice_int = invoice_int + 1
formatted = (width - len(str(new_invoice_int))) * "0" + str(new_invoice_int)
new_invoice_no = 'MAG' + str(formatted)
return new_invoice_no
class Invoice(models.Model):
invoice_no = models.CharField(max_length = 500, default = increment_invoice_number, null = True, blank = True)
This will work fine.
def invoiceIncrement():
get_last_invoice_number
incremente_last_invoice_number
return next_invoice_number
class Invoice:
invoice_no = models.CharField(max_length=500, null=True, blank=True,
validators=[RegexValidator(regex='^[a-zA-Z0-9]*$',
message='Invoice must be Alphanumeric',code='invalid_invoice number'),],
default=invoiceIncrement)
Try this: there are some obvious issues:
if more than one person adds an invoice at the same time, could have collision
will need to make an extra db call each time you create a new invoice.
Also: you may want to just consider using either an auto_increment or UUID.
Maybe this code can help
def increment_invoice_number():
last_invoice = Invoice.objects.all().order_by('id').last()
if not last_invoice:
return 'MAG0001'
invoice_no = last_invoice.invoice_no
new_invoice_no = str(int(invoice_no[4:]) + 1)
new_invoice_no = invoice_no[0:-(len(new_invoice_no))] + new_invoice_no
return new_invoice_no
def invoice_number_gen():
last_invoice = Invoice.objects.all().order_by('id').last()
last_invoice_number = last_invoice.invoice_no
#invoice number format is 'customer_name_short + number' eg: CS003
last_invoice_digits =int(last_invoice_number[2:])
#comment: slicing CS003 to get the number 003 and converting to int.
last_invoice_initials = last_invoice_number[:2]
new_invoice_digits = last_invoice_digits + 1
new_invoice_number = last_invoice_initials + str(new_invoice_digits)
return (new_invoice_number)
I wrote some instructions in order to extract data from my database.
I have two values; a city name and a keyword, which are attributes of Address and Museum:
class Museum(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
address = models.ForeignKey(Address)
description = models.CharField(max_length=200)
class Address(models.Model):
id = models.AutoField(primary_key=True)
streetAddress = models.CharField(max_length=200)
city = models.CharField(max_length=200)
Now I am receiving two optional parameters: a city and and a keyword. I want to filter out museums according to such city (exact match) AND such keyword (partial match in name OR description)
This is what I ended up writing:
if city is not None and keyword is None:
city_data = Address.objects.all().filter(city=city)
museum_list = Museum.objects.all().filter(address__in=city_data)
elif city is None and keyword is not None:
museum_list = Museum.objects.all().filter(
Q(name__contains=keyword) | Q(description__contains=keyword)
)
elif city is not None and keyword is not None:
city_data = Address.objects.all().filter(city=city)
museum_list = Museum.objects.all().filter(
Q(address__in=city_data) & (
Q(name__contains = keyword) | Q(description__contains=keyword)
)
)
else:
museum_list = Museum.objects.all()
I don't like this code, because I am accounting for all possible combinations. How can I use Django filtering to improve such code to something like:
results = Museum.objects.all()
if city not null
results = results.filterByAddress_City
if keyword not null
results = results.filterByKeywordLikeNameOrLikeDescription
Thanks.
Queries are composable, so you can pretty much do exactly what you state in your pseudocode.
results = Museum.objects.all()
if city:
results = results.filter(address__city=city)
if keyword:
results = results.filter(Q(name__contains = keyword) | Q(description__contains = keyword))
I'm trying to get a few million of items from a model, and parsing them. However, somehow it spends a lot of time trying to get the data saved.
These are the current models that I have:
class mapt(models.Model):
s = models.IntegerField(primary_key=True)
name = models.CharField(max_length=2000)
def __unicode__(self):
return str(self.s)
class datt(models.Model):
s = models.IntegerField(primary_key=True)
setid = models.IntegerField()
var = models.IntegerField()
val = models.IntegerField()
def __unicode(self):
return str(self.s)
class sett(models.Model):
setid = models.IntegerField(primary_key=True)
block = models.IntegerField()
username = models.IntegerField()
ts = models.IntegerField()
def __unicode__(self):
return str(self.setid)
class data_parsed(models.Model):
setid = models.IntegerField(max_length=2000, primary_key=True)
block = models.CharField(max_length=2000)
username = models.CharField(max_length=2000)
data = models.CharField(max_length=200000)
time = models.IntegerField()
def __unicode__(self):
return str(self.setid)
The s parameter for the datt model should actually act as a foreign key to mapt's s parameter. Furthermore, sett's setid field should act as a foreign key to setid's setid.
Lastly, data_parsed's setid is a foreign key to sett's models.
The algorithm is currently written this way:
def database_rebuild(start_data_parsed):
listSetID = []
#Part 1
for items in sett.objects.filter(setid__gte=start_data_parsed):
listSetID.append(items.setid)
uniqueSetID = listSetID
#Part 2
for items in uniqueSetID:
try:
SetID = items
settObject = sett.objects.get(setid=SetID)
UserName = mapt.objects.get(pk=settObject.username).name
TS = pk=settObject.ts
BlockName = mapt.objects.get(pk=settObject.block).name
DataPairs_1 = []
DataPairs_2 = []
DataPairs_1_Data = []
DataPairs_2_Data = []
for data in datt.objects.filter(setid__exact=SetID):
DataPairs_1.append(data.var)
DataPairs_2.append(data.val)
for Data in DataPairs_1:
DataPairs_1_Data.append(mapt.objects.get(pk=Data).name)
for Data in DataPairs_2:
DataPairs_2_Data.append(mapt.objects.get(pk=Data).name)
assert (len(DataPairs_1) == len(DataPairs_2)), "Length not equal"
#Part 3
Serialize = []
for idx, val in enumerate(DataPairs_1_Data):
Serialize.append(str(DataPairs_1_Data[idx]) + ":PARSEABLE:" + str(DataPairs_2_Data[idx]) + ":PARSEABLENEXT:")
Serialize_Text = ""
for Data in Serialize:
Serialize_Text += Data
Data = Serialize_Text
p = data_parsed(SetID, BlockName, UserName, Data, TS)
p.save()
except AssertionError, e:
print "Error:" + str(e.args)
print "Possibly DataPairs does not have equal length"
except Exception as e:
print "Error:" + str(sys.exc_info()[0])
print "Stack:" + str(e.args)
Basically, what it does is that:
Finds all sett objects that is greater than a number
Gets the UserName, TS, and BlockName, then get all the fields in datt field that correspond to a var and val field maps to the mapt 's' field. Var and Val is basically NAME_OF_FIELD:VALUE type of relationship.
Serialize all the var and val parameters so that I could get all the parameters from var and val that is spread across the mapt table in a row in data_parsed.
The current solution does everything I would like to, however, on a Intel Core i5-4300U CPU # 1.90Ghz, it parses around 15000 rows of data daily on a celery periodic worker. I have around 3355566 rows of data at my sett table, and it will take around ~23 days to parse them all.
Is there a way to speed up the process?
============================Updated============================
New Models:
class mapt(models.Model):
s = models.IntegerField(primary_key=True)
name = models.CharField(max_length=2000)
def __unicode__(self):
return str(self.s)
class sett(models.Model):
setid = models.IntegerField(primary_key=True)
block = models.ForeignKey(mapt, related_name='sett_block')
username = models.ForeignKey(mapt, related_name='sett_username')
ts = models.IntegerField()
def __unicode__(self):
return str(self.setid)
# class sett(models.Model):
# setid = models.IntegerField(primary_key=True)
# block = models.IntegerField()
# username = models.IntegerField()
# ts = models.IntegerField()
# def __unicode__(self):
# return str(self.setid)
class datt(models.Model):
s = models.IntegerField(primary_key=True)
setid = models.ForeignKey(sett, related_name='datt_setid')
var = models.ForeignKey(mapt, related_name='datt_var')
val = models.ForeignKey(mapt, related_name='datt_val')
def __unicode(self):
return str(self.s)
# class datt(models.Model):
# s = models.IntegerField(primary_key=True)
# setid = models.IntegerField()
# var = models.IntegerField()
# val = models.IntegerField()
# def __unicode(self):
# return str(self.s)
class data_parsed(models.Model):
setid = models.ForeignKey(sett, related_name='data_parsed_setid', primary_key=True)
block = models.CharField(max_length=2000)
username = models.CharField(max_length=2000)
data = models.CharField(max_length=2000000)
time = models.IntegerField()
def __unicode__(self):
return str(self.setid)
New Parsing:
def database_rebuild(start_data_parsed, end_data_parsed):
for items in sett.objects.filter(setid__gte=start_data_parsed, setid__lte=end_data_parsed):
try:
UserName = mapt.objects.get(pk=items.username_id).name
TS = pk=items.ts
BlockName = mapt.objects.get(pk=items.block_id).name
DataPairs_1 = []
DataPairs_2 = []
DataPairs_1_Data = []
DataPairs_2_Data = []
for data in datt.objects.filter(setid_id__exact=items.setid):
DataPairs_1.append(data.var_id)
DataPairs_2.append(data.val_id)
for Data in DataPairs_1:
DataPairs_1_Data.append(mapt.objects.get(pk=Data).name)
for Data in DataPairs_2:
DataPairs_2_Data.append(mapt.objects.get(pk=Data).name)
assert (len(DataPairs_1) == len(DataPairs_2)), "Length not equal"
Serialize = []
for idx, val in enumerate(DataPairs_1_Data):
Serialize.append(str(DataPairs_1_Data[idx]) + ":PARSEABLE:" + str(DataPairs_2_Data[idx]))
Data = ":PARSEABLENEXT:".join(Serialize)
p = data_parsed(items.setid, BlockName, UserName, Data, TS)
p.save()
except AssertionError, e:
print "Error:" + str(e.args)
print "Possibly DataPairs does not have equal length"
except Exception as e:
print "Error:" + str(sys.exc_info()[0])
print "Stack:" + str(e.args)
Defining lists by appending repeadedly is very slow. Use list comprehensions or even just the list() constructor.
In python you should not join a list of strings using for loops and +=, you should use join().
But that is not the primary bottleneck here. You have a lot of objects.get()s which each takes a database roundtrip. If you didn't have milions of rows in the mapt table, you should probably just make a dictionary mapping mapt primary keys to mapt objects.
Had you defined your foreign keys as foreign keys the django orm could help you do much of this in like five queries in total. That is, instead of SomeModel.objects.get(id=some_instance.some_fk_id) you can do some_instance.some_fk (which will only hit the databse the first time you do it for each instance). You can then even get rid of the foreign key query if some_instance had been initialized as some_instance = SomeOtherModel.objects.select_related('some_fk').get(id=id_of_some_instance).
Perhaps changing the models without changing the database will work.