I am working on Django 4.0.2 in python 3.10.2
I've read How to convert a models.IntegerField() to an integer(the poster actually need copy-constructor function).And I've searched for Google.
But it doesn't help.
what I want to do is:
#In app/models.py
class Foo:
a1 = models.IntergeField()
a2 = models.IntergeField()
#....
#many else
b1 = convertToInt(a1) * 3 + convertToInt(a2) *4 + convertToInt(a7) #calc by needing
b2 = convertToInt(a2) * 2 + convertToInt(a3) + convertToInt(a5) #calc by needing
#....
#many else
#b(b is price actually) will be used in somewhere else.Its type need be int for programmer-friendly using
any advice?
P.S. English is not my first language.Please forgive my syntax mistakes.
Edit 1:
if just a1 * 3, I will receive
TypeError: unsupported operand type(s) for *: 'IntegerField' and 'int'
And I'd like to explain why the solution in the above attached link is not work
the first answer use:
class Foo(models):
nombre_etudiant = models.IntergeField()
place_disponible =models.IntegerField(blank=True,null=True)
def __init__(self,*args,**kwargs):
super(Foo, self).__init__(*args, **kwargs)
if self.place_disponible is None:
self.place_disponible = self.nombre_etudiant
which I still can't mutiply the num by n. The code just do copying.I still can't get the value in int type.
the 2nd solution
class MyModel(models):
nombre_etudiant = models.IntergeField()
place_disponible =models.IntegerField()
def save(self, *args, **kwargs):
if not self.place_disponible:
self.place_disponible = int(nombre_etudiant)
super(Subject, self).save(*args, **kwargs)
self.place_disponible = int(nombre_etudiant) this will catch excepetion like TypeError: int() argument must be a string, a bytes-like object or a real number, not 'IntegerField'
Since you indicated in the comments that you don't need to store the derived attributes, I propose the following solution. Here the attributes are calculated every time and you can use them as you would use a1 and a2 attributes.
class Foo(models.Model):
a1 = models.IntegerField()
a2 = models.IntegerField()
#property
def b1(self):
return self.a1*3 + self.a2*4 # + ...
#property
def b2(self):
return self.a2*3 + self.a3 # + ...
Related
I am currently working on a small RPG in Pygame to get used to object oriented coding.
When looking into how to auto-update a property I came across the following:
class P:
def __init__(self,x):
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
I tried applying it to my code but I get the following error:
File "weapons.py", line 13, in __init__
self.name = '{} {}'.format(ammo, self.raw_name)
TypeError: name() takes exactly 3 arguments (2 given)
I understand what the error is but I don't get how to solve it since I need both the raw_name and the ammo attributes to auto-update my Arrow instance's name.
My class is as such:
class Projectile(Item):
def __init__(self, name, value, image, x, y, speed, dmg, dmg_modif, ammo):
super(Projectile, self).__init__(name, value, image, x, y)
self.dest = (self.rect[0],self.rect[1])
self.speed = speed
self.dmg_modif = dmg_modif
self.dmg = dmg
self.orientation = 0
self.ammo = ammo
#property
def name(self):
return self.___name
#name.setter
def name(self, raw_name, ammo):
if '{} {}'.format(raw_name,ammo) != self.___name:
self.___name = '{} {}'.format(raw_name,ammo)
The child class which returns the error is:
class Arrow(Projectile):
def __init__(self, ammo): #name, value, image, x, y, dmg
self.raw_name = 'Arrows'
self.name = '{} {}'.format(ammo, self.raw_name)
self.value = 5
self.image = variables.quiver_img
self.speed = 4
self.dmg = 2
self.dmg_modif = 1
super(Arrow, self).__init__(self.name, self.value, self.image, 200, 150, self.speed, self.dmg, self.dmg_modif, ammo)
And the parent classes are, Item and MySprite:
class Item(MySprite):
def __init__(self, name, value, image, x, y):
# Call the parent class (Sprite) constructor
super(Item, self).__init__(image, x, y)
self.name = name
self.value = value
self.inv_pos = -1
and
class MySprite(pygame.sprite.Sprite):
def __init__(self,image,x,y):
# Call the parent class (Sprite) constructor
super(MySprite, self).__init__()
self.image = image
self.rect = self.image.get_rect().move(x, y) #initial placement
self.top_cp = (self.rect[0]+self.rect[2]/2,self.rect[1])
self.bot_cp = (self.top_cp[0],self.rect[1]+self.rect[3])
self.left_cp = (self.rect[0],self.rect[1]+self.rect[3]/2)
self.right_cp = (self.left_cp[0]+self.rect[2],self.left_cp[1])
self.center = self.rect.center
self.pos = self.rect.topleft
self.blit_order = 1
self.level = variables.current_level #Level(1)#level to which sprite belongs
Any help would be welcome !
Please provide a minimal example next time.
Your code looks a little complicated. OK, the first problem is that you can't pass multiple arguments to a setter. You can either pass a tuple or just use a traditional setter method def set_name(self, name, ammo):.
Another problem is that you use the ___name attribute before it has been set, for example in the second line of the Arrows __init__ method.
Private attributes should have one underscore not three (that's just a convention to warn other programmers). If you have two or more underscores than the name gets mangled.
Also, it looks to me like you change the name in the setter only if the new name is equal to the old name (kinda pointless ;)). What do you actually want to do there? Maybe you don't need properties at all.
Here's a fixed (minimal) version of your code:
import pygame
class MySprite(pygame.sprite.Sprite):
def __init__(self):
super(MySprite, self).__init__()
class Item(MySprite):
def __init__(self, name):
super(Item, self).__init__()
self.name = name
class Projectile(Item):
def __init__(self, name):
super(Projectile, self).__init__(name)
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name + ' foo'
class Arrow(Projectile):
def __init__(self):
super(Arrow, self).__init__(name='Arrows')
arrow = Arrow()
print(arrow.name)
arrow.name = 'New name'
print(arrow.name)
So I eventually managed to solve my problem:
class Projectile(object):
def __init__(self, raw_name, ammo):
self.raw_name = raw_name
self.name = self.raw_name
self.ammo = ammo
#property
def ammo(self):
return self._ammo
#ammo.setter
def ammo(self, ammo):
self.name = str(ammo) + self.raw_name
self._ammo = ammo
class Arrow(Projectile):
def __init__(self):
self.raw_name = ' Arrows'
self.name = self.raw_name
super(Arrow, self).__init__(self.raw_name, ammo
= 10)
arrow = Arrow()
print arrow.ammo
print arrow.name
arrow.ammo = 15
print arrow.ammo
print arrow.name
gives:
>>>10
>>>10 Arrows
>>>15
>>>15 Arrows
How do I change the code so that it would return a is a square with side:5 and area:25 ?? when I call print a?
class Square():
def __init__(self, length):
self.length = length
def area(self):
return self.length ** 2
def __str__(self): #this is the part I don't know how to write
return "is a square with side:%s and area:%s." % (self.length, self.area())
a = Square(5)
print a
I guess you want to get the name of the variable that you asign with your class, right??
I don't know how to do that or is that is posible (or usefull in any way) because you can have have multiples variables pointing to the same object
for example in this
a=SomeObject()
b=a
c=a
d=c
and in this case how you will know which one you are using if all of them point to the same object?
A alternative is give your class a extra paremetrer with the name that you wish for you instance
class Square():
def __init__(self, length,name=""):
self.length = length
self.name = name
def area(self):
return self.length ** 2
def __str__(self): #this is the part I don't know how to write
return "%s is a square with side:%s and area:%s." % (self.name, self.length, self.area())
a = Square(5,'MySquare')
print a # MySquare is a square with side:5 and area:25.
I have this example:
class MyModel(models.Model):
# Some fields...
price = models.FloatField()
def calculate(self, number):
return self.price * number
In the views:
def whatever(request, any_number):
m = MyModel.objects.all()
c = m.calculate(any_number)
# More code...
It's a really easy example because I want to do something similar, so how can I do this?
Thank you!
You need to do it in a for loop, since m is an array of objects:
for item in m:
result = item.calculate(any_number)
# do some stuff with the result
How can I interpret booleans (or '') as integers 0 or 1? so totals could be 0, 1 or 2, depending on the values of uno and dos.
class foo(models.Model)
uno = models.BooleanField()
dos = models.BooleanField()
total = models.PositiveSmallIntegerField(blank=True, default=int(0))
def save(self, *args, **kwargs):
# HUMDINGER....
self.total = int(self.uno) + int(self.dos)
super(Survey, self).save(*args, **kwargs) # Call the "real" save() method.
This is the error it is throwing for that line...
invalid literal for int() with base 10: ''
I'm surprised that your BooleanFields have the empty string as their value. Regardless, since booleans evaluate to 0 and 1 in a numeric context, you can just do:
self.total = bool(self.uno) + bool(self.dos)
A common occurrence I have with one particular project is that it requires the user to enter dimensions (for width/depth/height) in Feet and Inches. Calculations are needed to be performed on that dimension, so I've been working on a custom field type that takes in a dimension in Feet/Inches (eg. 1'-10") and saves it to the database as a decimal number using a regex to parse the input. The field displays to the end-user as feet-inches at all times (with the eventual goal of writing a
method to be able to optionally display in metric, and interact with measure.py, and geodjango stuff). What I have so far is definitely not DRY, but aside from that, I'm having trouble with validation at the form level. The custom model field itself works properly (from what I've seen), and I've written a form field clean method which should work to validate the field. My question is how to hook that form field back into my model form to work for all the width/depth/height fields.
I'm thinking maybe an override of the init on the modelform (a la self.fields['depth']...) , but I'm not quite sure where to go from here...
DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$')
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$')
class FtInField(models.Field):
__metaclass__ = models.SubfieldBase
empty_strings_allowed = False
def db_type(self):
return 'double'
def get_internal_type(self):
return "FtInField"
def to_python(self,value):
if value is u'' or value is None:
return None
if isinstance(value, float):
m = FTDCML_PATTERN.match(str(value))
if m is None:
raise Exception('Must be an integer or decimal number')
feet = int(m.group('feet'))
dec_inch = float(m.group('dec_inch') or 0)
inch = dec_inch * 12
return "%d\'-%.0f\"" % (feet,inch)
return value
def get_db_prep_value(self,value):
if value is u'' or value is None:
return None
m = FTIN_PATTERN.match(value)
if m is None:
raise Exception('Must be in X\'-Y" Format')
feet = int(m.group('feet'))
inch = int(m.group('inch') or 0)
return (feet + (inch/float(12)))
class FtInField(forms.Field):
def clean(self,value):
super(FtInField, self).clean(value)
if value is u'' or value is None:
raise forms.ValidationError('Enter a dimension in X\'-Y" format')
m = FTIN_PATTERN.match(value)
if m is None:
raise forms.ValidationError('Must be in X\'-Y" Format')
feet = int(m.group('feet'))
inch = int(m.group('inch') or 0)
value = '%d\'-%.0f"' % (feet,inch)
return value
class ProductClass(models.Model):
productname = models.CharField('Product Name', max_length=60,blank=True)
depth = FtInField('Depth (Feet/Inches)')
width = FtInField('Width (Feet/Inches)')
height = FtInField('Height (Feet/Inches)')
class ProductClassForm(forms.ModelForm):
depth = FtInField()
width = FtInField()
height = FtInField()
class Meta:
model = ProductClass
class ProductClassAdmin(admin.ModelAdmin):
form = ProductClassForm
Thank you, thank you to both of you. This is what I came up with (based on both of your advise). I'll work on defining a data type to make it better in terms of repetition, but in the meantime, this works...(I was so close, yet so far away...) You guys are amazing. Thanks.
DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$')
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$')
class FtInFormField(forms.Field):
def clean(self,value):
super(FtInFormField, self).clean(value)
if value is u'' or value is None:
raise forms.ValidationError('Enter a dimension in X\'-Y" format')
m = FTIN_PATTERN.match(value)
if m is None:
raise forms.ValidationError('Must be in X\'-Y" Format')
feet = int(m.group('feet'))
inch = int(m.group('inch') or 0)
value = '%d\'-%.0f"' % (feet,inch)
return value
class FtInField(models.Field):
__metaclass__ = models.SubfieldBase
empty_strings_allowed = False
def db_type(self):
return 'double'
def get_internal_type(self):
return "FtInField"
def to_python(self,value):
if value is u'' or value is None:
return None
if isinstance(value, float):
m = FTDCML_PATTERN.match(str(value))
if m is None:
raise Exception('Must be an integer or decimal number')
feet = int(m.group('feet'))
dec_inch = float(m.group('dec_inch') or 0)
inch = dec_inch * 12
return "%d\'-%.0f\"" % (feet,inch)
return value
def get_db_prep_value(self,value):
if value is u'' or value is None:
return None
m = FTIN_PATTERN.match(value)
if m is None:
raise Exception('Must be in X\'-Y" Format')
feet = int(m.group('feet'))
inch = int(m.group('inch') or 0)
return (feet + (inch/float(12)))
def formfield(self, **kwargs):
defaults = {'form_class': FtInFormField}
defaults.update(kwargs)
return super(FtInField,self).formfield(**defaults)
class ProductClass(models.Model):
productname = models.CharField('Product Name', max_length=60,blank=True)
depth = FtInField('Depth (Feet/Inches)')
width = FtInField('Width (Feet/Inches)')
height = FtInField('Height (Feet/Inches)')
class ProductClassForm(forms.ModelForm):
class Meta:
model = ProductClass
class ProductClassAdmin(admin.ModelAdmin):
form = ProductClassForm
To avoid duplication you should probably implement a data type class that handles the parsing of feets and inches for you, it should greatly simplify the other code.
Then you should create a model field and form field, keeping in mind that these are two COMPLETELY SEPARATE components. (which you more or less have already done, but this is just for completeness)
Now, if I'm reading the question right, you want to set the default form field for your model field. To facilitate this you want to implement the formfield() function on your model field class. Ref: the django docs