django error while updating only one field in model - django

I want to update only one field in my model. However, I am getting an error.
This is my model:
class People(models.Model):
name = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
class Salary(models.Model):
id_of_people=models.ForeignKey(People)
salary = models.IntegerField(required=False)
In views.py
-When I try this one to update :
def update(request):
a=Salary.objects.get(id_of_people_id=1)
a.salary=500
Salary().save()
My Error says:
IntegrityError at/update
salary.id_of_people_id may not be NULL
and traceback indicates:
Salary().save()
-When I try this one :
def update(request):
a=Salary.objects.get(id_of_people_id=1)
a.salary=500
Salary().save(save_fields=['salary'])
-I get this error:
save() got an unexpected keyword argument 'save_fields'
Can you please help me to update only one field in my table ?

In both of those cases you'll want to call save on the model instance you've created, not the model class--that is, you should be saving a, not Salary:
a.salary=500
a.save()
When you do Salary().save(), what's happening is that you create a brand new, empty model instance, and then try to commit that to the database, rather than committing the one that you had just modified.

If a ForeignKey is defined in your model, the contraint will be enforced at the db level so you will need to save the object reference by the Foreign key before you save the referring object.
You may also want to reconsider whether or not the foreign keys should be defined in person or Salary.
If you were to define the model like this:
class Person(models.Model):
name = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
salary = models.ForeignKey(Salary)
class Salary(models.Model):
amount = models.IntegerField(required=False)
Then you could define your views function so that it looks like this:
def update(request):
s = Salary(amount=request.POST['salary'])
s.save()
p = Person(name=request.POST['name'], lastname=request.POST['lastname'], salary=s)
p.save()
The nice about this is that you could then reference the salary from a Person instance:
Person.objects.get(pk=1).salary.amount
I can't help but ask the question though why you really need these in separate objects. Things might be simpler if your model looked like this:
class Person(models.Model):
name = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
salary = models.IntegerField(required=False)

Related

How to call a a field of one model A into another model B so that b can work as a view

