Django rest model with foreign key access - django-rest-framework

class PortalContent(models.Model):
movies = models.ForeignKey(Movie, db_column="movies_id")
portalID = models.IntegerField()
projectID = models.IntegerField(default=0)
contentType = models.CharField(max_length=100)
licenseTerms = models.TextField()
createDate = models.DateTimeField(auto_now=True)
I have the above model .This model has a field which is related to Movie Model via foreign key.
Now when I view the list /portalContent/1/
the data takes more than 2 seconds to load . The movie table only has 20K records .
Not sure why this is taking so much time . I used the debug_toolbar and its showing one query i.e select * from movies as taking 1.6s . Both the tables have index defined .
Can anyone guide me

Thanks #Demux
We need to remove browsable API renderer from your list of supported renderers for the view.
You can do this globally like so:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
}
Or on a per-view basis like so:
class MyView(...):
renderer_classes = [renderers.JSONRenderer]

Related

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 save partial data in a separate model and then query checks if that data exists?

My data consists of some products, which are defined in FdProduct model:
# models.py:
class FdProduct(models.Model):
product_id = models.CharField(max_length=10, primary_key=True)
name = models.CharField(max_length=40)
active = models.BooleanField(default=True)
def __str__(self):
return self.product_id
# serializers.py:
class FdProductSerializer(serializers.ModelSerializer):
product_id = serializers.RegexField(regex='^\d{3}\.\d{6}$', max_length=10, min_length=10, allow_blank=False)
name = serializers.CharField(min_length=6, max_length=50, allow_blank=False)
class Meta:
model = FdProduct
fields = '__all__'
For each existing product I can prepare a configuration and save it using a model called SavedConfiguration:
# models:
class SavedConfiguration(models.Model):
saved_conf_id = models.CharField(max_length=13, primary_key=True)
saved_config = models.TextField()
product = models.ForeignKey(FdProduct, on_delete=models.CASCADE, default=0)
session_id = models.CharField(max_length=40, default=0)
creation_date = models.DateTimeField(auto_now=False, auto_now_add=True)
def __str__(self):
return str(self.saved_conf_id)
# serializers.py:
class SavedConfigurationSerializer(serializers.ModelSerializer):
saved_conf_id = serializers.RegexField(regex='^sc\d{2}', allow_blank=False)
saved_config = serializers.CharField(min_length=6)
session_id = serializers.RegexField(regex='^se\d{2}', allow_blank=False)
class Meta:
model = SavedConfiguration
fields = '__all__'
By connecting the SavedConfiguration with FdProduct model with use of ForeignKey I ensure that a product exists in the database when I configure it and want to save the configuration.
I'd like to introduce two things more: the first one would be a model for storing just a product_id and an array containing all saved_conf_ids for that product:
# models.py:
class ConfigOptions(models.Model):
product_id = ...
saved_conf_id = [...]
For example, if I configured a couple of times two products, Product One and Product Three, I may have data like this:
- Product One:
- C_ID_0023
- C_ID_0025
- C_ID_0032
- Product Three:
- C_ID_0149
- C_ID_0273
My question now is, how to construct such model and serializer for which records are created (copied) into ConfigOptions model table each time SavedConfiguration is saved?
Second question: I'm thinking about creating another model, say ConfigPresenceCheck, which would receive POST requests and based on that would check if saved product configurations exist (so, fetching them from ConfigOptions or returning 404), and if they exist, would return them together with all parameters from SavedConfiguration (e.g. saved_config, session_id, etc.).
Please give me directions how to build such models. I'd also appreciate some good tutorials related to
constructing Django models.
I think you should use many to many fields instead of foreign key, from my understanding many products can have many saved configurations and vice versa, at database level many to many fields are stored by creating a table any way.

Multiple endpoints for a single model in REST framework

I have a REST framework app for a multi-page form:
class InformationRequest(models.Model):
# user information
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
# contact details
phone = models.CharField(max_length=60)
email = models.CharField(max_length=60)
I'm trying to create endpoints for each of the two blocks of data within the model:
UserInformationSerializer(serializers.Serializer):
first_name = serializers.CharField(max_length=60)
last_name = serializers.CharField(max_length=60)
ContactDetailsSerializer(serializers.Serializer):
phone = serializers.CharField(max_length=60)
email = serializers.CharField(max_length=60)
I'd like the endpoints to look like:
requests/1/user-informtion
requests/1/contact-details
But I'm unsure of how to structure the view to achieve this. Currently I'm using a model viewset:
class InformationRequestViewSet(viewsets.ModelViewSet):
queryset = InformationRequest.objects.all()
serializer_class = ??
Is it possible to have two serializers for one model?
It's certainly possible to have 2 (or any number of) serializers for a model. And you are on the right path. What you want is different urls mapping to different views. So in your case, it can be something like the following:
Note that I turned each of your serializers into a ModelSerializer.
path-to/serializers.py
class UserInformationSerializer(serializers.ModelSerializer):
class Meta:
model = InformationRequest
fields = ('first_name', 'last_name')
class ContactDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = InformationRequest
fields = ('phone', 'email')
Next, we have 2 different urls that point to 2 different views:
path-to/urls.py
urlpatterns = [
url(r'^requests/(?P<pk>\d+)/user-information/$', views.UserInformationDetail.as_view()),
url(r'^requests/(?P<pk>\d+)/contact-details/$', views.ContactInformationDetail.as_view()),
# ... other urls
]
And finally, the views themselves (I'm using generic RetrieveAPIView for convenience)
path-to/views.py
class UserInformationDetail(generics.RetrieveAPIView):
queryset = InformationRequest.objects.all()
serializer_class = UserInformationSerializer
class ContactInformationDetail(generics.RetrieveAPIView):
queryset = InformationRequest.objects.all()
serializer_class = ContactDetailsSerializer

Writable many-to-many field in Django Rest Framework tries to save new child objects?

Edit: This is using django rest framework 2.3
I have a model structure that has 3 relationship "levels", one of which is many to many.
class Shipment(models.Model):
stuff...
class ShipmentItem(models.Model):
shipment = models.ForeignKey(Shipment)
assets = models.ManyToMany(ShipmentAsset)
class ShipmentAsset(models.Model)
serial_number = models.CharField(unique=True)
Using Django rest framework I want to be able to post to the "Shipment" endpoint with a payload that contains the ShipmentItems for the Shipment, and the ShipmentAssets for the ShipmentItems ideally in one request.
The serializers are as follows..
class ShipmentAssetSerializer(serializers.ModelSerializer):
class Meta:
model = ShipmentAsset
field = ('id', 'serial_number', )
class ShipmentItemSerializer(serializers.ModelSerializer):
assets = ShipmentAssetSerializer(
many=True, required=False, allow_add_remove=True,
)
class Meta:
model = ShipmentItem
fields = ('id', 'assets', )
class ShipmentSerializer(serializers.ModelSerializer):
class Meta:
model = Shipment
fields = (
'id',
)
The shipmentItem/Shipment relationship seems to work when I post to it with the assets part disabled, but when I try to post assets in the payload, It appears to be trying to create NEW assets with the posted data (I get an error regarding the unique constraint on the serial number) rather than creating a new many-to-many table object. Any idea what I'm doing wrong?
Edit: Important clarification, I'm using Django Rest Framework 2.3.13

how to get foreign key fields using reverse lookup in python/django ajax request (json)

---models.py---
class Products(models.Model):
category = models.ForeignKey(Category)
name= models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique = True)
price = models.IntegerField(default=100)
class Image(models.Model):
property = models.ForeignKey(Products, related_name='images')
image = models.ImageField(upload_to='static/images/home',blank=True,null=True)
---views.py----
if request.is_ajax():
query = Products.objects.all()
p = Paginator(query, 4)
pagedata = p.page(1)
jsondata = serializers.serialize('json', pagedata.object_list)
data = json.dumps({'id' : jsondata,})
return HttpResponse(data, content_type='application/json')
now in ajax data are in (pk, category, name, slug ,price)
but i also want foreign key field i.e 'image' using reverse lookup in ajax. i have already tried list but i want to do using reverse lookup..
You cannot use serializers.serialize and then json.dumps on your stuff. serializers.serialize is basically doing the same thing as json.dumps, to convert a python object into json string. What you need to do is manually construct a dictionary that contains all your data. You might need to loop through the Product list because there's no way to query for reverse relationships for each item in one run.

Resources