Django - How to create many to one relation - python

In my application there is many-to-one relation, such as one teacher can teach more than one subject. So in admin panel I can't simulate it. Can't add more than one subject:
Here are my codes:
models.py:
class Subject(models.Model):
def __str__(self):
return self.name
name = models.CharField(max_length=200)
credit = models.IntegerField()
class Teacher(models.Model):
def __str__(self):
return self.name
name = models.CharField(max_length=100)
email = models.CharField(max_length=100, null=True)
chair = models.ForeignKey(Chair, on_delete=models.CASCADE)
academic_degree = models.CharField(max_length=100)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE)

You've got it reversed. ForeignKey is Many-to-One with Many being the instances of model where it is defined; you've declared ForeignKey on the Teacher model to Subject model, which means "many teachers can teach only a single subject" -- which should be the other way around.
So define the ForeignKey to the Teacher model on the Subject model. And also do the same for other similar ones.

You are doing it other way around
You should put the 'ForeighKey' relation in 'Subject' model instead of 'Teacher'
class Subject(models.Model):
def __str__(self):
return self.name
name = models.CharField(max_length=200)
credit = models.IntegerField()
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
This is assuming there is only 1 teacher for a subject. Teacher can have multiple subjects. If there are many teachers for same subject then you need to use ManyToMany() relation.

Django has extremely great support for a attribute related to many other attribute. In your case a single subject could be taught by multiple teacher and multiple teacher can teach single subject. In order to define relationship like above you can leverage ManyToMany relation(this facilate many subject getting associated with single teacher). In case you need one to Many relationship you can use ManyToOne relation.
subject = models.ManyToManyField(subject)

Related

How to Connect a Django Model with ManyToMany Relationship?

