I have two models named Profile and Controversy. My requirement is many people can be involved in a controversy and a single person can have multiple Controversies. With that said, I feel like I should a ManyToMany field in both the models but I'm guessing that violates ManyToMany fields documentation as it should be used in only model.
my models are as follows :
class Profile(models.model):
name = models.CharField(max_length=200)
Controversy = models.ManyToManyField(Controversy) # As one person can have multiple controveries
class Controversy(models.Model):
year = models.Datefield()
other_people_involved = models.ManytoManyField(profile) # As multiple people can be involved in a controversy
description = models.TextField()
This obviously will throw error.
I'm not able to understand as to how to tackle such a scenario
You can try this way:
Create another model to store the person and controvery connection.
class Profile(models.model):
name = models.CharField(max_length=200)
class Controversy(models.Model):
year = models.Datefield()
description = models.TextField()
class PeopleInvolved(models.Model):
controversy = models.ManyToManyField(Controversy)
person = models.ManytoManyField(profile)
So to list the controversies of a person do this:
controversies = [i.controversy for i in PeopleInvolved.objects.filter(person=[profile_id])] #pass the profile id of the person.
And to list the people involved in a controversy do this:
peoples = [i.person for i in PeopleInvolved.objects.filter(controversy=[controversy_id])] #pass the controversy id.
Related
Imagine there are three models named Movie, Actor, and Participation.
class Movie(models.Model):
identifier = models.CharField()
class Actor(models.Model):
name = models.CharField()
class Participation(models.Model):
movie_identifier = models.CharField()
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Let's assume that I can't use ForgeinKey for the movie in the Participation model.
how can I retrieve all the participation records of a movie with only one query?
Here is the solution if I had a foreign key for the movie in the participation table:
qs = Movie.objects.filter(identifier="an_identiier").prefetch_related("participations_set")
How can I do this without having a Movie foreign key in the Participation model?
Thanks!
One of the most important things when designing a database (hence when designing your models) is database normalization [Wikipedia].
You talk about Participation being related to multiple models like Movie, Series, Episode, etc. this means that Movie, Series, Episode all can be said to have something in common or they can be said to be a specialization of another entity let us say Participatable for the lack of a better word, or we can say Participatable is a generalization of Movie, Series, Episode, etc.
How do we model these? Well we will just have an extra model that our other models will have a OneToOneField with:
class Participatable(models.Model):
# Any common fields here
MOVIE = 'M'
SERIES = 'S'
TYPE_CHOICES = [
(MOVIE, 'Movie'),
(SERIES, 'Series'),
]
subject = models.CharField(max_length=1, choices=TYPE_CHOICES)
class Movie(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='movie',
)
class Series(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='series',
)
class Participation(models.Model):
participatable = models.ForgeinKey(Participatable, on_delete=models.CASCADE)
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Other than this solution which I find is the best for such modelling you can go with using the content-types framework which will essentially do what you do currently. That is it will use a field that stores the related id and also a foreign key that points to an entry in a table that will simply describe which table this id is for.
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.
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.
Well, this is the problem, I have a username column and I defined it in the models.py.
And a user may take some courses( the course may changes in the future), the relation between user and courses is 1 vs multi, which means a user can take multi courses and a courses could be taken by several users.
I am new to django and DB design, how to represent this in Django with ORM?
def user(models.Model):
name = models.CharField(max_length=30)
class courses(models.Model):
course = models.CharField(max_length=100)
Following #djsutho thought, define a many-to-many relationship:
class user(models.Model):
name = models.CharField(max_length=30)
courses = models.ManyToManyField(courses)
class courses(models.Model):
course = models.CharField(max_length=100)
Then, for example, querying courses per user would be as easy as:
courses.objects.filter(user__name='Bob')
Also note that, by Django model naming convention, model class names should start with a upper case letter: user should be User, courses - Courses.
Also note that the model name should not be in a plural form - better name courses as Course. Also better rename course field to name.
So, finally, here's the picture:
class User(models.Model):
name = models.CharField(max_length=30)
courses = models.ManyToManyField(Course)
class Course(models.Model):
name = models.CharField(max_length=100)
Hope that helps.
I'm learning Django and trying to get the hang of querying foreign keys across a bridging table. Apologies if this is a duplicate, I haven't been able to find the answer by searching. I've got models defined as follows
class Place(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
class PlaceRef(models.Model):
place = models.ForeignKey(Place) # many-to-one field
entry = models.ForeignKey(Entry) # many-to-one field
class Entry(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=10)
If I want to retrieve all the Entries associated with a particular Place, how do I do it?
place = get_object_or_404(Place, id=id)
placerefs = PlaceRef.objects.filter(place=place)
entries = Entry.objects.filter(id.....)
Also, if there is a more sensible way for me to define (or get rid of) PlaceRefs in Django, please feel free to suggest alternatives.
Thanks for helping out a beginner!
First, I'd suggest rewriting the models to:
class Place(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
class Entry(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=10)
places = models.ManyToManyField(Place, related_name='places')
So you can query:
Entry.objects.filter(places__id=id)
In your current model:
Entry.objects.filter(placeref_set__place__id=id)
Note that the double underscore __ is used to jump from one model to the next. Also, django creates some fields on the model that help you navigate to related objects. In this example: Entry.placeref_set. You can read more about it here:
http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward