When you want add relation Many to one relation between models, Django provides ForeignKey. Take a look at simple example. Each clubteam has a owner and owner can be own a several clubteam (depending on his budget).
owner is associated to user class
class clubteam(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, default = 1)
When you add model about player and each player belong to one clubteam.
Standard foreign key
python manage.py startapp player
from __future__ import unicode_literals
from django.conf import settings
from django.db import models
from club.models import clubteam
class Player(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
clubteam = models.ForeignKey(clubteam)
Age = models.PositiveIntegerField()
def __str__(self):
return str(self.user.username)
def __unicode__(self):
return str(self.user.username)
official link
https://docs.djangoproject.com/en/1.10/ref/contrib/contenttypes/
Generic Foreign Key
from __future__ import unicode_literals
from django.conf import settings
from django.db import models
from club.models import clubteam
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Player(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Age = models.PositiveIntegerField()
def __str__(self):
return str(self.user.username)
def __unicode__(self):
return str(self.user.username)
Here model.CASCADE means when the parent model is deleted, the child model is also instantly deleted.
when you want to show some players list in a specific clubteam, Here is a solution for that.
from django.shortcuts import render
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404
from player.models import Player
from club.models import clubteam
def player_viewr(request, clubteam_id = None):
instance = get_object_or_404(clubteam, clubteam_id)
content_type = ContentType.objects.get_for_model(Player)
obj_id = instance.id
players=Player.objects.filter(content_type=content_type, object_id = obj_id)
context = {
"instance": instance,
"players": players
}
return render(request, "player_list.html", context)
The first thing, you need specific id for the clubteam, and check if that exist by instance = get_object_or_404(clubteam, clubteam_id)
content_type = ContentType.objects.get_for_model(Player)
This is for grabbing the specific type of contenttype and this is going to be feed to objects.filter, because the player models has the foreignkey of contenttype. And by the obj_id, player is filtered to some players who belong to specific clubteam.
Now we need to add something like this to the rendered html.
{% for player in players%}
<div>
{{player.user.username}} | {{player.age}}
</div> </hr>
{% endfor %}
More sophisticated way to code generic foreign key
The fuct that whenever you want to grab player list, you need to code these line is not elegant way to code. Now is the time to add model manager.
from __future__ import unicode_literals
from django.conf import settings
from django.db import models
from club.models import clubteam
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class PlayerManager(models.Manager):
def filter_by_clubteam(self, instance):
content_type = ContentType.objects.get_for_model(instance.__class__)
#content_type = ContentType.objects.get_for_model(Player)
qs = super(PlayerManager, self).filter(content_type=content_type, object_id = instance.id)
return qs
class Player(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Age = models.PositiveIntegerField()
object=PlayerManager()
def __str__(self):
return str(self.user.username)
def __unicode__(self):
return str(self.user.username)
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from player.models import Player
from club.models import clubteam
def player_viewr(request, clubteam_id = None):
instance = get_object_or_404(clubteam, clubteam_id)
players=Player.objects.filter_by_clubteam(instance)
context = {
"instance": instance,
"players": players
}
return render(request, "player_list.html", context)
The other way to grab player list.
from __future__ import unicode_literals
from django.conf import settings
from django.db import models
from player.models import Player
# Create your models here.
class clubteam(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default = 1)
@property
def playerlist(self):
instance = self
return Player.object.filter_by_clubteam(instance)
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from player.models import Player
from club.models import clubteam
def player_viewr(request, clubteam_id = None):
instance = get_object_or_404(clubteam, clubteam_id)
players=instance.playerlist
context = {
"instance": instance,
"players": players
}
return render(request, "player_list.html", context)
Create childkey form
from __future__ import unicode_literals
from django.conf import settings
from django.db import models
from player.models import Player
from django.contrib.contenttypes.models import ContentType
# Create your models here.
class clubteam(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default = 1)
@property
def playerlist(self):
instance = self
return Player.object.filter_by_clubteam(instance)
@property
def get_content_type(self):
instance = self
content_type = ContentType.objects.get_for_model(instance.__class__)
return content_type
from django import forms
class PlayerForm(forms.Form):
content_type = forms.CharField(widget=forms.HiddenInput)
object_id = forms.IntegerField(widget=forms.HiddenInput)
age = forms.IntegerField()
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
from player.models import Player
from club.models import clubteam
from player.forms import PlayerForm
def player_viewr(request, clubteam_id = None):
instance = get_object_or_404(clubteam, clubteam_id)
players=instance.playerlist
initial_data = {
"content_type":instance.get_content_type,
"object_id":instance.id
}
player_enroll = PlayerForm(request.POST or None, initial = initial_data)
if player_enroll.is_valid():
c_type = player_enroll.cleaned_data.get("content_type")
content_type = ContentType.objects.get(model=c_type)
obj_id = player_enroll.cleaned_data.get("object_id")
age_data = player_enroll.cleaned_data.get("age")
new_player, created = Player.objects.get_or_create(
user = request.user,
content_type=content_type,
object_id = obj_id,
age = age_data,
)
context = {
"instance": instance,
"players": players,
"player_enroll":player_enroll,
}
return render(request, "player_list.html", context)
<form method = "POST" action=".">
{% csrf_token %}
{{ player_enroll }}
<input type="submit" value="Enroll">
</form>