I am making an app that is pretty much similar to google classroom in django.
I have a Course model and an assignment model, and I want to connect an assignment to the specified course.
These are my models
class Assignment(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
date_created = models.DateTimeField(default=timezone.now)
class Course(models.Model):
title = models.CharField(max_length=100)
subject = models.CharField(max_length=100)
image = models.ImageField(default='no_course_image.jpg', upload_to='course_images')
owner = models.ForeignKey(User, on_delete=models.CASCADE)
students_invited = models.ManyToManyField(User, null=True, blank=True)
assignments = models.ManyToManyField(Assignment, null=True, blank=True)
date_published = models.DateTimeField(default=timezone.now)
class Meta:
verbose_name_plural = 'Course'
ordering = ['-date_published']
def __str__(self):
return '{} - {}'.format(self.title, self.owner)
But i am getting an error when I specify the course field in the assignment model with the ForeignKey!
Could you please help me with how to connect the assignment to the Course model?
Thank you
ForeignKey is used to setup a many to one relationship. As you are trying to setup a ManyToManyField it won't work in this situation as you can see in the Django documentation
ForeignKey¶
class ForeignKey(to, on_delete, **options)¶
A many-to-one relationship. Requires two positional arguments:
the class to which the model is related and the on_delete option.
In fact you don't even need to set the relation in the Assignment Model as Django will take care of creating a third table linking the two together by their primary keys. You can see this in the documentation
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
class Meta:
ordering = ['title']
def __str__(self):
return self.title
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
class Meta:
ordering = ['headline']
def __str__(self):
return self.headline
So every time you add the assignment to the course like so
>>> c1 = Course(title='Python Course')
>>> c1.save()
>>> a1 = Assignment(name='Python Assignment')
>>> a1.save()
>>> c1.assignments.add(a1)
And the relation will automatically be created and c1.assignments.all() will return all the assignments linked to the course
If you need to go the other way around then you would use a1.course_set.add(c1). When using the model that doesn't have the ManyToManyField object tied to it you need to use the *_set notation where * will be replaced by the model name in lower case. Can read more about Related Objects references in the docs here
When you try to create the Model Assignment with reference to the model Course, the Course Model has not yet created and vice versa and you will get an error either of the model is not defined
You can use the quotes for it
class Assignment(models.Model):
course = models.ForeignKey('Course', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
date_created = models.DateTimeField(default=timezone.now)
You can use a custom through model enter link description here
I guess the Course model has to be written before the Assignment model.

Django Many Users to One model. A Model about the User

I'm trying to figure out how many users can be associated with one instance of a model.
I have a sports club project. There are many users (admin and staff) only one Club. I can't seem to form a many to one relationship with the User model.
I want to filter mainly by the club.
Say if 3 clubs use the project, each club would want to be separated by the club and not by the user.
Below is a simplified version of my models.
I've also tried to add the ForeignKey to the club and go the other way.
Class Club(models.model):
name = models.CharField(max_length=40, null=True)
Class User(AbstractBaseUser):
name = models.CharField(max_length=40, null=True)
club = models.ForeignKey(Club, on_delete=models.CASCADE)
Since there is just one club but various users, I believe your model should remain like this but on the user model you can assign different roles for different users in a club
Class User(AbstractBaseUser):
name = models.CharField(max_length=40, null=True)
club = models.ForeignKey(Club, on_delete=models.CASCADE)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
You are defining your models appropriately. When you create the ForeignKey, each instance of the model that is being associated with (here your Club model) has access to the instances associating with it through a Manager object. You can define the "related_name" argument in the ForeignKey field definition so that your club objects have access to the users associated with them through a custom-defined name (rather than the default name):
Class Club(models.model):
name = models.CharField(max_length=40, null=True)
Class User(AbstractBaseUser):
name = models.CharField(max_length=40, null=True)
club = models.ForeignKey(Club, related_name="members", on_delete=models.CASCADE)
You can then access the related users with club.members.all assuming that "club" is the name of the club context object passed to the Template and "members" is the related_name of the User model's ForeignKey relation to Club. As a trivial example, if you wanted to list the members of a club, you could then do the following:
{% for member in club.members.all %}
<p>{{member.name}} is a member</p>
{% endfor %}
Check out this link for more on ForeignKey relations: https://docs.djangoproject.com/en/2.2/topics/db/queries/#following-relationships-backward

Using a django model as a field for another model?

I have been tasked with creating Django Models for a hypothetical apartment booking application.
My question is: can I use a model that I've defined, as a field in another model?
For example, I will have one model called "Listing" that represents an apartment being listed.
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
I also want to have a "Booking" model that represents an apartment once someone has booked it. It will have the exact same info as a Listing, with the addition of the username of the person who booked it. So can I have my Booking model use Listing as a field? And then just have one extra field for the booker's username.
Any other tips/critiques are highly appreciated as I am a complete beginner at Django.
I'm not 100% sure what you mean by use Listing as a field
But to me, you should be looking at the different built-in model relationships that exist in Django.
In your particular case, you will probably want to use a One-to-One relationship like so,
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
class Booking(models.Model):
listing= models.OneToOneField(
Listing,
on_delete=models.CASCADE,
)
username = models.Charfield()
Now if a user can book more than one apartment at a time, you'll be interested in a ForeignKey relationship like so,
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
class Booking(models.Model):
listing= models.ForeignKey(
Listing,
on_delete=models.CASCADE,
)
username = models.Charfield()
Note that in both examples I used Charfield for the username, feel free to use whatever Django field you need.
The concept of a model as field is odd. What you can do is establish relationships between models, or to inherit one from the other. Given your situation, you can maybe inherit Booking from Listing:
The docs on this topic.
You'll have something like this:
class Listing(models.Model):
address = models.IntegerField()
owner = models.CharField(max_length=256)
duration = models.DurationField()
price= models.IntegerField()
class Booking(Listing):
#your new fields

Python Django how to retrieve specific objects

I've got this Post model at the moment:
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
def __unicode__(self):
return self.title
If I've got different parts of a website (or a forum rather) that contain different posts, e.g. Discussion about basketball, and Discussion about football, if I wanted to return just posts concerning basketball or just posts concerning football, is the easiest way to just make a specific basketball_post model/football_post model or is there a more efficient way? Should I perhaps be storing the values differently?
Thanks
Django has a really good tutorial. It is about making a Poll app. In the first chapter the thing you want is discussed. It is about a Question that can have multiple Choices.:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
The foreignKey creates a relation between two models. The same can be done for a blog:
class Category(models.Model):
title = models.CharField(max_length=200)
class Post(models.Model):
category = models.ForeignKey(Category) # This is the important part.
title = models.CharField(max_length=200)
body = models.TextField()
date = models.DateTimeField()
def __unicode__(self):
return self.title
The ForeignKey relation lets you do really nice things:
basketball_posts = Post.objects.filter(category_title='Basketball')
But before we all tell you how it is done, I really recommend to do the tutorial. It introduces you to all important Django concepts: https://docs.djangoproject.com/en/1.7/intro/tutorial01/
Update
If you have a fixed set of categories that are not likely to change, than you can hardcode them and use field choices:
class Post(models.Model):
FOOTBALL = 'F' # Variable name and db_value
CRICKET = 'C'
INTRODUCTION = 'I'
CATEGORY_CHOICES = (
(FOOTBALL, 'Soccer'), # Variable name and display value
(CRICKET, 'Cricket'),
(INTRODUCTION, 'Hello my name is'),
)
category = models.CharField(max_length=1,
choices=CATEGORY_CHOICES,
default=INTRODUCTION)
...
https://docs.djangoproject.com/en/dev/ref/models/fields/#choices
One of the advantages of this 'choice machinery' over a CharField without pre defined choices is that you are sure what values end up in your database. This lets you query them, without worrying if your data is sane:
Post.objects.filter(category=Post.CRICKET)
Use the extra table if you need the freedom to create new categories in the future. Use field choices if you don't want (or need) that freedom.
I would suggest to just add a field which makes the post relevant to that certain topic:
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
type = models.CharField(max_length=20) #<--- new field: e.g 'basketball','hockey'..
def __unicode__(self):
return self.title
example query:
#basketball posts
qs = Post.objects.filter(type__icontains="basketball")
then you dont need to have multiple models which also would be redundant.
Assuming all of the posts are in the same format, you could add another field to your model like "type". Different discussion forums could send a different values for that field when the post is added.
type = models.CharField(max_length=140, choices=['Football', 'Basketball', 'Baseball'])
Storing this would make it easy to filter which posts are which.
Post.objects.filter(type = 'Football')
Assuming that one post can be about only one sport, the better approach would be to have a foreign key relation between a model that stores data about a post with another model that stores the data about sports.
Something like this
class Sport(models.Model):
name = models.CharField(max_length = 200)
description = models.TextField()
def __unicode__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
sport = models.ForeignKey(Sport)
def __unicode__(self):
return self.title
This gives you the advantage of isolating the 'Sport' and the 'Post' models.You can add as many sports as you want, without any posts referring to it.
One more advantage is that you can add relevant information to the relevant models.
Eg:Suppose you want to add the information about "how many players are there in a team for sport x?". You can easily achieve this by adding a field "number_of_players" in the 'Sport' model without affecting the 'Post' model.
If you had to do this in one model, 'Post', then it would create lot of issues in terms of data consistency and other undesirable things.
Also, the query will look something like this:
posts = Post.objects.filter(sport__name = "Basketball")
PS:If your requirement is that a post can be tagged to multiple sports, then you can use ManyToMany field instead of a simple foreign key.
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/
You could assign your posts tags or category, and filter on those.
If you use the model approach what happens when you add more sports? You'll need manually add the sports in your code, using a tags or category approach allows you to handle it in the db, and would then allow you to filter on the tags/categories in your system

Query ManyToMany relations without a named through field

I have this setup in my models:
class Author(models.Model):
name = models.CharField(max_length=100)
class Topic(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author, null=True, blank=True)
topics = models.ManyToManyField(Topic, null=True, blank=True)
Given an author, I want to know which topics he wrote about:
def author_info(request, pk):
author = get_object_or_404(Author, pk=pk)
topics = ????
If I had specified a through field, I could use that, but now Django makes the through field for me, and since its supposed to be transparent, Id rather not reference the field (unless there is a proper Django construction for that).
Use Lookups that span relationships:
topics = Topic.objects.filter(article__authors=author).distinct()
Note: you have to use distinct here, because the same topic can be selected by different articles.

Categories