Fetching objects in complex through relationship Django - python

I have been trying numerous things to solve the following in Django object filtering but thus no luck.
Utalizing a primary key for an individual, I would like to build an object list of all their milestones.
My models are laid out as such:
TEAM MEMBER -- owns many tasks through --> OWNER -- -- > TASKS -- each task has multiple milestones --> MILESTONES
The models are shown below:
class TeamMember(models.Model):
member_name = models.CharField(max_length=140)
email = models.EmailField()
task= models.ManyToManyField(Task, through='Owner')
class Owner(models.Model):
teammember = models.ForeignKey(TeamMember, on_delete=models.CASCADE)
task = models.ForeignKey(Task, on_delete=models.CASCADE)
class Task(models.Model):
task_name = models.CharField(max_length=140)
task_description = models.TextField(null=True, blank=True)
last_updated = models.DateTimeField(null=True, blank=True)
class Milestone(models.Model):
name = models.CharField(max_length=140)
task= models.ForeignKey(Task, on_delete=models.CASCADE)
expected_date = models.DateTimeField()
The following doesnt work for me:
Milestones.objects.filter(teammember__id)
Any ideas?

You need to use multiple double.underscore steps. Actual code depends on your exact model and field names.
Something like:
Milestones.objects.filter(task__owner__teammember__id=1)

I you want to get milestone data for a particular member , you can get it by defining the fields in value queryset as follows:
TeamMember.objects.filter(id=1).values
('task__milestone','owner__task__milestone',
'task__milestone__expected_date','task__milestone__name')
I did not test it , but surely it will get all the related information.

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 ModelForm for Multiple Categories of a Product in EAV data model

Hello all I am making auction website like ebay, I have this model design which has many other extra attributes model classes for different categories. But here let's take an example of a PC one which will be used for its sub-categories Desktop and Laptop.
Now the problem, I want to create ModelForm for users. For instance if user selects Desktop as their product to put on auction, how will that modelform code look like? So the Desktop respected fields are given to the user to fill from the extra_pc_attributes class? The problem is that, wouldn't it get tedious to write separate modelform for each category and also in the views.py use those as objects.
Maybe use Jsonfield instead of creating a whole EAV old-fashioned table for extra attributes? But I am new and I don't know how it will work or even if it applies to this situation.
class Categories(MPTTModel):
name = models.CharField(max_length=50, unique=True)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
class auction_product(models.Model):
product_name = models.CharField(max_length=64)
category = models.ForeignKey(Categories, on_delete=models.CASCADE)
date_added = models.DateField(default=timezone.now)
user = models.ManyToManyField(User, through='product_ownership', related_name='product_user')
product_bid = models.ManyToManyField(User, through='bid', related_name='product_bid')
product_comment = models.ManyToManyField(User, through='comment')
album = models.OneToOneField(ImageAlbum, related_name='product_model', on_delete=models.CASCADE)
def __str__(self):
return self.product_name
#Extra PC Attributes
class extra_pc_attributes(auction_product):
processor = models.CharField(max_length=264)
ram = models.FloatField()
brand = models.CharField(max_length=64)
motherboard = models.CharField(max_length=264)
case = models.CharField(max_length=264)
screen_size = models.FloatField()
weight = models.FloatField()

Is there any way to select a value dynamically for a model's related field in runtime?

I want to achieve a functionality, where I need to select a django model (e.g from a drop down list), and after selecting one, all the objects of that model shows up.
class Thread(models.Model):
sender = models.(???) # This need to be a field that can store a different model on a run time.
receiver = models.(???) # same here.
Is there any way that I can dynamically first select the model and then pick an object of that list. I have seen this functionality in odoo. But is there anything in Django?
Use Inheritance for in your Model and map your foreign key to User, and then pass either a teacher of student object.
You can use the many-to-many filed with multiple available choices of "Student" and "Teacher" from another Model.
class UserRole(models.Model):
STUDENT = 'STUDENT'
TEACHER = 'TEACHER'
ROLE_CHOICES = (
(STUDENT, 'student'),
(TEACHER, 'teacher'),
)
role_name = models.CharField(max_length=255, choices=ROLE_CHOICES)
def __str__(self):
return "{}".format(self.role_name)
class User(AbstractUser):
username = models.CharField(max_length=50, unique=True)
email = models.EmailField(_('email address'))
role = models.ManyToManyField(UserRole)
Class Thread(models.Model):
sender = models.OneToOneField(User, on_delete=models.CASCADE)
receiver = models.OneToOneField(User, on_delete=models.CASCADE)
This way you can only put available roles in sender and receiver fields of Thread.
The solution was possible with ajax too, but there also is another way in django which I was searching for.
class Test(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Have a good one.

Django filtering queries with multi-table inheritance

I'm using Django multi-table inheritance to implement a notifications system.
It looks like this:
class Notification(models.Model):
# this allows us to check the type without having to query another table
type = models.CharField(max_length=2, choices=type_choices)
user = models.ForeignKey(User, related_name='+', null=True)
date = models.DateTimeField(default=datetime.now)
read = models.BooleanField(default=False)
class Meta:
ordering = ["-date"]
# Users can comment on items.
class CommentNotification(Notification):
comment = models.ForeignKey(Comment, related_name='+')
class ShareNotification(Notification):
share = models.ForeignKey(Share, related_name='+')
# If user unsubscribes from an item, they will not receive notifications of comments on that item
class UnsubscribeItem(models.Model):
user = models.ForeignKey(User, related_name='+')
item = models.ForeignKey(Item, related_name='+')
class Comment(models.Model):
item = models.ForeignKey(Item, related_name='comments')
user = models.ForeignKey(User, related_name='+')
comment = models.TextField()
If I want to get all notifications for a user, I can simply query the Notification table. But I also want to exclude any CommentNotification entries if the user has unsubscribed from that item (only if there is an UnsubscribeItem with user=request.user and item=comment.item).
The problem of course is the field I want to filter is not on the base class. Is it possible to modify the queryset itself to exclude those entries? Or do I need to exclude them while serializing the collection? (I'm using django-rest-framework to serialize for my API, if that helps.)

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