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.
Related
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)
I have a visitorSaveSerializer which is responsible for validating the data to be saved:
class VisitorSaveSerializer(serializers.ModelSerializer):
class Meta:
model = Visitor
fields = ('gsm', 'email', 'firstname', 'lastname')
The problem is:
visitor_serializer = VisitorSaveSerializer(data={...related data here...})
if visitor_serializer.is_valid():
visitor_serializer.save()
visitor_id = visitor.serializer.data.get("id", 0) // Fails for sure.
OK, I know id is not among serializer fields, so last line fails.
How should I approach saving an object when I need to get last inserted id?
The serializer returns the instance saved, so you can obtain the primary key of that instance with:
visitor_serializer = VisitorSaveSerializer(data={…})
if visitor_serializer.is_valid():
visitor = visitor_serializer.save()
visitor_id = visitor.pk
Can anyone explain why this is iterable:
User.objects.all()
this is valid and gives me a value (The current user's alias. session is storing the user id):
User.objects.get(id = request.session['currentuser']).alias)
But this is giving me the error saying it is 'not iterable?':
Poke.objects.get(user = User.objects.get(id = request.session['currentuser']).alias)
(This code is supposed to get a list of Poke entries where the user column matches the current user's alias.)
Here is the Poke model. It does not use ForeignKeys, as I was having trouble setting two of them without errors.
class Poke(models.Model):
id = models.IntegerField(primary_key=True)
user = models.CharField(max_length=100)
poker = models.CharField(max_length=100)
pokes = models.IntegerField()
class Meta:
app_label = "poke_app"
Get will retrieve a single object and therefore the result will not be iterable. See documentation.
Do you see an integer value when you print(request.session['currentuser'])?
If you will see a string then you shoud give an integer value
EX: userobj = User.objects.get(id=uid)
Oh sory
User.objects.get(id = request.session['currentuser']).alias)
You open ( and closed it after ['currentuser']) but why you close ) again after .alias ?
I have two Django models and connected via Foreignkey element and in the second model I need to use the firs model's attribute - example (pseudocode):
Class Category(models.Model):
c_attribute = "Blue"
Class Object(models.Model):
o_category = models.ForeignKey(Category)
o_color = o_category.c_attribute
The key here is the last line - I got error saying that ForeignKey object has no attribute c_attribute.
Thanks
Because o_category is a Key to a Category, not a Category itself!
you can check by type(o_category) to check is not Category!
so you have access to related Cateogry of a Object in other parts of application when connected to database.for example in shell you can write:
c = Category()
c.save()
o = Object(o_category = c, ...) #create Object with desired params
... #some changes to o
o.save()
o.o_category.c_attribute #this will work! :)
You can use to_field='', but that might give you an error as well.
Class Object(models.Model):
o_category = models.ForeignKey(Category)
o_color = models.ForeignKey(Category, to_field="c_attribute")
The best thing is do create a function in your Object model, that would get you the categories c_attribute like so:
def get_c_attribute(self):
return self.o_category.c_attribute
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.