I am trying to update a user "karma points" whenever a user posts something. For this, i first created a new model called Myuser that allows for points property:
class Myuser(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
points=models.IntegerField(default=1)
And then in my view.py post_new() function, I tried to update the score:
u=User.objects.get(username=request.user.username)
u.myuser.points=u.myuser.points+5
u.save()
but then i notice that rather than update the points field, it just saves a new instance with the same user id but updated score. I thought .save() is supposed to update exisiting copy.
This is what i did for object initiation
u=User.objects.get(username=request.user.username)
Myuser.objects.create(user_id=u.id, points=1)
Edit: I think the problem might be model initiation. When I initiate an instance and check
u=User.objects.get(username='barkthinks') #a registered username
Myuser.objects.create(user_id=u.id, points=10)
<Myuser: Myuser object (6052d3844fbcaa988e993c30)>
When I do:
Myuser.objects.all()
I will get this result
QuerySet [<Myuser: Myuser object (None)>
when I do .save(), sometimes I keep bumping into this error:
TypeError: Field 'id' expected a number but got ObjectId('6052d1054fbcaa988e993c2b').
Get the Unique Myuser instance and update the model instead
u=User.objects.get(username=request.user.username)
myuser = Myuser.objects.get(user=u)
myuser.points += 5
myuser.save()
to update any instance of a model,
variable = Models.objects.filter(conditions).update(attribute_to_update = update_value)
get the instance of the model using filter and condition, then use the .update to update values
models.py :
class Myuser(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
points=models.IntegerField(default=1)
views.py :
u=User.objects.get(username='barkthinks')
new_user_instance = Myuser.objects.create(user = u , points=10)
And then in the view.py post_new() function,
my_user = MyUser.objects.get(user__id = request.user.id)
temp = my_user.points
updated_instance = Myuser.objects.get(User__id = request.user.id).update(points = temp + 10)
try at first check if there is Myuser instance if not create new one, but if there is Myuser class instance for that user, then update that instance by doing this code.
u=User.objects.get(username='barkthinks')
try:
myuser_instance = Myuser.objects.get(user=u)
myuser_instance.points += 5
myuser_instance.save()
except ObjectDoesNotExist:
Myuser.objects.create(user=u, points=10)
Related
I am relatively new to Django and have been kinda struggling.
These are my three models below:
class Site(models.Model):
siteID = models.CharField(max_length=255, primary_key=True)
class EndDevice(models.Model):
class Meta:
unique_together = ("edevID", "siteID")
edevID = models.CharField(max_length=255)
siteID = models.ForeignKey(Site, on_delete=models.CASCADE)
deviceCategory = models.BigIntegerField()
class ThirdCombi(models.Model):
siteID = models.OneToOneField(Site, on_delete=models.CASCADE, primary_key=True)
endDevice = models.TextField()
I am trying to make a table where one siteID displays all the edevID, which is the third model here. This does work using the following serializers.py
class CombiSerializer(serializers.ModelSerializer):
class Meta:
model = ThirdCombi
fields = ("siteID", "endDevice")
def serialize(devices):
d_list = []
fields = ['edevID', 'siteID', 'deviceCategory']
for device in devices:
d_list.append(model_to_dict(device, fields=fields))
return d_list
And the views.py as follow:
class CombiView(generics.RetrieveUpdateDestroyAPIView):
queryset = ThirdCombi.objects.all()
serializer_class = CombiSerializer
def get(self, request, *args, **kwargs):
try:
s1 = Site.objects.get(siteID=kwargs["pk"])
devices = EndDevice.objects.filter(siteID=s1)
a_site, created = ThirdCombi.objects.get_or_create(siteID=s1, endDevice=CombiSerializer.serialize(devices))
return Response(CombiSerializer(a_site).data)
except Site.DoesNotExist:
return Response(
data={
"message": "Site with id: {} does not exist".format(kwargs["pk"])},
status=status.HTTP_404_NOT_FOUND)
But once there is an update in EndDevice and I reload the page it gives me an integrity error and if I put an exception to integrity error, I cannot see the changes made in EndDevice reflected in ThirdCombi. I know why there is an integrity error because the siteID already exists and it tries to make a new one. I am not sure how to clear the old one in order to avoid the integrity error.
Any help will be appreciated in order to update the third table. Thanks.
In Short: Use update_or_create instead of get_or_create.
ThirdCombi.objects.update_or_create(siteID=s1, defaults={"endDevice":CombiSerializer.serialize(devices)})
Go to bottom for full updated code.
I know why there is an integrity error because the siteID already exists and it tries to make a new one.
You are right.
get_or_create: creates a new object if it doesn't find one with the passed parameters.
OneToOneField: If you have a model Site and another model ThirdCombi with a OneToOneField on Site, it means that ThirdCombi can only have utmost one object per Site
The problem is you are trying to create a new ThirdCombi with every get request.
Please observe:
Initially, there is a Site s1 with 2 devices.
s1 = Site.objects.get(siteID=kwargs["pk"])
devices = EndDevice.objects.filter(siteID=s1) #2 devices
a_site, created = ThirdCombi.objects.get_or_create(siteID=s1, endDevice=CombiSerializer.serialize(devices)) #2 devices serialized "d1, d2"
Now, get_or_create creates a new ThirdCombi object for s1, since there is no ThirdCombi object for s1 initially. Let the created object be third_combi1.
But once there is an update in EndDevice and I reload the page
See, you have updated the EndDevice. Now again observe:
We already have Site: s1, EndDevices: d1, d2 and ThirdCombi: third_combi1 for s1.
We cannot have another third_combi2 for s1.
Since you updated EndDevices, let the current updated EndDevices be: d1, d2, d3
s1 = Site.objects.get(siteID=kwargs["pk"])
devices = EndDevice.objects.filter(siteID=s1) #3 devices
a_site, created = ThirdCombi.objects.get_or_create(siteID=s1, endDevice=CombiSerializer.serialize(devices)) #2 devices serialized "d1, d2, d3"
The problem here is get_or_create doesn't find an object with "d1, d2, d3". Hence it tries to create another third_combi2 for 's1' with d1, d2, d3. Hence the integrity error.
Instead, use update_or_create.
update_or_create: update if an object with the given parameters exist, else create.
Your final code should be:
s1 = Site.objects.get(siteID=kwargs["pk"])
devices = EndDevice.objects.filter(siteID=s1) #2 devices
a_site, created = ThirdCombi.objects.update_or_create(siteID=s1, defaults={"endDevice":CombiSerializer.serialize(devices)})
Here, if there is a ThirdCombi object with siteId=s1, then update its endDevice field with the provided ones. Else create a new ThirdCombi object with the given data.
class UserProfile(models.Model):
user = models.OneToOneField(User)
how_many_new_notifications = models.IntegerField(null=True,blank=True,default=0)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
In views.py function which is 100% called and whom is present
whom.profile.how_many_new_notifications += 1
whom.save()
Whatever, how_many_new_notifications is still equal zero and not incremented , despite everything else is correct
Also tried something like this:
if whom.profile.how_many_new_notifications == None:
whom.profile.how_many_new_notifications = 1
else:
varible_number_of_notifications = int( whom.profile.how_many_new_notifications)
whom.profile.how_many_new_notifications = varible_number_of_notifications + 1
Get no errors in log, is there any reason why this code wouldn't work, or should I search for issues in other places?
User.profile is a property that gets a new copy of the profile each time it is used.
So when you do
user.profile.how_many_notifications += 1
user.profile.save()
Each line uses its own copy of the profile, the two Python objects are unrelated.
So you need to do
profile = user.profile
profile.how_many_notifications += 1
profile.save()
But using a profile property like that is a bit odd -- you have a OneToOneField, and a related property is already automatically defined as the lower case name of your class. So
user.userprofile.how_many_new_notifications += 1
user.userprofile.save()
Should also work. If you want to change the name userprofile, use related_name:
user = models.OneToOneField(User, related_name='profile')
And then it works with user.profile.
Hello to all I have been developing module under Odoo 8. I have a class "hrEmployee" with "_inherit=hr.employee" , now in my hrEmployee there is a One2many field having relation with another model "hr.employee.visa". I want to get the field values of the "hrEmployee" with onchange function defined on the field of "hr.employee.visa". Like when I change field value of "hrEmployee", I can get the field value entered on the current form (hrEmployee). How am I able to achieve this in Odoo v8? My Python code is shown below:
class hrEmployee(models.Model):
_inherit = "hr.employee"
diwan_no = fields.Char('Diwan No', size=30, help='Diwan Number')
zeo_number = fields.Char('ZEO Number',size=30, help='ZEO Number')
visas_ids = fields.One2many('hr.employee.visas', 'employee_id', 'Visas')
class hr_employee_visas(models.Model):
_name='hr.employee.visas'
employee_id = fields.Many2one("hr.employee.visas", "Employee" )
#api.onchange('visas_number')
#api.depends( 'visas_number')
def _visa_num(self):
cr=self._cr
uid=self._uid
ids=self._ids
for id in ids:
obj1=self.pool.get('hr.employee').browse(cr,uid,id,context=None)
print obj1.name_related
visas_sponsor = fields.Char('Sponsor')
visas_states = fields.Selection([('apply','Apply'),('active','Active'),('expire','Expire'),('cancel','Cancelled')], string='State' )
visas_number = fields.Char('Visa No', help='Visa Number')
I tried to use self.pool.get browse but it gives me "False" . Plz guide me or point me my mistake. Hopes for suggestion
Try following,
class hr_employee_visas(models.Model):
_name='hr.employee.visas'
employee_id = fields.Many2one("hr.employee", "Employee" )
#api.onchange('visas_number')
#api.depends( 'visas_number')
def _visa_num(self):
for obj in self:
print obj.employee_id.name
Here is the mistake
employee_id = fields.Many2one("hr.employee.visas", "Employee" )
You need to set hr.employee here.
No need to write both of the decorators together, in case of any changes into the visas_number field this method will be called, you can use any of the single decorator for this.
What is wrong with my code?
class Group(ImageModel):
title = models.CharField(verbose_name = "Title", max_length=7)
photos = models.ManyToManyField('Photo', related_name='+',
verbose_name=_('Photo'),
null=True, blank=True)
.....
pid = Photo.objects.get(image = str_path)
gid= Group.objects.get(id = self.id)
self.save_photos(gid, pid)
....
def save_photos(self, gid, pid):
group_photo = GroupPhotos(groupupload=gid.id,
photo=pid.id
)
group_photo.save()
and my GroupPhotos models is:
class GroupPhotos(models.Model):
groupupload = models.ForeignKey('Group')
photo = models.ForeignKey('Photo')
class Meta:
db_table = u'group_photos'
when i want to save it from admin panel i am getting value error sth like this:
Cannot assign "38": "GroupPhotos.groupupload" must be a "Group" instance.
with group_photo = GroupPhotos(groupupload=gid, photo=pid) defination it is working but there is no any changes in GroupPhotos table(group_photos). printing this print pid.id,' >>> ',gid.id i am getting true relation...
UPDATE:
I have been working since morning, but no progress... i have also tried this but nothing changed:
pid = Photo.objects.get(image = str_path)
ger = Group.objects.get(id = self.id)
ger.title = self.title
ger.save()
ger.photos.add(pid)
The error is here:
group_photo = GroupPhotos(groupupload=gid.id, photo=pid.id)
The arguments to groupupload and photo should be instances of Group and Photo respectively. Try the following:
group_photo = GroupPhotos(groupupload=gid, photo=pid)
In other words, when creating an object you need to pass arguments of the expected type and not an integer (which may be the primary key key of the desired object but it also might not, which is why you need to pass an object of the correct type).
i have solved my problem with adding through option to my manytomanyfield:
photos = models.ManyToManyField('Photo', related_name='+',
verbose_name=_('Photo'),
null=True, blank=True, through=GroupPhotos)
some info about ManyToManyField.through here:
Django will automatically generate a table to manage many-to-many
relationships. However, if you want to manually specify the
intermediary table, you can use the through option to specify the
Django model that represents the intermediate table that you want to
use.
The most common use for this option is when you want to associate extra data with a many-to-many relationship.
I have a model like below:
class StaffProfile(models.Model):
user = models.ForeignKey(User)
maas = models.FloatField()
maas_gunu = models.CharField(max_length=5)
When I try to insert data with a code like below:
staffprofilesay = StaffProfile.objects.filter(user = user_id).count()
if staffprofilesay > 0:
staffprofile = StaffProfile.objects.get(user = user_id)
else:
staffprofile = StaffProfile()
staffprofile.user = user_id
staffprofile.maas = calisan_formu.cleaned_data["maas"]
staffprofile.maas_gunu = calisan_formu.cleaned_data["maas_gunu"]
staffprofile.save()
I get an error like this:
Cannot assign "u'1'": "StaffProfile.user" must be a "User" instance.
What am I supposed to do?
PS: I'm using Django's User model
You need to assign a User object e.g.
from django.contrib.auth.models import User
user = User.objects.get(id=user_id)
staffprofile.user = user
user needs to be an instance of the User model, not a unicode object (which is what you are passing it).
Yes you have to pass User instance in staffprofile.user = user_id user id place.
As #david-s pointed out in a comment, if you don't have a user instance, you have to fetch from DB with an additional query.
Instead you can directly do is
staffprofile.user_id = user_id because Django behind the scene append _id in table for foreign keys so staffprofile.user will end staffprofile.user_id