Django Models - Create ManyToManyField that connects to the members of a group - django

I have these models: Users, Grades, Groups, Projects, Tasks.
Every Grade, has Users (that can be student or teacher). The teacher can create groups of students. How do I create a ManyToManyField that connects to the specific users of that Grade?
Right Now when I try to make a group, it inherits from Grades and I get EK17A, TE17A (Note that i want to get the users in EK17A, or the users in EK17A)
This is so the teacher can put the students into project groups :D
from django.db import models
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
age = models.IntegerField()
description = models.CharField(max_length=300)
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'User Profiles'
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_data(sender, update_fields, created, instance, **kwargs):
if created:
user = instance
profile = UserProfile.objects.create(user=user, is_teacher=False, is_student=True, age=18, description='No Description')
class Grades(models.Model):
name = models.CharField(max_length=10)
members = models.ManyToManyField(UserProfile, blank=True)
class Meta:
verbose_name_plural = 'Grades'
def __str__(self):
return self.name
class TeacherProjectTask(models.Model):
title = models.CharField(max_length=150)
description = models.CharField(max_length=1000, blank=True)
state = models.CharField(max_length=20)
class Meta:
verbose_name_plural = 'Tasks'
def __str__(self):
return self.title
class TeacherProject(models.Model):
title = models.CharField(max_length=150)
description = models.CharField(max_length=1000)
tasks = models.ManyToManyField(TeacherProjectTask, blank=True)
grade = models.OneToOneField(Grades, blank=True, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = 'Projects'
def __str__(self):
return self.title
class ProjectGroup(models.Model):
title = models.CharField(max_length=150)
description = models.CharField(max_length=1000)
members = models.ManyToManyField(Grades, blank=True)
class Meta:
verbose_name_plural = 'Group'
def __str__(self):
return self.title

Related

How to create model allowing infinite submodels in django?

Im creating a site where you can write down your goals, you should be able to split every goal into subgoals if chosen, and allow those subgoals to be split into subgoals infinitely.
This code below shows what i came up with first for the models, the first model is for creating a goal, the second model can either either be a subgoal of the goal or a subgoal of the subgoal.
But it seems like a really bad way to go around this problem.
Django semi-newbie BTW...
from django.db import models
from django.contrib.auth.models import User
class Goal(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
title = models.CharField(max_length=70, null=True)
content = models.TextField(blank=True)
slug = models.SlugField(max_length=50, editable=False)
date_created = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
unique_together = ['user', 'title']
def __str__(self):
return self.user.username + " - " + self.title
def save(self, *args, **kwargs):
self.slug = self.title.replace(' ', '-').lower()
super(Goal, self).save(*args, **kwargs)
class SubGoal(models.Model):
goal = models.ForeignKey(
Goal, on_delete=models.CASCADE, null=True, blank=True)
parent = models.ForeignKey(
"SubGoal", on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=70)
content = models.TextField(blank=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
try:
return self.goal.title + " - " + self.title
except:
return self.parent.title + " - " + self.title
You can make a ForeignKey to self. If the ForeignKey is NULL, then that goal has no parent, otherwise it refers to the parent:
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
django.utils.text import slugify
class Goal(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=70)
content = models.TextField(blank=True)
slug = models.SlugField(max_length=50, editable=False)
date_created = models.DateTimeField(auto_now_add=True)
parent = models.ForeignKey(
'self',
on_delete=models.SET_NULL,
null=True,
default=None,
related_name='subgoals'
)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'title'], name='user_title')
]
def __str__(self):
if self.parent_id is None:
return '{}-{}'.format(self.user.username, self.title)
else:
return '{}-{}'.format(str(self.parent), self.title)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Goal, self).save(*args, **kwargs)
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Not getting foreign key data in django api views

