how to reverse fetch data in django models - django

I am stuck on how to fetch the data child model which has a foreignkey of parent model.
this is how my model looks like
class Projects(models.Model):
project_name = models.CharField(max_length=100,null=False)
class ProjectTask(models.Model):
project_id = models.ForeignKey(Projects,on_delete=models.CASCADE,null=False)
class TaskBlockers(models.Model):
task_id = models.ForeignKey(ProjectTask,on_delete=models.CASCADE,null=False,related_name='task_id_related')
blocker = models.CharField(max_length=100,null=False)
now what I want is to get all the blockers under a projectTask which has a projectid = something.
ProjectTask.objects.filter(project_id=1) this will give a queryset right? and for each element in a queryset i want the blocker from TaskBlockers table.
How can I achieve this?

data = TaskBlockers.objects.filter(task_id__project_id_id=1).values("blocker")

Related

Preload FK relation in different column Django

I have Django models that looks like this
class Customer(models.Model):
name = models.CharField(_("Name"))
class Feature(models.Model):
label = models.CharField(_("Name"))
class AddOn(models.Model):
customer = models.ForeignKey(Customer)
feature = models.ForeignKey(Feature)
Given that I have an instance of Customer e.g
customer = Customer.objects.get(pk=1)
How do I get all the labels in feature in one query to avoid N+1 query?
For now what I've done is:
[addon.feature.label for addon in self.addon_set.all()]
But I think for each addon.feature will create a query that is not very optimized if there is a lot of addon
You can use values/values_list to get all labels in a single query
self.addon_set.values_list('feature__label', flat=True)
EDIT: Example of the ManyToManyField
class Customer(models.Model):
name = models.CharField(_("Name"))
features = ManyToManyField('Feature', through='AddOn')
class Feature(models.Model):
label = models.CharField(_("Name"))
class AddOn(models.Model):
customer = models.ForeignKey(Customer)
feature = models.ForeignKey(Feature)
You can then perform queries like customer_obj.features.all() or feature_obj.customers.all() and it won't affect your ability to still query the AddOn model

How to update through model in django many to many?

class Blog():
likes = models.ManyToManyField(User, through="myapp.Like")
class Like():
user = models.ForeignKey(Like)
blog = models.ForeignKey(Blog)
liked_at = models.DateTimeField(auto_now_add=True)
some_bool_field = models.BooleanField(default=False)
Now in views:
def like_blog(request, id):
blog = Blog.objects.get(id=id)
blog.users.add(request.user)
# now how can I update some_bool_field and How can I make use of this field
In future I can use some query like blog.users.filter(some_bool_field=False) so for that case I want to update this field.
OR AM I MISSING THE USES OF THROUGH MODEL ?
If you want to update the through model objects you can do like so:
def like_blog(request, id):
blog = Blog.objects.get(id=id)
blog.users.add(request.user)
# query your through model
Like.objects.filter(user=request.user, blog=blog).update(some_bool_field=True)
Getting all blogs filtered likes with some_bool_field=True:
true_boolean_likes = Blog.objects.filter(likes__some_bool_field=True)
for through model update you can use bellow method to update
like = Blog.objects.get(id=id)
for like in Likes.objects.filter(likes__some_bool_field =False): #or true by what you want to filter
like.the_field_want_to_update.update(id=like.id)
here .update update the value by which you are filtering here with id so it will update what data passed to it.

Edit update all schedules except primary key in Django Rest Framework