I have created a model called Department, Course. Models are as follow
This is the model for departments and course
class Departments(models.Model):
Department_Id = models.IntegerField(primary_key=True)
Department_Name = models.CharField(max_length=200)
Department_Code = models.CharField(max_length=200)
class Course(models.Model):
Course_Id = models.IntegerField(primary_key=True)
Department_Id = models.ForeignKey(Departments, on_delete=models.CASCADE)
Course_Name = models.CharField(max_length=200)
Course_Code = models.CharField(max_length=200)
I want to create a model called view which can be later on called for search. I want a view model in a such a way that it consit of the data in concat form i.e. name= Department_name+ Course_Name
class View (models.model):
view_id= models.IntegerField(primary_key=True)
Name= Department_name(I want this from Departments table)
+ Course_Name(I want this from Course table)
I try using one to one relation . I would really appricate the help
It's not clear why you'd want to do that. It's never a good idea to duplicate data from one model into another one, as it can lead to inconsistencies.
You can add a ForeignKey in View to your Course model and then when you do f"{view.course.name} {view.course.department.name}" you already have your string:
class View(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
def name(self):
return f"{self.course.name} {self.course.department.name}"
Notes:
Don't call your foreign key Department_id because it's not referring to the id but to the object itself in the Django ORM: department = models.ForeignKey(Department, on_delete=models.CASCADE). As you can see, this makes reading the code much simpler: self.course.Department_id is a Department object not an integer, so self.course.department makes more sense.
Don't prefix your field names with the class, it just makes the code so much less readable: Do you prefer department.name or department.Department_name?
The View model is still a mystery to me, as you can search without it. You can search for example for courses with a matching department name like this:
Course.objects.filter(department__name__icontains="maths")
which will return all courses with "maths" in their department name.
Remove all the ids from your models, they are created automatically by Django anyway (and called id). Again, department.id is much easier to read than department.Department_id. Also in your code, you have to generate the ids yourself since you don't set them to auto-populate.

How do I delete a single instance of an intermediate model in a Django Many-to-many (through) relationship?

This is a M2M relationship, that has the intermediate model 'Membership' (the intermediate model stores extra information about the relationship between a student and a course, using the 'through' keyword). In my case the extra relationship is the grade a student has in each of his courses. MY PROBLEM IS: I can't find a way in django to delete/remove only one of the relationships between one of the courses and the grade the student has.
class Student(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Course(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Student, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
group = models.ForeignKey(Course, on_delete=models.CASCADE)
grade = models.CharField(max_length=64)
Since 'Membership' is an intermediate model, it disables the remove(), that would be accesible in a normal ManyToMany relationship.
You can use the clear() method, but his would remove every grade the student has in a course relationship. For example: If 'Carlos' was in 5 different courses with 5 different grades for each course, and also some other student 'Maria'
c = Course
c.members.clear()
would clear every grade relationship. You can see another example in the docs:
https://docs.djangoproject.com/en/2.0/topics/db/models/#extra-fields-on-many-to-many-relationships
And if I try to use the remove() method I get an attribute error:
m1 = 'instance of a Membership'
m1.remove()
AttributeError: 'Membership' object has no attribute 'remove'
In the django admin, I am able to remove a single 'Membership object'==='grade relationship' but I can't figure out a way to remove it on the shell or on my code that does't use the clear() method (which does't work form me cause it clears every relationship)
Please Help :///
You should just delete the membership.
m1.delete()

Trouble overriding save method on Django model with ManyToManyField

I'm having trouble overriding the save method on a Django model to check a restriction on a many-to-many field.
Say I have the following models:
class Person(models.Model):
name = models.CharField()
class ClothingItem(models.Model):
description = models.CharField()
owner = models.ForeignKey(Person)
class Outfit(models.Model):
name = models.CharField()
owner = models.ForeignKey(Person)
clothing_items = models.ManyToManyField(ClothingItem)
I would like to put a restriction on the save method of Outfit that ensures that each ClothingItem in a given outfit has the same owner as the Outfit itself.
I.e. I'd like to write:
class Outfit(models.Model):
name = models.CharField()
owner = models.ForeignKey(Person)
clothing_items = models.ManyToManyField(ClothingItem)
def save(self, *args, **kwargs):
for ci in self.clothing_items:
if ci.owner != self.owner:
raise ValueError('You can only put your own items in an outfit!)
super(Outfit, self).save(*args, **kwargs)
but when I try that I get an error about <Outfit: SundayBest>" needs to have a value for field "outfit" before this many-to-many relationship can be used.
Any ideas what's going wrong here?
There are two issues going on here. To directly answer your question, the error basically means: You cannot refer to any m2m relationship if the original object(an instance of Outfit here) is not saved in database.
Sounds like you are trying to do the validation in save() method, which is a pretty bad practice in django. The verification process should typically happen in Form that creates Outfit objects. To override default django form, please refer to django ModelAdmin.form. To understand how to do validation on django forms, check ModelForm validation.
If you want code to refer to for m2m validation, I found a good example from SO.

Django ManyToManyField reverse Relationship

I would like to do a reverse relationship on my table Tickets.
Here is my model :
class Tickets(models.Model):
ticket_title = models.CharField(max_length=100)
ticket_content = models.TextField()
class User_Detail(models.Model):
user = models.OneToOneField(User)
tickets = models.ManyToManyField(Tickets, blank=True, null=True)
I create my ticket like that :
ticket = Tickets.objects.create(ticket_title="test", ticket_content="test content")
request.user.user_detail.tickets.add(ticket)
and the thing I'm having an issue to do is to get the username of the guy who post the ticket, (without request.user)
so I tried like that :
ticket = Tickets.objects.get(pk=1)
ticket.user_detail_set.user.username
but I get
AttributeError: 'ManyRelatedManager' object has no attribute 'user'
Thanks you for watching, I hope you'll understand.
Since you set up a many-to-many relationship, a Ticket may have many User_Detail objects. Therefore, Ticket.user_detail_set is a manager, not a single object. You could get the first user associated with a Ticket like this:
ticket.user_detail_set.first().user.username
But it sounds like you actually want a one-to-many relationship between Ticket and User_Detail, meaning you actually want Ticket to have a foreign key relationship. Your models should probably look like this:
class User_Detail(models.Model):
user = models.OneToOneField(User)
class Ticket(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=100)
contents = models.TextField()
Then you can do:
ticket = Ticket.objects.get(pk=1)
user = ticket.user
You might even be able to drop the User_Detail model entirely, unless you use it elsewhere in your application and/or it has more fields than what is shown here.

Django model clean and ManytoMany problem

I want to check my Foo instance if it belongs to a category yet my category is a many to many attribute thus I get "'Foo' instance needs to have a primary key value before a many-to-many relationship can be used." once I try such:
class Category(models.Model):
name = models.CharField(max_length=120)
class Movie (models.Model):
poster = models.ImageField(blank=True)
categories = models.ManyToManyField(Category)
def clean(self):
try:
self.categories.all().get(db_name="special")
self.poster.url = u'/media/special_img.png'
except Category.DoesNotExist:
pass
You can't check if Foo belongs to a category yet until you save it. But since it isn't saved anyway, you can be sure that it doesn't belong to a category yet.
One way to check wheter it has been saved already is by using if foo.pk. The pk is the primary key and it will be None if it hasn't been saved yet.