I am trying to optimize a DRF view that has very low performance, is there a way to make it faster? This is where I am right now
Models:
class CategoryVideos(models.Model):
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
name = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return f"{self.name} and {self.id}"
class Videos(models.Model):
category = models.ManyToManyField(CategoryVideos, null=True, blank=True)
illustration = models.FileField(null=True, blank=True)
video = models.FileField(null=True, blank=True)
title = models.CharField(max_length=255, null=True, blank=True)
description = models.CharField(max_length=255, null=True, blank=True)
url_video = models.CharField(max_length=255, null=True, blank=True)
url_image = models.CharField(max_length=255, null=True, blank=True)
Serializers:
class CategorySerializer2(serializers.ModelSerializer):
class Meta:
model = CategoryVideos
fields = ["name"]
class VideoSerializer(serializers.ModelSerializer):
category = CategorySerializer2(many=True, read_only=True)
class Meta:
model = Videos
fields = ["id", "description", "title", "url_video", "url_image", "category"]
read_only=True
View:
class OfferListAPIView(generics.ListAPIView):
queryset = Videos.objects.prefetch_related('category').all()
serializer_class=VideoSerializer
For the moment, with 400 videos and just 6 categories, it takes approx 2.8 secs to get an answer which is way too high.
Many thanks
As you are using only for listing you can add
db_index=True attribute for any field you can also use db_index=True to create an index on a ForeignKey and ManyToManyFields for performance.
make note that creating indexes can slow down the performance of some database operations, such as inserting or updating large amounts of data.
Related
I have two classes Vessels and Components, each vessel has several components.
I just want to fetch all vessels and all their related components in one query, I thought prefretch_related does that trick but in DRF in the api i am only receiving the vessels without their related components
models.py
class Vessel(models.Model):
name = models.CharField(max_length=255, null=True, blank=True)
imo = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
return self.name
class Component(models.Model):
vessel = models.ForeignKey(
Vessel, blank=True, null=True, on_delete=models.CASCADE, related_name='vessel_components')
name = models.CharField(max_length=200, blank=True, null=True)
manufacturer = models.CharField(max_length=200, blank=True, null=True)
model = models.CharField(max_length=200, blank=True, null=True)
type = models.CharField(max_length=200, blank=True, null=True)
remarks = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
serializers.py
class VesselSerializer(serializers.ModelSerializer):
class Meta:
model = Vessel
fields = '__all__'
class ComponentSerializer(serializers.ModelSerializer):
class Meta:
model = Component
fields = '__all__'
the view :
#api_view(['GET'])
def getVessels(request):
vessels = Vessel.objects.all().prefetch_related('vessel_components')
vSerializer = VesselSerializer(vessels, many=True)
return Response(vSerializer.data)
the result i am getting :
I thought prefretch_related does that trick but in DRF.
This will fetch the Components for the Vessels, but since your serializers do not serialize these components, these will not end up in the result.
You should define the ComponentSerializer as subserializer for VesselSerializer, so:
class ComponentSerializer(serializers.ModelSerializer):
class Meta:
model = Component
fields = '__all__'
class VesselSerializer(serializers.ModelSerializer):
vessel_components = ComponentSerializer(many=True) # 🖘 subserializer
class Meta:
model = Vessel
fields = '__all__'
I have model named organization. I am using this same model model for 2 api's. I have a field code. one API do code auto generation another API takes user entry code. I want to separate the tables based on code. Autogeneration code starts SUB001,SUB002,.... like wise. user entry code thats userwish.
models.py
class Organization(models.Model):
code = models.CharField(max_length=255, null=False, unique=True)
name = models.CharField(max_length=255, null=False)
organization_type = models.CharField(max_length=255, choices=TYPES, null=False, default=COMPANY)
internal_organization = models.BooleanField(null=False, default=True)
location = models.ForeignKey(Location, on_delete=models.RESTRICT)
mol_number = models.CharField(max_length=255, null=True, blank=True)
corporate_id = models.CharField(max_length=255, null=True, blank=True)
corporate_name = models.CharField(max_length=255, null=True, blank=True)
routing_code = models.CharField(max_length=255, null=True, blank=True)
iban = models.CharField(max_length=255, null=True, blank=True)
description = models.TextField(null=True, blank=True)
total_of_visas = models.IntegerField(null=False, default=0)
base_currency = models.ForeignKey(Currency, on_delete=models.RESTRICT, null=True, blank=True, default=None)
logo_filename = models.ImageField(_("Image"), upload_to=upload_to, null=True, blank=True)
def __str__(self):
return self.name
admin.py
#admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
list_display = (
'id',
'code',
'name',
'location',
'organization_type',
'internal_organization',
'mol_number',
'corporate_id',
'corporate_name',
'routing_code',
'iban',
'description',
'total_of_visas',
'base_currency',
'logo_filename',
)
Is there any possible to split models based on code,.. Really Expecting help...
You can use Proxymodel inheritance. Documentation
class AutoGenerationManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(code__istartswith="SUB")
class AutoGeneration(Organization):
objects = AutoGenerationManager()
class Meta:
proxy = True
class UserGenerationManager(models.Manager):
def get_queryset(self):
return super().get_queryset().exclude(code__istartswith="SUB")
class UserGeneration(Organization):
objects = UserGenerationManager()
class Meta:
proxy = True
models
class CreatorRawArtwork(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=500)
descripton = models.TextField()
editions = models.IntegerField(null=True, blank=True)
price = models.CharField(max_length=500)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
medias = models.FileField(null=True, blank=True, upload_to="raw-medias")
user = models.ForeignKey(to=Login, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True
)
collection = models.ForeignKey(
to=DesignerCollection, on_delete=models.CASCADE, related_name="creatorrawartwork", null=True, blank=True)
categories = models.ManyToManyField(DesignerCategories, related_name='creatorrawartwork')
def __str__(self):
return self.title
serializer
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
categories = serializers.PrimaryKeyRelatedField(queryset=DesignerCategories.objects.all(), many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
views
class CreatorRawArtworkView(viewsets.ModelViewSet):
queryset = CreatorRawArtwork.objects.all()
serializer_class = CreatorRawArtworkSerializer
Here i am trying to create manytomany fields using drf serialier it is showing some error
plese check the screenshot for parameter and responses
What can be the issue please take a look
class CreatorRawArtworkSerializer(serializers.ModelSerializer):
collection = DesignerCollectionSerializer(read_only=True) #assuming you have already defined serializer for *DesignerCollectionSerializer*
categories = DesignerCategoriesSerializer(many=True)
class Meta:
model = CreatorRawArtwork
fields = "__all__"
depth=1
I tested with your code and your code is working fine
just make sure your request data is json
I am a django newbie and have one more big struggle for longer time... :/
User can choose a 'main language' which is set as ForeignKey. User can choose 'further languages' as ManyToMany (Checkbox). Assuming, user selects english as 'main' language, so english has to be filterd out from the 'further languages'... have been searching so much and have no idea how to do it. Is this even possible without JavaScript?
Of course, I could set the 'queryset' in the second form but it would filter the objects after the submit... The similar problem is, when a selected country has to be connected to the proper zipcodes...
I am very thankful for any hints.
Best regards.
class Country(models.Model):
enter code here
country = models.CharField(max_length=40)
active = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'Länder'
def __str__(self):
return self.country
class ZipCode(models.Model):
zipcode = models.CharField(max_length=5)
city = models.CharField(max_length=255)
active = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'Postleitzahlen'
def __str__(self):
return '{0} {1}'.format(self.zipcode, self.city)
class MainLanguage(models.Model):
language = models.CharField(verbose_name='Hauptsprache', max_length=40)
active = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'Hauptsprachen'
ordering = ['language']
def __str__(self):
return self.language
class SecondLanguage(models.Model):
language = models.CharField(verbose_name='weitere Sprachen', max_length=40)
active = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'weitere Sprachen'
ordering = ['language']
def __str__(self):
return self.language
class CustomUserprofile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(verbose_name='Vorname', max_length=40,
null=True, blank=True)
country = models.ForeignKey(Country, verbose_name='Land',
null=True, blank=True)
zipcode = models.ForeignKey(ZipCode, blank=True, null=True)
main_language = models.ForeignKey(
MainLanguage, verbose_name='Hauptsprache',
null=True, blank=True)
second_language = models.ManyToManyField(
SecondLanguage, verbose_name='weitere Sprachen',
null=True, blank=True)
class UserProfileForm(forms.ModelForm):
second_language = forms.ModelMultipleChoiceField(
queryset=SecondLanguage.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple)
class Meta:
model = CustomUserprofile
exclude = ('user',)
I have been working on a model for tags and am trying to avoid using contenttypes. I have couple questions related to ManyToManyField in django.
I have the following model
taggables/models.py
class Tag(models.Model):
tag_statuses = (
(u'P', _('Pending approval')),
(u'A', _('Approved')),
)
slug = models.SlugField()
created_at = models.DateTimeField(null=True, blank=True)
created_by = models.ForeignKey(User, related_name='tagged_item_created_by')
status = models.CharField(max_length=20, choices=tag_statuses)
site = models.ForeignKey(Site, default=settings.SITE_ID, related_name='tagged_item_site')
def __unicode__(self):
return self.slug
class TagI18n(models.Model):
tag = models.CharField(max_length=100)
descriptor = models.TextField(null=True, blank=True)
# i18n properties
item = models.ForeignKey(Tag)
language = models.CharField(max_length=6, choices=settings.LANGUAGES, default=settings.LANGUAGE_CODE)
class Meta:
unique_together = (("language", "item"))
def __unicode__(self):
return self.tag
I also have different apps around my project that uses tag model as many to many field. such as events for example
evetns/models.py
class Item(models.Model):
event_status_list = (
(u'P', _('Pending approval')),
(u'A', _('Approved')),
(u'R', _('Rejected')),
(u'S', _('Spam')),
)
published_at = models.DateTimeField(null=True, blank=True)
published_by = models.ForeignKey(User, null=True, blank=True, related_name='item_published_by')
updated_by = models.ForeignKey(User, null=True, blank=True, related_name='item_updated_by')
updated_at = models.DateTimeField(null=True, blank=True)
site = models.ForeignKey(Site, default=settings.SITE_ID, related_name='events_item_site')
event_slug = models.SlugField(null=True, blank=True)
# event timing
event_start_date = models.DateField()
event_start_time = models.TimeField(null=True, blank=True)
event_end_date = models.DateField()
event_end_time = models.TimeField(null=True, blank=True)
event_recurrent = models.BooleanField(default=False)
event_status = models.CharField(max_length=20, choices=event_status_list, default=u'P')
# relations
media = models.ManyToManyField(ImageFile, null=True, blank=True)
comments = models.ManyToManyField(Comment, null=True, blank=True)
votes = models.ManyToManyField(Vote, null=True, blank=True)
tags = models.ManyToManyField(Tag, null=True, blank=True)
audience = models.ManyToManyField(Audience, null=True, blank=True)
Now what am trying to do here is run a query to programmatically retrieve all the related models to Tag and then count how many a times a tag was used. Am sure I can do that with contenttypes (generic types) but I don't know how it will perform under heavy usage that's why I wanted to do the many to many fields.
If you are interested in the total number of usage ( aka reference count ) of a tag very often, I think you should store it in the database, example put one extra field to the Tag model, like
referencecount = models.IntegerField( default=0 )
Than in the appropriate places, ( example models .save() )you can increment or decrements it's value.
For your use case, the performance of generic wouldn't matter, because you need anyway to do N queries over 2N tables (one for each "taggable" model and one for each m2m join table, at least).
With the m2m approach, you should have the list of 'taggable' models stored somewhere, at least as a list of ('app_name', 'model') pairs. Then use ContentType (it's very performant) to get the actual model class or query directly from there:
counts = {}
for m in taggable_models:
ct = ContentType.get_by_natural_key(*m)
c = ct.model_class().objects.filter(tags=yourtag).distinct().count()
counts[ct.name] = c