Currently I have a site, and I want the user to be able to view their liked articles. I want this to be included in the user api view that is already set up. I have tried the tracks = serializers.StringRelatedField(many=True)that is in the drf docs yet this didn't work. I have also tried the following:
from rest_framework import serializers
from articles.models import Article, CustomUser,FavoriteArticles
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('title', 'content')
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = '__all__'
class FavoriteArticleSerializer(serializers.ModelSerializer):
class Meta:
model = FavoriteArticles
fields = '__all__'
class UserProfileSerializer(serializers.ModelSerializer):
fav_title = FavoriteArticleSerializer(read_only=False)
class Meta:
model = CustomUser
fields = 'username, git, email, fav_article, fav_title, homepage'
and my models:
from django.db import models
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save
from django.dispatch import receiver
import uuid
class ProgrammingLanguage(models.Model):
programming_language = models.CharField(max_length=120, null=False, primary_key=True, default="React")
def __str__(self):
return self.programming_language
class Article(models.Model):
title = models.CharField(max_length=25, primary_key=True)
content = models.TextField()
usedfor = models.TextField()
url=models.CharField(max_length=200, null=True)
article_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="article_programming_language", default="react")
score = models.IntegerField(max_length=5, null=0)
def __str__(self):
return self.title
class CustomUser(AbstractUser):
username = models.CharField(max_length=50, unique=True, primary_key=True)
git = models.CharField(max_length=200, null=True)
homepage = models.CharField(max_length=250, null=True)
user_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="most_used_programming_language", default="react")
def __str__(self):
return str(self.username)
class FavoriteArticles(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
fav_title = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='fav_title')
reasons_liked = models.CharField(max_length=120, null=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name="user", default="tom" )
def __unicode__(self):
return '%s: %s' % (self.fav_title, self.reasons_liked)
I think you misunderstood what related_name means. It specifies how you would access a model from its reverse relationship. So I'd recommend you remove it from fields in your FavoriteArticles model and use the default Django already provides (in this case favoritearticles_set):
class FavoriteArticles(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
fav_title = models.ForeignKey(Article, on_delete=models.CASCADE)
reasons_liked = models.CharField(max_length=120, null=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, default="tom")
def __unicode__(self):
return '%s: %s' % (self.fav_title, self.reasons_liked)
This way, you can access favorite articles of a user via my_user.favoritearticles_set.all(). Then, you can change your UserSerializer to include a liked_articles field which is populated from the favoritearticles_set reverse relationship to a user's FavoriteArticles using a source attribute:
class UserSerializer(serializers.ModelSerializer):
liked_articles = FavoriteArticleSerializer(source='favoritearticles_set', many=True, read_only=True)
class Meta:
model = CustomUser
# explicitly include other fields as required
fields = ('username', 'git', 'user_programming_language', 'liked_articles')
Note that we've made this a read_only field, so it will only get populated if you perform a GET request.

Django - Return full_name from Profile model which has relation with Django User model in other model

I created Book, Book_stat a Profile model which has relation with Django User Model, i am trying to display Book title and full_name from Profile as default str return string from Book_stat
models.py
from django.db import models
from django.contrib.auth.models import User
from decimal import Decimal
# Create your models here.
class Book(models.Model):
title = models.CharField(max_length=200)
def __str__(self):
return self.title
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
full_name = models.CharField(max_length=150)
def __str__(self):
return self.full_name
class Book_stat(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
rating = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal('0.00'))
like = models.BooleanField(default=False)
def __str__(self):
return self.book.title # here i would like to return book title + full_name from Profile Model
admin.py
from django.contrib import admin
from .models import Book, Book_stat, Profile
# Register your models here.
admin.site.register(Book)
admin.site.register(Book_stat)
admin.site.register(Profile)
When i click on Book_stat in my django admin page i would like to display Book title and Profile full_name as title's in my Book_stat list
def __str__(self):
return self.book.title +' '+ self.user.profile.full_name
try this hope you will get it
Try this:
In your Profile model add related_name like this:
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
full_name = models.CharField(max_length=150)
def __str__(self):
return self.full_name
And in your BookStat model:
class Book_stat(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
rating = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal('0.00'))
like = models.BooleanField(default=False)
def __str__(self):
return self.book.title + " - " + self.user.profile.full_name
class Book_stat(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
rating = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal('0.00'))
like = models.BooleanField(default=False)
def __str__(self):
return str(self.book.title) + " : " + str(self.user.get_full_name()) ## changes done here

Field related to field of related object Django

How can i make field related to field of related model. I have two models: album and photo, album model have boolean field private. How to create field private in photo, which will have False value if album field equal to None and value of album private field if it's not.
models.py:
from django.db import models
from django.contrib.auth.models import User
import os
import uuid
def get_image_path(instance, filename):
return '{}.{}'.format(uuid.uuid4(), filename.split('.')[-1])
class Album(models.Model):
user = models.ForeignKey(User, related_name='albums', on_delete=models.CASCADE)
title = models.CharField(max_length=80, default='New album')
creation_date = models.DateField(auto_now_add=True)
private = models.BooleanField(default=False)
def __str__(self):
return self.title
class Meta:
ordering = ['-creation_date', ]
class Photo(models.Model):
user = models.ForeignKey(User, related_name='photos', on_delete=models.CASCADE)
album = models.ForeignKey(Album, related_name='photos', on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=80, default='New photo')
image = models.ImageField(title, upload_to=get_image_path)
creation_date = models.DateField(auto_now_add=True)
# ???
private = models.BooleanField()
# ???
def __str__(self):
return self.title
class Meta:
ordering = ['-creation_date', ]
As #RodXavier said just use property
class Photo(models.Model):
user = models.ForeignKey(User, related_name='photos', on_delete=models.CASCADE)
album = models.ForeignKey(Album, related_name='photos', on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=80, default='New photo')
image = models.ImageField(title, upload_to=get_image_path)
creation_date = models.DateField(auto_now_add=True)
#property
def private(self):
return getattr(self, 'album', False)

Django Model design for a basic inventory application

I am new to Django (and databases for that matter) and trying to create a simple inventory application to help learn. I've been through the tutorials and am going through some books, but I am stuck at what i think is simple, just not sure where to look or how to ask.
With an inventory application, you have your equipment which then has a manufacturer, which the equipment has a model number that only that manufacturer has. Lets say Dell Optiplex 3040. I am also using the admin console right now as well. So i would like to be able to relate equipment to a manufacturer and then also relate the equipment to the model number. It almost seems as I am needing to use the many to many field and the through field to accomplish what I am trying to do but I dont think that is the right way to do it (shown in the link below). https://docs.djangoproject.com/en/1.9/topics/db/models/#many-to-many-relationships
Below is the code I have so far. Thank you.
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
equipmentModel = models.CharField(max_length=50)
def __str__(self):
return self.equipmentModel
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
***Edit to add the updated code and the admin.py code in response question I had to answer.
#admin.py
from django.contrib import admin
# Register your models here.
from .models import Device,Department,Manufacturer,Employees, Job_Positions, EquipmentModel
class DeviceModelAdmin(admin.ModelAdmin):
list_display = ["ip", "department","model","serial_number","date_updated"]
list_filter = ["department","model","ip"]
search_fields = ["ip"]
class Meta:
model = Device
class EmployeesModelAdmin(admin.ModelAdmin):
list_display = ["employee_name_first", "employee_name_last", "employee_username", "phone"]
list_filter = ["department"]
class Meta:
model = Employees
admin.site.register(Device, DeviceModelAdmin)
admin.site.register(Department)
admin.site.register(Manufacturer)
admin.site.register(EquipmentModel)
admin.site.register(Employees, EmployeesModelAdmin)
admin.site.register(Job_Positions)
updated models.py
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
model_number = models.CharField(max_length=50)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
def __str__(self):
return self.model_number
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE,null=True)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
A many-to-many relationship is not what you want here, because any piece of equipment (I assume) can only have one manufacturer.
You do need an intermediate model which stores the model information, and you already have one in your EquipmentModel. I would suggest modifying it as follows:
class EquipmentModel(models.Model):
# This stores information about a particular model of device
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
model_number = models.CharField(max_length=50)
And then instead of having a foreign key to the manufacturer in Device, replace it with a foreign key to the equipment model:
class Device(models.Model):
# ...
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE)