Parameters for Django REST Model Model.objects.create function - django-rest-framework

Need to know the parameters for Model.objects.create function. This example is from this link: https://www.django-rest-framework.org/api-guide/relations/#nested-relationships. Here in this line Track.objects.create(album=album, **track_data)
What is album=album? I think right side assigned value of album is Album.objects.create(**validated_data) but what is the left side album. As per the documentation it is the Model field. But neither Model Track and Album contains fieldalbum`.
Is this the default model name for Album?
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ['order', 'title', 'duration']
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album

Not explicitly said in the tutorial, but it's assumed that there is a ForeignKey field in Track called album, that refers to the Album model.
Notice the following in the second code snippet within the Example section:
>>> album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse')
>>> Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)
<Track: Track object>
That hints what I'm saying. The fact that there is no field albumon TrackSerializer would have raise an error if it was simply Track.objects.create(**track_data) because the field album would be missing. Thus, you need to include it explicitly.

Related

Django Rest Framework - Updating a ForeignKey Field entry in the view

In my Django Rest Framework project, I have a ForeignKey relationship between two models:
class Book(models.Model):
...
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
...
class Category(models.Model):
name = models.CharField(max_length=100, blank=False)
As you can see, a Book can belong to a Category but it does not have to. That means the 'category' field could be null.
So, in my views.py, any Book instance can be updated/patched if the user wants to assign a certain Book to a particular Category. That views.py update method looks like this:
class UpdateBooksCategory(generics.GenericAPIView):
'''
Class-based view to update the 'category' field of a Book instance.
'''
serializer_class = BookSerializer
permission_classes = [IsAuthenticated]
def patch(self, request,*args, **kwargs):
# get the Book instance first
book = Book.objects.get(pk=request.data.get('bookId'))
# if it is not assigned to a Category, then assign it
if book and not book.category:
book.category = Category.objects.get(name=request.data.get('categoryName'))
book.save()
serializer = self.get_serializer(book, context={"request": request})
return Response(serializer.data)
# otherwise, return a generic response
return Response({'response': "You have already put the selected Book in a Category."})
If you can see, first I get the Book instance that the user wants to update by using the Book's ID. If its Category field is not already filled, I get a Category instance using the given category name and assign it.
For the sake of completeness, here are my serializer classes:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name']
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', /*some other fields*/,..., 'category']
So, finally my question: I wanted to know if this is the preferred way of updating a ForeingKey field like this? I mean looking at the UpdateBooksCategory class-based view, is this the right way of doing it? The code works ( I tested it with PostMan) but since I am new to DRF I wanted to know if such an updating process is correct.
You can change your BookSerializer:
class BookSerializer(serializers.ModelSerializer):
category_id = serializers.IntegerField(write_only=True)
category = CategorySerializer(read_only=True)
class Meta:
model = Book
fields = [
'id',
# some other fields,
'category',
'category_id',
]
category will be a nested data that is read only, then setting the category will be by including the category_id in your requests.

Django Rest - get related data in M2M relation

I have 2 models:
class Artist(models.Model):
name = models.CharField(max_length=255)
music_type = models.CharField(max_length=50)
class Event(models.Model):
event_name = models.CharField(max_length=255)
description = models.TextField()
place = models.CharField(max_length=50)
longitude = models.DecimalField(max_digits=9, decimal_places=6)
latitude = models.DecimalField(max_digits=9, decimal_places=6)
date = models.DateField()
artists = models.ManyToManyField(Artist)
For every artist I would like to get list of other artists if they have ever been in any event together.
I was able to create close solution, but only for specific artist:
def get_related_artists(request):
artist_id = 2
related_events = Artist.objects.filter(id=artist_id).first().event_set.all()
related_artists_ids = []
for event in related_events:
related_artists_ids = related_artists_ids + list(event.artists
.all()
.values_list('id', flat=True)
.all())
related_artists = Artist.objects\
.filter(id__in=set(related_artists_ids))\
.exclude(id=artist_id)
serializer = ArtistRelatedSerializer(related_artists, many=True)
return JsonResponse(serializer.data, safe=False)
So firstly I get all event where specific artist took part. Later I iterate over this events and get other artist's ids. Another step is to remove duplicated ids and specific artist id. At the end I use serializer to return data.
Serializer looks like:
class ArtistRelatedSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = '__all__'
Unfortunately I think it isn't optimal solution and works only for hardcoded artist's id. I would like to get all artists and for ech list of other artists.
I was thinking about creating loop and iterate over Artist.objects.count() but I couldn't find a solid solution to maintain all this queries.
Is there any other, maybe easier way to solve this solution?
You can solve this issue from Serializer by using SerializerMethodField. Get all events in each Artist, the example below:
class ArtistSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = ('id', 'name', 'music_type', 'events')
events = serializers.SerializerMethodField()
def get_events(self, obj):
events_qs = Event.objects.filter(artists__in=[obj.id])
events = EventSerializer(
events_qs, many=True, context=self.context).data
return events
To avoid the error by the circle imports, you should use import in the function

How to post data to Embedded document with Mongoengine REST

I am trying to use Django with mongoengine to make an API.
So far I can get the objects and delete them. but when I want to post some data. Lets say student + course it is giving an error:
type object 'Course' has no attribute 'objects'
Models en ..
#Model.py
class Course(EmbeddedDocument):
course_name = StringField(max_length=200)
course_fee = StringField(max_length=200)
class Student(Document):
student_name = StringField(max_length=200)
student_contactperson = StringField(max_length=200)
student_adress = StringField(max_length=200)
courses = ListField(EmbeddedDocumentField(Course))
#Serializers.py
class CourseSerializer(EmbeddedDocumentSerializer):
class Meta:
model = Course
fields = ('course_name','course_fee')
class StudentSerializer(DocumentSerializer):
courses = CourseSerializer(many=True)
class Meta:
model = Student
fields = ('student_name','student_contactperson','student_adress','courses')
depth = 2
def create(self, validated_data):
course_data = validated_data.pop('courses')
student = Student.objects.create(**validated_data)
Course.objects.create(student=student, **course_data)
return student
#Views.py
class StudentViewSet(meviewsets.ModelViewSet):
lookup_field = 'name'
queryset = Student.objects.all().order_by('-date_joined')
serializer_class = StudentSerializer
A Document represents a MongoDB document (i.e a record in a collection), a Document class is bound to a particular collection. An EmbeddedDocument represents a structure that gets nested in a Document.
So by design an EmbeddedDocument isn't attached to any collection unless you embed it inside a Document.
This means that you can't query or save an EmbeddedDocument class, you need to query/save the parent Document.
Document.objects is an entry point for querying a collection, it only exists on Document classes. You are calling Course.objects.create but Course is an EmbeddedDocument.
I believe you need to change your code to the following
class StudentSerializer(DocumentSerializer):
...
def create(self, validated_data):
course_data = validated_data.pop('courses')
course = Course(**course_data) # assuming course_data is {course_name: ..., course_fee: ...}
return Student.objects.create(courses=[course], **validated_data)

Confused to Serializer relations in Django Rest

In the Serializer relations part on Django official website, it provides a music albums example to represent and explain some relationship.
class Album(models.Model):
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
album = models.ForeignKey(Album, related_name='tracks')
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
class Meta:
unique_together = ('album', 'order')
ordering = ['order']
def __unicode__(self):
return '%d: %s' % (self.order, self.title)
Later, it interacts model with Serializer.
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
The result is:
{
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': [
'1: Sunflower',
'2: Whitetail',
'3: Dinosaur Act',
...
]
}
I am confused variable tracks in the AlbumSerializer. It seems that the variable tracks is irrelevant to Album and Track model.How it is related to the Album and Track models? How it calls and invokes unicode method of Track model in the AlbumSerializer?
It is related via related_name
album = models.ForeignKey(Album, related_name='tracks')
The related_name attribute specifies the name of the reverse relation from Album to Track.
Read more https://docs.djangoproject.com/en/1.9/ref/models/fields/#django.db.models.ForeignKey.related_name

Django ModelForms: Trying to save a form using a foreign key ID

I'm trying to create a new Topic and the category id is dynamically determined in javascript on the client side. The problem i'm having is I pass the category id and I want to lookup the correct category object, but using a model form, it checks if the category is an instance of Category before I can assign it and save it.
--model.py--
class Topic(models.Model):
category = models.ForeignKey(Category)
--form.py--
class TopicForm(ModelForm):
category = forms.IntegerField(widget=forms.HiddenInput())
class Meta:
model = Topic
fields = ('category')
--view.py--
form = TopicForm(request.POST)
if form.is_valid():
form.save(commit=False) # throws exception category is not a Category instance
form.category = Category.objects.get(pk=form.cleaned_data.get('category'))
form.save()
Use a ModelChoiceField instead of the IntegerField in your form. See the built-in fields reference
Following Oggy's suggestion, I changed it to a ModelChoiceField and now Django does all the magic behind the scenes.
category = forms.ModelChoiceField(Category.objects.all(), widget=forms.HiddenInput())
Now I hope the queryset doesn't get evaluated, since it's not necessary and there are 90,000 records. :)

Resources