I am having a problem regarding adding entry to a many to many relation field. I have the models as follows
class Address(models.Model):
id = models.AutoField(primary_key=True)
country = CountryField(blank_label='(select country)', blank=False, null=False, verbose_name='Country')
state = models.CharField(
max_length=50,
choices=STATE_CHOICES,
verbose_name='State',
blank=False,
null=False
)
...
class Volunteer(models.Model):
userID = models.OneToOneField(User, on_delete=models.CASCADE, to_field='id', primary_key=True, related_name='volunteer')
identificationNumber = models.CharField(max_length=50, unique=True, blank=False, null=False, verbose_name='Identification Number')
currentAddress = models.ManyToManyField(Address, related_name='volunteerCurrentAddress', verbose_name='Current Address', blank=False)
permanentAddress = models.ManyToManyField(Address, related_name='volunteerPermanentAddress', verbose_name='Permanent Address', blank=False)
...
def save(self, *args, **kwargs):
self.slug = self.userID.username
super(Volunteer, self).save(*args, **kwargs)
class TemporaryVolunteer(Volunteer):
pass
And in the views, I get both the currentAddress and permanentAddress fields as a ManyToManyRelatedManager. They are temporaryVolunteer.currentAddress and temporaryVolunteer.permanentAddress. I use these to create a new Volunteer instance as
volunteer = Volunteer(...)
volunteer.save()
volunteer.currentAddress.add(temporaryVolunteer.currentAddress.all()[0])
volunteer.permanentAddress.add(temporaryVolunteer.permanentAddress.all()[0])
volunteer.save()
But when I do print(volunteer.currentAddress.all()) or print(volunteer.permanentAddress.all()), it returns an empty queryset. I also checked the admin site for confirmation and there are no entries of address on the volunteer instance.
Is there any way the entries can be added with this approach?
The problem was in the design of the database. I had used a new class TemporaryVolunteer in order to store unverified accounts and later moved to the Volunteer class after they were verfied. As I had inherited TemporaryVolunteer from Volunteer class, the way Django handles Many to many relationships without making duplicates (Source: https://docs.djangoproject.com/en/3.0/topics/db/examples/many_to_many/) led to the problem of no entries being added in the corresponding Volunteer class.
Initially, I checked this by copying all the members of Volunteer to TemporaryVolunteer. After verifying that it worked, I changed the database design as this is a bad approach and kept a boolean value isVerified in the Volunteer class and removed the TemporaryVolunteer class entirely.
Related
I have 3 models (supervisor, students, and allocation)
I am building an allocation system where multiple students can be allocated to one supervisor
Now I want my model to be able to yeld this output
Example of how i want the output to come out
Here are the structure of my model
class StudentProfile(models.Model):
stud_id = models.UUIDField(default=uuid.uuid4, primary_key=True, unique=True)
user_id = models.OneToOneField(User,blank=True, null=True, on_delete=models.CASCADE)
programme_id = models.ForeignKey(Programme, on_delete=models.CASCADE)
session_id = models.ForeignKey(Sessi`**enter code here**`on, on_delete=models.CASCADE)
type_id = models.ForeignKey(StudentType, on_delete=models.CASCADE)
dept_id = models.ForeignKey(Department, on_delete=models.CASCADE)
class SupervisorProfile(models.Model):
super_id = models.UUIDField(default=uuid.uuid4, primary_key=True, unique=True)
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
dept_id = models.ForeignKey(Department, on_delete=models.CASCADE)
class Allocate(models.Model):
allocate_id = models.UUIDField(default=uuid.uuid4, primary_key=True, unique=True)
stud_id = models.ForeignKey(StudentProfile, on_delete=models.CASCADE)
super_id = models.ForeignKey(SupervisorProfile, on_delete=models.CASCADE)
now my main focus is the Allocate model where the allocation is made, and there is a lot of redundancy any suggestions on how to improve my model to remove redundancy in yielding the expected HTML output would be appreciated 🙏
As far as I understand, you need to assign several students to one Supervisor
For this, you only need to use ForeignKey in class StudentProfile
As below:
supervisor=models.ForeignKey(Supervisor,on_delete=models.DO_NOTHING)
But if you need to connect a student to several Supervisor, you should use ManyToManyField
ManyToManyField automatically creates a third table like class Allocate of yourself
For more information, refer to the hire.
It is also possible to reduce the redundancy by considering the department.
However
It doesn't seem that less redundancy can be found in sql database
I hope it was useful
well my college is making us go learn a framework and make a website with it in a month, and it's really killing me, because of that I couldn't really get a good understanding of the Django framework as I am making progress while watching YouTube vids and reading docs.
Anyways my models are all messed up which made the job even harder, and whenever I solve a problem another one arises, but the deadline is close and making any changes to the models will cost me a great deal of time. This time my problem is about fetching data.
The concerned models are the following:
The User class for authentication
class User(AbstractBaseUser, PermissionsMixin):
id = models.AutoField(primary_key=True,null=False)
username = models.CharField(max_length=50)
email = models.EmailField(unique=True)
nom = models.CharField(max_length=255)
prenom = models.CharField(max_length=255)
usertype = models.CharField(choices=types,max_length=20,default="user")
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
student_data = models.OneToOneField(Etudiant, on_delete=models.CASCADE,blank=True, null=True,related_name='Etudiant_access')
Prof_data = models.OneToOneField(Prof, on_delete=models.CASCADE,blank=True, null=True)
objects=UserManager()
def __str__(self):
return self.prenom + " " + self.nom
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
The Students(Etudiant) class for managing the students:
class Etudiant(models.Model):
filiere = models.ForeignKey(Filiere, on_delete=models.DO_NOTHING)
classe = models.ForeignKey(Classe,null=True, on_delete=models.DO_NOTHING)
notes = models.ManyToManyField(note,blank=True, null=True)
The class Classe (LMAO) for managing the different classes:
class Classe(models.Model):
#Cla_id = models.AutoField(primary_key=True, null=False)
Designation = models.CharField(max_length=100)
filiere = models.ForeignKey(Filiere, on_delete=models.CASCADE)
Epreuve = models.ManyToManyField(Epreuve,blank=True, null=True)
def __str__(self):
return self.Designation
The thing is that I wanna fetch all data of the Users that are students (which means that their Prof_data attribute is blank/null and their student_data attribute is pointing to the Etudiant(Student) class while having an Etudiant.classe attribute equals to a value in the view's parameters
I've solved a great deal of it but I'm stuck at the end
This is my view function:
#login_required
def class_info(request,design):
#getting the Classe(s) from the url which Designation == design
classe_now = Classe.objects.get(Designation=design)
print(classe_now) # This works like a charm
#getting the Students objects that are part of the class_now
Etudiants = Etudiant.objects.filter(classe=classe_now)
print(Etudiants) # This works too. It returns the 'Etudiant' objects from where i wanna access to the Users data
#getting the User data of the student objects (This is where i get confused)
students_to_show = User.objects.filter(student_data=Etudiants)
pprint(students_to_show)
return render(request, 'Prof/class_info.html')
I am really confused, you are truly my last hope in this, and thank you for your time.
You can filter your User model by selecting all users that do have empty/null relation to Prof model and nonempty/null relation to Etudiant model.
student_users = User.objects.filter(Prof_data__isnull=True, student_data__isnull=False)
then for each stident_user, you can fetch its student data in the following manner:
student_user = student_users[0]
student_user.student_data.filiere
student_user.student_data.classe
student_user.student_data.notes
You can then pass the queryset result to the render function as a context variable. Check this brief tutorial on how to pass data to templates.
I have three models that I'm trying to hook up so I can pull-out StudentItem information based upon ID of the Course that was passed in.
The models look like the following:
class Student(models.Model):
first_name = models.CharField(max_length=128, unique=False)
last_name = models.CharField(max_length=128, unique=False)
class Course(models.Model):
name = models.CharField(max_length=256, unique=False)
course_student = models.ManyToManyField(Student)
class StudentItem(models.Model):
item_student = models.ForeignKey('Student',on_delete=models.CASCADE)
description = models.CharField(max_length=256, unique=False, blank=True)
Right now, my view looks like:
class CourseDetailView(LoginRequiredMixin,DetailView):
model = models.Course
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_item_list'] = StudentItem.objects.prefetch_related(Prefetch('item_student__id__course_student',queryset=Course.objects.filter(pk=self.kwargs['pk'])))
return context
I can get everything connected via prefetch across all of the models but the queryset filtering is not working. I am getting all records for every course regardless of the course ID that was passed in.
Hopefully it's a small tweak. Really appreciate the help!
I am working on a blog type website.
where students will ask question and teacher will answer it.
I put two user role
Teacher and student
class User(AbstractBaseUser, PermissionsMixin):
USER_TYPE = (
('None', 'None'),
('Student', 'Student'),
('Teacher', 'Teacher'),
)
user_type = models.CharField(choices=USER_TYPE, default='Student', max_length=50)
This is the user model where the role is defined.
Post model for submitting the question and Comment model for answering it.
In the Post model I put on field is_answered and as default put it False
class add_question(models.Model):
created_by = models.ForeignKey(User, blank=False, on_delete=models.CASCADE)
is_answered = models.BooleanField(default=False)
And the answer model [which is comment one] is referred to as the foreign key of the question
class submit_answer(models.Model):
question_id = models.ForeignKey(
add_question, blank=False, on_delete=models.CASCADE)
created_by = models.ForeignKey(User, blank=False, on_delete=models.CASCADE)
Both question and answer model contains created_by field and ForeignKey of User and answer model contains another ForeignKey of question.
so I need when the teacher role will put a comment the is_answered Field in add_question model should turn as true.
as student also can comment on his/er question so I need on condition to apply.
I am using serializer as I need API of this
So, should I modify on my views.py or serializers.py and how should I do that!
It would be great help if someone guide me how to do it?
Thanks and let me know if any other information needed.
The best practice would be adding such codition in save() method of models.Model. You should name your Model classes differently, like Question and Answer, because after creating, if you want to edit or something, it would be weird if you have to search for submit_answer, right? And as #wjh18 said, use CamelCase in classes.
Also question_id is usually bad idea, better think of question, because it will lead directly to the whole object, not its id.
class Answer(models.Model):
question = models.ForeignKey(Question, blank=False, on_delete=models.CASCADE)
created_by = models.ForeignKey(User, blank=False, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
if self.created_by.user_type == 'Teacher' and not self.question.is_answered:
self.question.is_answered = True
self.question.save()
super().save(*args, **kwargs)
I have the following abstract class:
class UserStamp(models.Model):
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
related_name='%(app_label)s_%(class)s_created_by', on_delete=models.CASCADE)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
related_name='%(app_label)s_%(class)s_updated_by', on_delete=models.CASCADE)
class Meta:
abstract = True
The Account Model inherits from it:
class Account(UserStamp):
pass
And I have a User Model with a FK to
class User(AbstractBaseUser,PermissionsMixin, UserStamp):
account = models.ForeignKey(Account, blank=True, null=True, related_name='owner',on_delete=models.CASCADE)
I have the following error when I migrate:
django.db.migrations.exceptions.CircularDependencyError:
The circular error I think appears because:
Account is calling User by inheriting created_by, updated_by from UserStamp, so points to User, and User points with Account FK back to Account.
If I use:
account = models.ForeignKey('accounts.Account', blank=True, null=True, related_name='owner',on_delete=models.CASCADE)
the issues is not solved.
My problem has (2 issues), but I decided to split the initial question in 2 questions to be more clear(I think they can be solved separately):
Second part here (how to set created_by, updated_by)
You can set a default user by modifying the save() method of your model:
class UserStamp(models.Model):
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
...
def save(self, *args, **kwargs):
if not self.created_by:
super_users = settings.AUTH_USER_MODEL.objects.filter(
is_superuser=True).order_by('date_joined')
first_user = super_users[0]
self.created_by = first_user
super().save(*args, **kwargs)
But I don't think that's what's causing your migration error. You may want to try a OneToOneField