Let's say that I have created an app for a school with several models (e.g. Student, Teacher, Course, Attendance, Grade, Timetable, Payments etc).
It's working great for the current year. But now I want to expand my application, so that several schools can use it and it can store data of (mostly) independent seasons/years.
The first solution that comes to my mind, is to add 2 extra models (1)school=user and (2)season=year. And then add ForeignKeys from (almost) ALL my models to both of these (school, season).
(Maybe I could add a third model named SchoolSeason, with just these 2 fields and use this as FK to all my fields.)
Is there a more elegant solution?
Edit: a drawback to this solution would be that the models (e.g. Students) will share their auto-incremented ID with other schools.
Hard to tell without your current models but I would to the same by adding to 2 extra models. But no need to add both of them to all of your models : only Season is needed if you link Season to School.
class School(models.Model):
name = models.CharField(...)
class Season(models.Model):
school = models.ForeignKey(School)
name = models.CharField(...)
other_fields...
Each Season is linked to a School. Then, you can add the Foreign Key to all of your models.
About your problem in the edit, you are right, it would be a problem. You should not use auto-incremented key but UUid.
Finally, it would look like :
class BaseSeasonModel(models.Model):
uid = models.UUIDField(
primary_key=True,
default=uuid_lib.uuid4,
editable=False,
)
season = models.ForeignKey(Season)
class Meta:
abstract = True
And all of your models would inherit from it :
class Student(BaseSeasonModel):
...
Related
i have an issue with the code in django framework regarding to related_name and related_query_name in django. please django expert explain the related_name in django, the code is below:
related_name='+'
Related Name
Django maintains backward relation on each object for easy access to related objects. Suppose you have two models named "School" and "Student" and one school can have multiple students. So you will have model definition something like this
class School(models.Model):
name = models.CharField(max_length=55)
city = models.Charfield(max_length=55)
class Student(models.Model):
name = models.CharField(max_length=55)
school = models.ForeignKey(School)
Now if you have an school objects then you can access all students of that school with writing query explictly.
school = School.objects.get(id=1)
# Now if need all students of this school, first thing that come in your mind would be
Student.objects.filter(school=school)
# But instead of this, you can access all students by
school.student_set.all()
Here student_set is the default, related name made by Django. But you can have your custom related names like this
class Student(models.Model):
name = models.CharField(max_length=55)
school = models.ForeignKey(School, related_name='students')
# Now you can do
school.students.all()
Special Character in related name
If you define related_name='+' then backward relation would not be available on object and school.student_set.all() will give you error.
If you’d prefer Django not to create a backwards relation, set related_name to '+' or end it with '+'. For example, this will ensure that the User model won’t have a backwards relation to this model:
Related Query Name
related_query_name is similar to related_name but it gets used in queryset.
If you need to apply some filter on student via school model, then you would do
School.objects.filter(student__name='abc')
But if you define related_query_name then you can do
class Student(models.Model):
name = models.CharField(max_length=55)
school = models.ForeignKey(School, related_query_name='abc')
# Now you can do
School.objects.filter(abc__name='abc')
Refer doc for further reference: https://docs.djangoproject.com/en/3.0/ref/models/fields/
How to write a complex query to
1) create a student,Course,OptionOne - example -
student_name=John,
rollno = 20
course1 = this field will refence a field in OptionOne, OptionOne will
reference the course desired. enter code here
**illustration** - John Selects mathematics as the first option, while Mike
selects Geoography as Option One, Mathematics as Option Two
2) Select all students who opt mathematics as option one
3) Select the student alongwith the course he opted
django.db import models
# Create your models here.
class Course(models.Model):
course_name = models.CharField(max_length=200)
course_code = models.CharField(max_length=200)
class PriorityOne(models.Model):
course = models.OneToOneField(Course, verbose_name=("Course"),
on_delete=models.CASCADE)
class PriorityTwo(models.Model):
course = models.OneToOneField(Course, verbose_name=("Course"),
on_delete=models.CASCADE)
class PriorityThree(models.Model):
course = models.OneToOneField(Course, verbose_name=("Course"),
on_delete=models.CASCADE)
class Student(models.Model):
student_name=models.CharField(max_length=200)
rollno = models.CharField(max_length=200)
course1 = models.OneToOneField(PriorityOne,on_delete=models.CASCADE)
course2 = models.OneToOneField(PriorityTwo,on_delete=models.CASCADE)
course3 = models.ForeignKey(PriorityThree, on_delete=models.CASCADE)
You can use a M:M field here if multiple students can take the same course. The course will have the ManyToMany field referencing the Student model. This means multiple course objects can be associated with a student and a Student can have multiple Courses. I know it seems a little weird on where you define the M2M field. If you want to set a priority list, then you can define an integer field with the top priority course pk. That is of course one way of doing it. Any of the syntax for M2M fields are here Django M2M docs. If you need further explanation, I will be glad to help.
I have some models that represents some companies and their structure. Also all models can generate some Notifications (Notes). User can see own Notes, and, of course, can't see others.
class Note(models.Model):
text = models.CharField(...)
class Company(models.Model):
user = models.ForeignKey(User)
note = models.ManyToManyField(Note, blank='True', null='True')
class Department(models.Model):
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
class Worker(models.Model):
department = models.ForeignKey(Department)
note = models.ManyToManyField(Note, blank='True', null='True')
class Document(models.Model)
company = models.ForeignKey(Company)
note = models.ManyToManyField(Note, blank='True', null='True')
The question is how I can collect all Notes for particular user to show them?
I can do:
Note.objects.filter(worker__company__user=2)
But its only for Notes that was generated by Workers. What about another? I can try hardcoded all existing models, but if do so dozen of kittens will die!
I also tried to use backward lookups but got "do not support nested lookups". May be I did something wrong.
EDIT:
As I mentioned above I know how to do this by enumerating all models (Company, Worker, etc. ). But if I will create a new model (in another App for example) that also can generate Notes, I have to change code in the View in another App, and that's not good.
You can get the Notes of a user by using the following query:
For example let us think that a user's id is 1 and we want to keep it in variable x so that we can use it in query. So the code will be like this:
>>x = 1
>>Note.objects.filter(Q(**{'%s_id' % 'worker__department__company__user' : x})|Q(**{'%s_id' % 'document__company__user' : x})|Q(**{'%s_id' % 'company__user' : x})|Q(**{'%s_id' % 'department__company__user' : x})).distinct()
Here I am running OR operation using Q and distinct() at the end of the query to remove duplicates.
EDIT:
As I mentioned above I know how to do this by enumerating all models
(Company, Worker, etc. ). But if I will create a new model (in another
App for example) that also can generate Notes, I have to change code
in the View in another App, and that's not good.
In my opinion, if you write another model, how are you suppose to get the notes from that model without adding new query? Here each class (ie. Department, Worker) are separately connected to Company and each of the classes has its own m2m relation with Note and there is no straight connection to User with Note's of other classes(except Company). Another way could be using through but for that you have change the existing model definitions.
Another Solution:
As you have mentioned in comments, you are willing to change the model structure if it makes your query easier, then you can try the following solution:
class BaseModel(models.Model):
user = models.Foreignkey(User)
note = models.ManyToManyField(Note)
reports_to = models.ForeignKey('self', null=True, default=None)
class Company(BaseModel):
class Meta:
proxy = True
class Document(BaseModel):
class Meta:
proxy = True
#And so on.....
Advantages: No need to create separate table for document/company etc.
object creation:
>>c= Company.objects.create(user_id=1)
>>c.note.add(Note.objects.create(text='Hello'))
>>d = Document.objects.create(user_id=1, related_to=c)
>>d.note.add(Note.objects.create(text='Hello World'))
I have two classes in my models.py file:
class Person:
person_name = models.CharField(max_length = 50)
class Course:
course_name = models.CharField(max_length = 50)
course_person = models.ManyToManyField(Person)
In my modified example, one person is takes many courses and one course is taken by many people, hence ManyToMany.
When I let Django auto-generate my table, I get an extra ID field.
I want the autogenerated person_course manytomany table to consist of the two composite keys person_id and course_id only. Note: Both of them are auto-generated, auto-incremented fields.
I have also tried defining my ManyToMany class and attempted to link the fields using the keyword through=, but that did not help.
I have asked Google but without much help. Many some geniuses among you can provide some hint :)
Django currently does not support composite primary key by default
What you can do instead is keep the auto generated id as the (surrogate) primary key and then define a unique_together relationship in the through table.
class Meta:
unique_together = (course, person)
This way, you can guarantee unique entries in the through table, and when you reference the id it is the equivalent of referencing the unique (course, person) which is what we want anyways.
There are some third party apps that implement this feature if you want. However, unless an absolute necessity (like a legacy system support), I would just keep it simple and implement unique_together.
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
Apologies on the last question. Should have phrased it better.
I have three classes, Student and another Adult and AdultProfile. I would like to make a query such that it gets all the adults who are from US but it has to be done using Student class. This is because my queryset is Student.objects.all() and based on this queryset, i would like to get all the adults(through AdultProfile) from US . This is an example of the code while the original code much more complex and longer. This example shows the gist of the problem.
class Student(models.Model):
name = models.CharField(max_length=255)
birthday= models.DateField(blank=True,null=True)
class Adult(models.Model):
user = models.OneToOneField(User)
parent= models.ForeignKey(Student,related_name="relationships")
class AdultProfile(models.Model):
country = models.CharField(max_length=2)
adult = models.OneToOneField(Adult,related_name='profile')
Need some help in this.. Hope i have phrased it better this time...
You're not going to be able to do this from a Student queryset. The only way you will end up with Adult objects from a Student class is from a Student instance via its reverse-related-accessor: student_instance.relationships.all().
The missing ingredient in your django ORM travels is probably the fact that you can query related objects (FK, OneToOne) via its related_name (or by default, the model name).
student_qs = Student.objects.all() # some query
adults_in_us = Adult.objects.filter(parent__in=student_qs, profile__country='US')