I have a model in django, in which there will be several roles - regular user, admin and manager. Each of them will be able to do something else. Is the following model OK to work correctly?
class Team(models.Model):
name = models.CharField('Name', max_length=128)
users = models.ManyToManyField(User)
admins = models.ManyToManyField(User)
managers = models.ManyToManyField(User)
def __str__(self):
return self.name
This might work. If the number of roles is large, or dynamic (as in roles can be added, removed, renamed, updated). You could introduce a ternary relation, like:
from django.conf import settings
class Role(models.Model):
name = models.CharField(max_length=128)
class Team(models.Model):
name = models.CharField('Name', max_length=128)
members = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.PROTECT)
Related
I'm doing a cookbook app, which help users find meal thay can do with their ingridients. I'm using Django RestFramework, and i need to return list of avaliable meals that user can do, but don't know how to do search by ingridients
My models.py:
#models.py
class Meal(models.Model):
name = models.CharField(max_length=250)
description = models.TextField(blank=True, null=True)
recipe = models.TextField()
is_published = models.BooleanField(default=False)
category = ForeignKey('Category', on_delete=models.CASCADE, null=True)
user = ForeignKey(User, verbose_name='User', on_delete= models.CASCADE)
difficulty = ForeignKey('Difficulty', on_delete=models.PROTECT, null=True)
ingridients = models.ManyToManyField('Ingridient')
class Ingridient(models.Model):
name = models.CharField(max_length=100, db_index=True)
ico = models.ImageField(upload_to="photos/%Y/%m/%d/", blank=True, null=True)
category = ForeignKey('CategoryIngridients', on_delete=models.CASCADE, null=True)
def __str__(self):
return self.name
class CookBookUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
ingridients = models.ManyToManyField('Ingridient')
serializer.py
class MealSerializer(serializers.ModelSerializer):
class Meta:
model = Meal
fields = "__all__"
views.py
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
return Meal.objects.filter(ingridients=CookBookUser.objects.filter(user_id = self.request.user.id).ingridients)
CraftWithUsersIngridientsListAPIView isn't working and I get AttributeError 'QuerySet' object has no attribute 'ingridients', can someone help fix this?
I tried building different serializer but it doesn't help
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
user_ingredients = CookBookUser.objects.get(user=self.request.user).ingredients.all()
return Meal.objects.filter(ingredients__in=user_ingredients)
This way, you first get the CookBookUser instance for the current user, then get all of their ingredients, and finally, filter the Meal objects that contain those ingredients. The __in query lookup is used to check if the meal ingredients are in the user's ingredients.
I am following the example in the documentation: https://docs.djangoproject.com/en/3.2/topics/db/models/#extra-fields-on-many-to-many-relationships
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
In this case, given a Person object, how can I access all the groups that Person is in?
You access these with:
Group.objects.filter(members=my_person_object)
i'm working on a project the scenario : teachers can make course and publish it in Course model and also institute can make course in Course model?
how can i make it automatically choose one of the foreign key fields?
both institutes and teacher can have post
class Institute(models.Model):
courses = GenericRelation(Course)
institute_name = models.OneToOneField(CustomUser,on_delete=models.CASCADE)
institute_id = models.SlugField(unique=True,default=slug_generator(),blank=True)
phone_number = models.CharField(max_length=11)
locations = models.OneToOneField(Location,on_delete=models.DO_NOTHING,default='')
institute_name.is_institute = True
pass...
def __str__(self):
return self.institute_name.username
class Teacher(models.Model):
course = GenericRelation(Course)
teacher = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
teacher_slug = models.SlugField(unique=True,default=slug_generator())
phone_number = models.CharField(max_length=11,default='')
teacher.is_teacher = True
certification = models.ForeignKey(Certification,on_delete=models.CASCADE, blank=True,null=True)
def __str__(self):
return self.teacher.username
class CustomUser(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
is_institute = models.BooleanField(default=False)
email = models.EmailField(unique=True)
objects = UserManager()
def __str__(self):
return self.username
class Student(models.Model):
student = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
student.is_student = True
student_slug = models.SlugField(unique=True,default=slug_generator())
def __str__(self):
return self.student.username
Then define:
if user loggedin in user.is_institute
So querying in institute model
else loggedin in user.is_teacher
And then will work on teacher model.
Does this structure fine ?
I've heard that generic foreign keys not working with API
i also tried this , but i dont how to query them
class Course(models.Model):
course_name = models.CharField(max_length=20)
tags = models.ManyToManyField(Category)
time_created = models.DateTimeField(auto_now_add=True)
content_type = models.ForeignKey(ContentType , on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type','object_id')
def __str__(self):
return self.course_name
from django.contrib.contenttypes.models import ContentType
Teacher ,Institute have different fields name
Thanks
I don't think that GenericRelation is something you really need for this.
How about change the structure a little bit. Let's have Course as the main model for the task.
For example
class Course(models.Model):
teacher = models.ForeignKey(Teacher, related_name='courses', on_delete=models.CASCADE, null=True, blank=True)
institute = models.ForeignKey(Institute, related_name='courses', on_delete=models.CASCADE, null=True, blank=True)
# other necessary fields
#property
def is_teacher(self):
return self.teacher is not None
#property
def is_institute(self):
return self.institute is not None
After that you can check if Course is made by institute like
if course_object.is_teacher:
But if you really want to differentiate your users by institute or teacher you'd need to make custom user model, here's the starting point for you https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project
In that case in your Course model you'd have only one field something like author = models.ForeignKey(User, related_name='courses', on_delete=models.CASCADE)
Hope I've got your question right.
I need two Django models: first with Users, second with Projects.
Between them I need many-to-many relationship with an additional field(s).
How to make the below code working?
from django.db import models
class User(models.Model):
name = models.CharField('Name', max_length=50)
projects = models.ManyToManyField(Project, through='UserProjects')
def __str__(self):
return self.name
class Project(models.Model):
name = models.CharField('Name', max_length=50)
users = models.ManyToManyField(User, through='UserProjects')
def __str__(self):
return self.name
class UserProjects(models.Model):
user = models.ForeignKey(User)
project = models.ForeignKey(Project)
is_active = models.BooleanField('Active')
At the end User.projects should return Projects for specified User
and in the same way Project.users should return Users for specified Project.
There's no need to put the m2m field on both sides
Jussi pick one, and Django will automatically create a reverse relationship for the other direction.
from django.db import models
class User(models.Model):
name = models.CharField('Name', max_length=50)
def __str__(self):
return self.name
class Project(models.Model):
name = models.CharField('Name', max_length=50)
users = models.ManyToManyField(User, through='UserProjects', related_name='projects')
def __str__(self):
return self.name
class UserProjects(models.Model):
user = models.ForeignKey(User)
project = models.ForeignKey(Project)
is_active = models.BooleanField('Active')
Here is the simplest solution in my opinion:
from django.db import models
class User(models.Model):
name = models.CharField('Name', max_length=50)
class Project(models.Model):
name = models.CharField('Name', max_length=50)
class UserProjects(models.Model):
user = models.ForeignKey(User, related_name='projects')
project = models.ForeignKey(Project, related_name='users')
is_active = models.BooleanField('Active')
In above User.projects returns Projects for specified User and also Project.users returns Users for specified Project.
I'm trying to use a ManyToMany relationship and it is giving me the following error:
NameError: name 'ManyToManyField' is not defined
Background: Building a to do app where users have (many) projects, projects have (many) lists of tasks and projects have (many) tags that characterise them.
Here is my models.py, any help catching the error would be greatly appreciated.
from django.db import models
from django.contrib.auth.models import User
#Not sure if I need the ID's. They may be superfluous. Ask in the lab today.
#Used to list collaborators on projects and track friends lists
#Borrowed from http://stackoverflow.com/a/1113039/1254402
class SeparatedValuesField(models.TextField):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
self.token = kwargs.pop('token', ',')
super(SeparatedValuesField, self).__init__(*args, **kwargs)
def to_python(self, value):
if not value: return
if isinstance(value, list):
return value
return value.split(self.token)
def get_db_prep_value(self, value):
if not value: return
assert (isinstance(value, list) or isinstance(value, tuple))
return self.token.join([unicode(s) for s in value])
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
class UserProfile(models.Model):
user_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
user = models.OneToOneField(User)
# The additional attributes we wish to include.
first_name = models.CharField(max_length=64)
surname = models.CharField(max_length=64)
friends = SeparatedValuesField()
picture = models.ImageField(upload_to='profile_images', blank=True)
projects = models.ManyToManyField('Project')
# This line is required. Links UserProfile to a User model instance.
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
#Project model.
#Attributes = name, website, team members
#Many users can have many projects
class Project(models.Model):
project_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
name = models.CharField(max_length=128)
description = models.CharField(max_length=300)
website = models.URLField(blank=True)
team_members = SeparatedValuesField()
class List(models.Model):
#Many lists belong to one project
project = models.ForeignKey(Project)
tasks = ManyToManyField('Task')
name = models.CharField(max_length=128)
colour = models.CharField(max_length=10)
#NOTE! - Abstracting the tags (category, progress and priority) to project level.
class Task(models.Model):
#Many tasks belong to one list
belong_to_list = models.ForeignKey(List)
#Unique id for task
task_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
#Standard title & description
title = models.CharField(max_length=100)
description = models.CharField(max_length=300)
#NOTE! - Abstracting the tags (category, progress and priority) to project level.
class Tag(models.Model):
project = models.ForeignKey(Project)
#UUID
task_id = models.CharField(max_length=100, null=True, blank=True, unique=True)
#User assigns each tag a colour. hex code.
colour = models.CharField(max_length=10)
In List, you are referring to ManyToManyField without referencing it via models as you do with all the other fields.
Note that the error message would have told you exactly where the problem was, so that you wouldn't have needed to post all the other irrelevant code.