save() prohibited to prevent data loss due to unsaved related object 'student' - django

I am a recreating a Django project. I am trying create post_save signal that will create student marks when a student is created. I am getting the error message: save() prohibited to prevent data loss due to unsaved related object 'student'.
Here is my student model:
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
class_id=models.ForeignKey(Class, on_delete=models.CASCADE, null=True, blank=True, default=1)
col = models.CharField(max_length=50, null=True, blank=True, default=science_college)
name = models.CharField(max_length=100, null=True, blank=True)
sex= models.CharField(max_length=50, choices=SEX_TYPE, null=True, blank=True)
DOB=models.DateField(default="1998-01-01", null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
SID=models.CharField(('STUDENT_ID'), max_length=30, default=student_ids, unique=True, editable=False)
id = models.IntegerField(primary_key=True, editable=False)
def __str__(self):
return self.name
And here is the signal code
def create_marks(sender, instance, created, **kwargs):
if created:
if hasattr(instance, 'name'):
ass_list = instance.class_id.assign_set.all()
for ass in ass_list:
try:
StudentCourse.objects.get(student=instance, course=ass.course)
except StudentCourse.DoesNotExist:
sc=StudentCourse(student=instance, course=ass.course)
sc.save()
sc.marks_set.create(name='CAT 1')
sc.marks_set.create(name='CAT 2')
sc.marks_set.create(name='CAT 3')
sc.marks_set.create(name='SEMESTER EXAM')
elif hasattr(instance, 'course'):
student_list = instance.class_id.student_set.all()
cr = instance.course
for s in student_list:
try:
StudentCourse.objects.get(student=s, course=cr)
except StudentCourse.DoesNotExist:
sc = StudentCourse(student=s, course=cr)
sc.save()
sc.marks_set.create(name='CAT 1')
sc.marks_set.create(name='CAT 2')
sc.marks_set.create(name='CAT 3')
sc.marks_set.create('SEMESTER EXAM')
post_save.connect(create_marks, sender=Student)

Related

Error for my model with ManyToManyField in Django

I am working for a personal project that is using an API and having user authentication with JWT (but used in serializer). I wanted to implement ManyToManyField for user and city but it doesn't work properly. This is the extended model I have found and django aggregation . I want that the UserSearchLocation to store the City and when logged in to see the city, while other users will not see it until the search same city.
models.py
class UserSearchLocation(models.Model):
city_name = models.CharField(max_length=85, blank=False)
def __str__(self):
return self.city_name
class City(models.Model):
user_searched_locations = models.ManyToManyField(User,
through='UsersLocations',
through_fields=('city', 'user'),
related_name="my_cities",
blank=True)
id = models.AutoField(primary_key=True, editable=False)
location = models.CharField(max_length=85)
country = models.CharField(max_length=85, blank=True)
country_code = models.CharField(max_length=2, blank=True)
latitude = models.DecimalField(max_digits=6, decimal_places=4,
null=True, blank=True)
longitude = models.DecimalField(max_digits=6, decimal_places=4,
null=True, blank=True)
zip_code = models.PositiveIntegerField(default=0)
#users_location = models.ManyToManyField(UserSearchLocation)
def __str__(self):
return f'{self.location}, {self.country_code}'
def save(self, *args, **kwargs):
self.location = self.location.capitalize()
self.country = self.country.capitalize()
self.country_code = self.country_code.capitalize()
return super(City, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = 'cities'
unique_together = ("location", "country_code")
class UsersLocations(models.Model):
id = models.AutoField(primary_key=True, editable=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
city = models.ForeignKey(City,
on_delete=models.CASCADE,
related_name='locations_by_users',
null=True)
To add in localhost/admin/ a City works, but when to add a UserSearchLocation I have this error:
Exception Value:
column base_usersearchlocation.user_id does not exist
LINE 1: SELECT "base_usersearchlocation"."user_id", "base_usersearch...
Your error says the city.location doesn't exist - location is a CharField on your City model - are you sure you've run migrations and don't have any naming conflicts?

Django model UniqueConstraint problem, I want category parent not to be the current instance

Hey i have problem with the categories parent. As you can see in the code i have category with a foreign key pointing to it self. Now i dont want a instance of category to be a child of itself. So far i have tried unique_together and UniqueConstraint but that didn't work.
class Category(models.Model):
parent = models.ForeignKey('self', related_name="children", on_delete=models.CASCADE, blank=True, null=True) #'self' to indicate a self-reference.
title = models.CharField(max_length=100)
slug = AutoSlugField(populate_from='title', unique=True, null=False, editable=True)
logo = models.ImageField(upload_to="catlogo", blank=True, null=True, help_text='Optional')
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
#enforcing that there can not be two categories under a parent with same slug
verbose_name_plural = "categories"
constraints = [
models.UniqueConstraint(fields=['slug', 'parent'], name='unique_parent')
]
You can add some validations for it yourself though, you should simply overwrite the validate_unique method and add this validation to it. Try this.
class Category(models.Model):
parent = models.ForeignKey('self', related_name="children", on_delete=models.CASCADE, blank=True, null=True) #'self' to indicate a self-reference.
title = models.CharField(max_length=100)
slug = AutoSlugField(populate_from='title', unique=True, null=False, editable=True)
logo = models.ImageField(upload_to="catlogo", blank=True, null=True, help_text='Optional')
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "categories"
def validate_unique(self, *args, **kwargs):
super(Category, self).validate_unique(*args, **kwargs)
if self.__class__.objects.\
filter(parent=self.parent, slug=self.slug).\
exists():
raise ValidationError(
message='Category with this (parent, slug) already exists.',
code='unique_together',
)

Showing data related to a logged in user in Django

I am building this simple system for a school, where students can log in to see their results at the end of every semester. I designed a model for exams with a manytomany relationship to a user. My problems is in my template am finding it hard to show a exams results related to a logged in user.
models.py
class StudentProfile(models.Model):
SEX_CHOICES = (
('Male', 'Male'),
('Female', 'Female')
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
other_name = models.CharField(max_length=30, null=True, blank=True)
birth_of_date = models.DateField(null=True, blank=True)
birth_Of_admission = models.DateField(null=True, blank=True)
nationality = models.CharField(max_length=120)
phone_number = models.CharField(max_length=15, validators=[MinLengthValidator(10)])
gender = models.CharField(max_length=120, choices=SEX_CHOICES)
home_address = models.CharField(max_length=250, null=True, blank=True, )
passport_picture = models.ImageField(upload_to='passport_picture', null=True, blank=True,
help_text='Upload the passport picture here')
def __str__(self):
return "%s %s" % (self.user.first_name, self.user.last_name)
#receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
StudentProfile.objects.create(user=instance)
instance.studentprofile.save()
class Subject(models.Model):
subject_name = models.CharField(max_length=30, null=True, blank=True)
def __str__(self):
return self.subject_name
class Year(models.Model):
year = models.CharField(max_length=30, null=True, blank=True)
def __str__(self):
return self.year
class Exam(models.Model):
TERM_CHOICES = (
('First Term', 'First Term'),
('Second Term', 'Second Term'),
('Third Term', 'Third Term')
)
level = models.ForeignKey('Level', null=True, blank=True, on_delete=models.CASCADE)
student = models.ForeignKey(Year, null=True, blank=True, on_delete=models.CASCADE)
year = models.ForeignKey(Year, null=True, blank=True, on_delete=models.CASCADE)
subject = models.ForeignKey(Subject, null=True, blank=True, on_delete=models.CASCADE)
term = models.CharField(max_length=120, default="", choices=TERM_CHOICES)
mid_term_score = models.PositiveSmallIntegerField(help_text='the marks scored for mid term exams')
End_of_term_score = models.PositiveSmallIntegerField(help_text='the marks scored for end of term exams')
class_work_score = models.PositiveSmallIntegerField(help_text='the marks scored for class work')
def __str__(self):
return self.subject + "-" + self.term
views.py
class StudentView(LoginRequiredMixin, ListView):
model = Exam
template_name = 'student.html'
context_object_name = 'student'
def get_object(self):
return self.request.user.exam
What I am trying to do is to show logged in student only his results based on the exams he has taken and but is rather showing me all. Even those he has not taken.
you can retrive those exams by set_all look_up_relationship or manually can query on Exam model.
possible way can be like this
def get_object(self):
return self.request.user.exam_set.all()
Also you can try this
def get_object(self):
return Exam.objects.filter(student_id=self.request.user.id)
Edit
If i understand you properly now, then student's current level is an important factor of this Exam filtering. We should add that too than, otherwise all exam will appear. But from your Exam model structure, i haven't see any level entity associated with User model present. I am assuming term and level actually same thing ( most likely which are not )
def get_object(self):
return Exam.objects.filter(student_id=self.request.user.id, term = self.request.user.level )

Update existing M2M relationship in Django

I'm trying to save an existing instance of a customer record. Its model has a M2M to the vehicle model (since a customer can multiple vehicles). After reading several questions/answer here, I still do not know how to solve this.
Customer model:
class Customer(models.Model):
vehicle_id = models.ManyToManyField(VehicleSale)
name = models.CharField(max_length=40, blank=True, db_index=True, null=True,
verbose_name='name')
lic = models.CharField(max_length=20, blank=True, db_index=True, null=True,
verbose_name='license')
addr = models.CharField(max_length=40, blank=True, null=True, verbose_name='address')
city = models.CharField(max_length=15, blank=True, null=True, verbose_name='city')
state = models.CharField(max_length=2, blank=True, null=True, verbose_name='state')
zip = models.CharField(max_length=10, blank=True, null=True, verbose_name='zipcode')
email = models.EmailField(blank=True, null=True, verbose_name='email')
tel1 = models.CharField(max_length=15, blank=True, verbose_name='Tel. 1', null=True)
tel2 = models.CharField(max_length=15, blank=True, verbose_name='Tel. 2', null=True)
ssn = models.CharField(max_length=12, blank=True, db_index=True, null=True,verbose_name='SSN')
class Meta:
db_table = 'customer'
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
self.name = self.name.upper()
self.addr = self.addr.upper()
self.city = self.city.upper()
self.state = self.state.upper()
return super(Customer, self).save(*args, **kwargs)
In the view, after defining customer as
customer = current_vehicle.customer_set.all()
I tried the following:
if 'customer' in request.POST:
if customer:
customer_form = CustomerForm(request.POST, instance=customer[0])
if customer_form.is_valid():
customer_form.save()
Also tried adding before customer_form is defined:
customer.vehicle_id = current_vehicle.id
And then this after the form:
customer_form.vehicle_id = current_vehicle.id
Form is not valid so it's not saved. Upon checking {{ form.errors}}, it always reports vehicle_id is required.
Finally, after the answer in this, I adjusted it to my scenario by adding:
obj = customer_form.save(commit=False)
and hoping to assign vehicle_id, but it fails immediately.
What am I missing?
Thanks.
1st EDIT:
The section on the view now looks as:
customer_form = CustomerForm(request.POST, instance=customer[0])
customer_form.save()
customer_form.vehicle_id.add(current_vehicle)
You are misunderstanding what a ManyToMany field is here:
customer_form.vehicle_id = current_vehicle.id
vehicle_id is defined as a ManyToMany field on your Customer model, therefore you can't just assign a single id to it. You have to add an instance of VehicleSale model, eg:
customer_form.vehicle_id.add(current_vehicle)
See docs here:
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/
See also this answer for why you can't save until you populate the vehicle_id relation:
https://stackoverflow.com/a/2529875/202168

post save operation if a filed is null or blank in django models?

here is my code :
class Invitation(models.Model):
#other fields here
Code = models.CharField(max_length=128, null=True, blank=True)
Tags = models.ManyToManyField("CategorieInvitation", null=True, blank=True)
Tags = models.ManyToManyField("Usage", null=True, blank=True)
Note = models.CharField(max_length=128, null=True, blank=True)
Used = models.BooleanField(default=False, blank=True)
SendTo = models.EmailField(null=True, blank=True)
# a revoir
def post_save(self, model_instance, add):
if self.Code.__len__() == 0 :
self.Code = generate_invitation(1)[0]
self.save()
how to replace Code with the result of generate_invitation if Code is blank or null even if created in django-admin interface ?
regards
Bussiere
For what you are trying to do it's probably easier and more efficient to override the save method.
class Invitation(models.Model):
#other fields here
code = models.CharField(max_length=128, null=True, blank=True)
tags = models.ManyToManyField("CategorieInvitation", null=True, blank=True)
tags2 = models.ManyToManyField("Usage", null=True, blank=True)
note = models.CharField(max_length=128, null=True, blank=True)
used = models.BooleanField(default=False, blank=True)
send_to = models.EmailField(null=True, blank=True)
# a revoir
def save(self, *args, **kwargs):
if not self.code:
self.code = generate_invitation(1)[0]
super(Invitation, self).save(*args, **kwargs)
By the way post_save is not something that should be a model instance method.
See: https://docs.djangoproject.com/en/1.4/ref/signals/#signals