I have four models:
QuestStatus
AdventureStatus
QuestAdventureStatus (consists of two
things, foreign key fields to QuestStatus and AdventureStatus)
QuestAdventure (has the M2M relationship to QuestAdventureStatus)
I have a serializer for QuestAdventure and QuestAdventureStatus exists as a field on my serializer:
quest_adventure_status = serializers.ListField(source='quest_adventure_status.all', required=False)
How do I properly create a new QuestAdventure and create quest_adventure_status(es) as well (updating too)? For creating, quest_adventure_Status is mandatory, but when I pass in my instance it's already serialized and not model objects?
Is there a proper way to deal with this in DRF?
I'd suggest you taking a look at drf-writable nested: https://github.com/beda-software/drf-writable-nested
Related
I want to add an extra field to a query set in Django.
The field does not exist in the model but I want to add it to the query set.
Basically I want to add an extra field called "upcoming" which should return "True"
I already tried adding a #property method to my model class. This does not work because apparently django queries access the DB directly.
models.py
class upcomingActivity(models.Model):
title = models.CharField (max_length=150)
address = models.CharField (max_length=150)
Views.py
def get(self, request):
query = upcomingActivity.objects.all()
feature_collection = serialize('geojson', query ,
geometry_field='location',
fields= ( 'upcoming','title','address','pk' )
)
This answer is for the case that you do not want to add a virtual property to the model (the model remains as is).
To add an additional field to the queryset result objects:
from django.db.models import BooleanField, Value
upcomingActivity.objects.annotate(upcoming=Value(True, output_field=BooleanField())).all()
Each object in the resulting queryset will have the attribute upcoming with the boolean value True.
(Performance should be nice because this is easy work for the DB, and Django/Python does not need to do much additional work.)
EDIT after comment by Juan Carlos:
The Django serializer is for serializing model objects and thus will not serialize any non-model fields by default (because basically, the serializer in this case is for loading/dumping DB data).
See https://docs.djangoproject.com/en/2.2/topics/serialization/
Django’s serialization framework provides a mechanism for “translating” Django models into other formats.
See also: Django - How can you include annotated results in a serialized QuerySet?
From my own experience:
In most cases, we are using json.dumps for serialization in views and this works like a charm. You can prepare the data very flexibly for whatever needs arize, either by annotations or by processing the data (list comprehension etc.) before dumping it via json.
Another possibility in your situation could be to customize the serializer or the input to the serializer after fetching the data from the DB.
You can use a class function to return the upcoming value like this:
def upcoming(self):
is_upcoming = # some logic query or just basically set it to true.
return is_upcoming
then call it normally in your serializer the way you did it.
fields= ( 'upcoming','title','address','pk' )
I am using Django 1.9 and am trying the bulk_create to create many new model objects and associate them with a common related many_to_many object.
My models are as follows
#Computational Job object
class OT_job(models.Model):
is_complete = models.BooleanField()
is_submitted = models.BooleanField()
user_email = models.EmailField()
#Many sequences
class Seq(models.Model):
sequence=models.CharField(max_length=100)
ot_job = models.ManyToManyField(OT_job)
I have thousands of Seq objects that are submitted and have to be associated with their associated job. Previously I was using an iterator and saving them in a for loop. But after reading realized that Django 1.9 has bulk_create.
Currently I am doing
DNASeqs_list = []
for a_seq in some_iterable_with_my_data:
# I create new model instances and add them to the list
DNASeqs_list.append(Seq(sequence=..., ))
I now want to bulk_create these sequence and associate them with the current_job_object.
created_dnaseqs = Seq.objects.bulk_create(DNASeqs_list)
# How do I streamline this part below
for a_seq in created_dnaseqs:
# Had to call save here otherwise got an error
a_seq.save()
a_seq.ot_job.add(curr_job_obj)
I had to call "a_seq.save()" in for loop because I got an error in the part where I was doing "a_seq.ot_job.add(curr_job_obj)" which said
....needs to have a value for field "seq" before this many-to-many relationship can be used.
Despite reading the other questions on this topic , I am still confused because unlike others I do not have a custom "through" model. I am confused with how best to associate the OT_Job with many Seqs with minimal hits to database.
From the docs https://docs.djangoproject.com/en/1.9/ref/models/querysets/#bulk-create:
If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does.
It does not work with many-to-many relationships.
bulk_create literally will just create the objects, it does not retrieve the PK into the variable as save does. You would have to re-query the db to get your newly created objects, and then create the M2M relationships, but it sounds like that would not be appropriate and that your current method is currently the best solution.
consider the below:
class Tag(Model):
...
class Post(Model):
tags = ManyToManyField(Tag) # a join table "post_tags" is created
post = Post.objects.get(pk=1)
post.tags.all() # this will cause django to join "tag" with "post_tags"
post.tags.values('pk') # even though pk is already in post_tags, django will still join with "tag" table
My need is only the list of PKs. Does anyone know of a supported way, or a clean hack where I can just get the PKs from an M2M without an additional join to the actual related table?
You can checkout django doc about prefetch_related. Quoting the docs:
prefetch_related, on the other hand, does a separate lookup for each
relationship, and does the ‘joining’ in Python. This allows it to
prefetch many-to-many and many-to-one objects, which cannot be done
using select_related, in addition to the foreign key and one-to-one
relationships that are supported by select_related.
So it should be:
post = Post.objects.filter(pk=1).prefetch_related('tags')[0]
You can define relation using through argument:
class Tag(Model):
pass
class Post(Model):
tags = ManyToManyField(Tag, through='PostTag')
class PostTag(Model):
post = models.ForeignKey(Tag)
tag = models.ForeignKey(Post)
then
PostTag.objects.filter(post_id=1).values('tag_id')
will perform in a single query, like this:
SELECT `appname_posttag`.`tag_id` FROM `appname_posttag` WHERE `appname_posttag`.`post_id` = 1
I am using the Django Python Serializer to serialize a list of models which contain a many-to-many relationship. Even with prefetch_related, the serialization retrieves the prefetched-fields. For example:
class House(models.Model):
name = models.CharField(...)
rooms = models.ManyToManyField(Door)
class Room(models.Model):
name = models.CharField(...)
num_windows = models.PositiveIntegerField(...)
Using debug mode I can see that the following function makes the expected 2 database requests.
getHouses():
House.objects.all().prefetch_related('rooms')
However, when I attempt to serialize this object using the django.python.Serializer, it makes an additional query for the rooms in each house. Is there a way to configure the serializer to see the prefetched m2m relationships?
The only way to get rid of this is to build the map by yourself. You will need 2 seperate serializers, one for House and other for Room.
While serializing, first iterate on houses query and serialize it, then run Room serializer for house.rooms which gives you serialized room which can be put as another key in serialized house using house_serialized['rooms_serialized'] = rooms_serialized.
Hope this helps.
Is is possible in the admin to pull a field from a remote model, if you have a local foreign key pointing to that model?
class FirstModel(models.Model):
[...]
value12 = models.CharField()
class SecondModel(models.Model):
[...]
firstmodel = models.ForeignKey(FirstModel)
And in the Admin I want to pull in value12, any time someone views/edits SecondModel. I figure I can do this through Inlines, but then I lose Fields and FieldSets ordering. Any other options? Ideal results would be sortable with fields/fieldsets, -and- read-only.
You should be able to access any field in the first model as: firstmodel__value12
For the list view for the SecondModel:
list_display = ('firstmodel__value12',)
For the edit view you can use formfield_overrides. To make it non-editable you specify a read-only widget, e.g. like this one or provide your own.