I wanna change all fields of a json object except 'pk' in DRF. I just need to keep one json data. When adding a new data ,this one should override existing data. Is there a way to do it with django ?
my models.py
class ClientUser2(models.Model):
phone_number = models.CharField(max_length=20,unique=True)
name = models.CharField(max_length=100,blank=True)
status = models.IntegerField(default=1)
class ClientNameSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ClientUser2
fields = ('url','phone_number','name','status','pk')
my views.py
class ClientViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows messages to be viewed or edited.
"""
queryset = ClientUser2.objects.all()
serializer_class = ClientNameSerializer
and it's my api root
api_root
If you want to be able to only retrieve and update models you can use RetrieveUpdateApiView
Reference : https://www.django-rest-framework.org/api-guide/generic-views/#retrieveupdateapiview

Django Rest Framework Many=False producing errors

I am stuck on trying to solve an issue with the Serializers and related fields using the django-rest-framework. Currently I have a model that looks like this:
class DataSetModel(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
class DataPointModel(models.Model):
dataSet = models.ForeignKey(DataSetModel, related_name='dataPoints')
label = models.CharField(max_length=200)
My serializers look like this:
class DataPointSerializer(serializers.ModelSerializer):
class Meta:
model = DataPointModel
fields = ('pk','label')
class DataSetSerializer(serializers.ModelSerializer):
dataPoints = DataPointSerializer(many=True, read_only=True)
class Meta:
model = DataSetModel
fields = ('pk','title')
The problem I am having is when I try to change the "many=False" in the serializer produces this error:
Got AttributeError when attempting to get a value for field label on
serializer DataPointSerializer. The serializer field might be named
incorrectly and not match any attribute or key on the RelatedManager
instance. Original exception text was: 'RelatedManager' object has no
attribute 'label'.
Since this is only ever one model object (one-to-many relationship), I want to get the result as a single object vs a list of one object.
Am I doing this the right way? I thought that turning the "many=False" it would fetch the first record in an nested query.
Any insight would be greatly appreciated.
You can't set many=False, because dataPoints is a related field that returns a queryset containing a list of instances, not just an instance.
When you do DataPointModel.dataPoints that returns a queryset, it can't returns just an instance. So setting many=False, it wouldn't get the first element of the list.
So the solve I came to was refactoring my models with where the Foreign Keys are attached.
Here is the fix I implemented:
class DataSetModel(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
dataPoint = models.ForeignKey(DataPointModel)
class DataPointModel(models.Model):
label = models.CharField(max_length=200)
Moving it to the DataSetModel automatically joins the data model if you set 'many=False' in the Serializer object.
Write your DataPointModel as below. It should work then
class DataPointModel(models.Model):
dataSet = models.OneToOneField(DataSetModel, related_name='dataPoints')
label = models.CharField(max_length=200)

django: how do I query based on GenericForeignKey's fields?

I'm new in using GenericForeignKey, and I couldn't make it to work in a query statement. The tables are roughly like the following:
class Ticket(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
class Issue(models.Model):
scan = models.ForeignKey(Scan)
A scan creates one issue, an issue generates some tickets, and I made Issue as a foreign key to Ticket table. Now I have a Scan object, and I want to query for all the tickets that related to this scan. I tried this first:
tickets = Tickets.objects.filter(issue__scan=scan_obj)
which doesn't work. Then I tried this:
issue = Issue.objects.get(scan=scan_obj)
content_type = ContentType.objects.get_for_model(Issue)
tickets = Tickets.objects.filter(content_type=content_type, issue=issue)
Still doesn't work. I need to know how to do these kind of queries in django? Thanks.
The Ticket.issue field you've defined will help you go from a Ticket instance to the Issue it's attached to, but it won't let you go backwards. You're close with your second example, but you need to use the issue_id field - you can't query on the GenericForeignKey (it just helps you retrieve the object when you have a Ticket instance). Try this:
from django.contrib.contenttypes.models import ContentType
issue = Issue.objects.get(scan=scan_obj)
tickets = Ticket.objects.filter(
issue_id=issue.id,
issue_ct=ContentType.objects.get_for_model(issue).id
)
Filtering across a GenericForeignKey can by creating a second model that shares the db_table with Ticket. First split up Ticket into an abstract model and concrete model.
class TicketBase(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
class Meta:
abstract = True
class Ticket(TicketBase):
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
Then create a model that also subclasses TicketBase. This subclass will have all the same fields except issue which is instead defined as a ForeignKey. Adding a custom Manager allows it to be filtered to just a single ContentType.
Since this subclass does not need to be synced or migrated it can be created dynamically using type().
def subclass_for_content_type(content_type):
class Meta:
db_table = Ticket._meta.db_table
class Manager(models.Manager):
""" constrain queries to a single content type """
def get_query_set(self):
return super(Manager, self).get_query_set().filter(issue_ct=content_type)
attrs = {
'related_to': models.ForeignKey(content_type.model_class()),
'__module__': 'myapp.models',
'Meta': Meta,
'objects': Manager()
}
return type("Ticket_%s" % content_type.name, (TicketBase,), attrs)