get dictionary from queryset - django

I have below query where I want to fetch 'specs' which is a dictionary but the type of envi_dict is a Queryset class. How do I fetch the dictionary from this queryset? Any help is much appreciated.
envi_dict = Environment.objects.values('specs')
Result
<QuerySet [({u'CPU Model': u'Dell', u'RAM': 1000, u'CPU': 400},), ({u'CPU Model': u'Dell', u'RAM': 1000, u'CPU': 400},)]>, <class 'django.db.models.query.QuerySet'>, )
I tried Environment.objects.filter(title=item.title).values('specs') and also Environment.objects.get('specs') but I am still getting a queryset.
Edit: Below is models.py
class CommonModel(models.Model):
author = models.ForeignKey('auth.User',)
title = models.CharField(max_length=400)
comments = models.TextField(blank=True)
requirements = JSONField(default = {})
specs = JSONField(default= {})
created_date = models.DateTimeField(default=timezone.now)
updated_date = models.DateTimeField(blank=True, null=True)
class Meta:
abstract = True
def update(self):
self.updated_date = timezone.now()
self.save()
def __str__(self):
return self.title
class Estimate(CommonModel):
gp_code = models.TextField(default='Unknown')
inputs = models.TextField(blank=True)
...
def __str__(self):
return self.title
class Environment(CommonModel):
estimate = models.ForeignKey(Estimate,related_name='environments')
logic = PythonCodeField(blank=True, null=True)
...

Build a list of dicts with model instance.title as key and the specs as value by iterating over all Environment model instances.
[{i.title: i.specs} for i in Environment.objects.all()]

Use Django model_to_dict
If you need to convert a single queryset into a dictionary, use
model_to_dict.
If you need to convert all querysets into a dictionary use Model.objects.values() or django.core.serializer
using model_to_dict
from django.forms.models import model_to_dict
qs = Environment.objects.filter(title=item.title)
if qs.exists():
qs_dict = model_to_dict(qs) # {id:1,'estimate':'some-estimate-data','logic':'some-logic-data'}
# Do something here with qs_dict
else:
# qs=None -- do some here when qs is not found

Related

How to add dynamic field to django.core.serializers.serialize

I'm trying to export a queryset into json format. However, my query has a dynamic field (ie not defined in the model), and when I try to add it nothing shows.
My model:
class MyModel(models.Model):
id = models.TextField(primary_key=True, blank=True)
quantity = models.IntegerField(null=True, blank=True)
rate = models.IntegerField(null=True, blank=True)
class Meta:
managed = False
My queryset:
qs = MyModel.objects.filter(id=id).annotate(result=F('rate') * F('quantity'))
My call:
class ClassName:
#classmethod
def build__json(cls, queryset):
geojson_str = serialize('json',
queryset,
fields=('result')
)
my_geojson = json.loads(geojson_str)
return my_geojson
qs_json = ClassName.build_json(qs)
Is there a way to use serialize to do this? Or do I need to write a custom class?
PS: I'm not building a view, just trying to convert a queryset into a json.
Thanks in advance
I think that would solve you're problem
serializers.py
class Serializer(serializers.ModelSerializer):
...
rate_quantity = serializers.CharField(read_only=True, source="rate_quantity_value")
models.py
#property
def rate_quantity_value(self):
return rate * quantity

Django REST Framework: I want to resolve n+1 in SerializerMethodField

I am trying to create a queryset that returns Boolean from a queryset prefetched with a reverse reference by SerializerMethodField, as shown in the code below.
I'm creating one that determines if there is an object for the current user and returns Boolean.
However, when I use the prefetched queryset to filter by the current user as shown below, a new queryset is issued instead of the prefetched queryset, and the n+1 problem occurs.
In the following code, how can we save the queryset and return
Booelan?
# serializers.py
class VideoSerializer(serializers.ModelSerializer):
is_viewed = serializers.SerializerMethodField()
is_favorited = serializers.SerializerMethodField()
is_wl = serializers.SerializerMethodField()
class Meta:
model = Video
fields = (
"pk",
"is_viewed",
"is_favorited",
"is_wl",
)
#staticmethod
def setup_eager_loading(queryset):
queryset.prefetch_related('history_set', 'favorite_set')
def get_is_viewed(self, obj):
user = self.context["request"].user
if user.is_authenticated:
try:
obj.history_set.get(user=user) # <- here
return True
except History.DoesNotExist:
pass
return False
def get_is_favorited(self, obj):
user = self.context["request"].user
if user.is_authenticated:
try:
obj.favorite_set.get(user=user) # <- here
return True
except Favorite.DoesNotExist:
pass
return False
def get_is_wl(self, obj):
user = self.context["request"].user
if user.is_authenticated:
try:
Track.objects.get(playlist__user=user, playlist__is_wl=True, video=obj)
return True
except Track.DoesNotExist:
pass
return False
A large number of query sets were issued.
#models.py
class Video(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField("title", max_length=300)
def __str__(self):
return self.title
class History(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE
)
video = models.ForeignKey(Video, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.user}, {self.video.title}"
class Favorite(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE
)
video = models.ForeignKey(Video, on_delete=models.CASCADE)
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return f"{self.user}, {self.video.title}"
You can use Exists subquery.
Video.objects.annotate(is_favorite=Exists(Favorite.objects.filter(user=self.request.user, video=OuterRef("id"))))
After that you can access is_favorite attribute.
class VideoSerializer(serializers.ModelSerializer):
is_viewed = serializers.SerializerMethodField()
is_favorited = serializers.SerializerMethodField()
is_wl = serializers.SerializerMethodField()
class Meta:
model = Video
fields = (
"pk",
"is_viewed",
"is_favorited",
"is_wl",
)
#staticmethod
def setup_eager_loading(queryset):
queryset.prefetch_related('history_set', 'favorite_set')
def get_is_viewed(self, obj):
user = self.context["request"].user
if user.is_authenticated:
try:
obj.history_set.get(user=user) # <- here
return True
except History.DoesNotExist:
pass
return False
def get_is_favorited(self, obj):
return obj.is_favorite
def get_is_wl(self, obj):
user = self.context["request"].user
if user.is_authenticated:
try:
Track.objects.get(playlist__user=user, playlist__is_wl=True, video=obj)
return True
except Track.DoesNotExist:
pass
return False
You can add annotations for other fields (is_views, is_wl)
Another query being made with prefetch_related method call is intended. You can find it in django documentation.
https://docs.djangoproject.com/en/3.2/ref/models/querysets/
I think using subquery and Exists query expression is better option, as 'Utkucan Bıyıklı' suggested.
By reverse reference, i understand you are referring a foreignkey field, in that case you need to use select_related, prefetch_related is used for many-many fields.
Based on it you can use any of the below code. make sure to return the queryset.
#staticmethod
def setup_eager_loading(queryset):
#prefetch_related for 'to-many' relationships
queryset.prefetch_related('history_set', 'favorite_set')
return quesyset
#staticmethod
def setup_eager_loading(queryset):
#select_related for 'foreign key' relationships
queryset = queryset.select_related('history_set', 'favorite_set')
return queryset

Django FilterSet with distinct AND order_by

I want to use django-filter to create a FilerSet with distinct results for field A (Minutes.case), ordered by field B (case__case_filed_date). Database is PostgreSQL.
Commented lines in class MinutesListView are things I've tried (in various configurations).
models.py
class Case(models.Model):
case_filed_date = models.DateField()
case_number = models.CharField(max_length=25, unique=True)
as_of_timestamp = models.DateTimeField()
def __str__(self):
return self.case_number
class Minutes(models.Model):
case = models.ForeignKey(Case, on_delete=models.CASCADE)
minute_entry_text = models.TextField(blank=True, null=True)
minute_entry_date = models.DateField(blank=True, null=True)
minute_entry_type_text = models.CharField(max_length=255, blank=True, null=True)
filters.py
class MinuteFilterSet(df.FilterSet):
case__case_number = df.CharFilter(lookup_expr='icontains', label='Case Number', distinct=True)
minute_entry_text = df.CharFilter(lookup_expr='icontains', label='Minutes Text')
class Meta:
model = Minutes
fields = ['minute_entry_text']
order_by = ['-case__case_filed_date']
views.py:
class FilteredListView(ListView):
filterset_class = None
def get_queryset(self):
# Get the queryset however you usually would. For example:
queryset = super().get_queryset()
# Then use the query parameters and the queryset to
# instantiate a filterset and save it as an attribute
# on the view instance for later.
self.filterset = self.filterset_class(self.request.GET, queryset=queryset)
# Return the filtered queryset
return self.filterset.qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Pass the filterset to the template - it provides the form.
context['filterset'] = self.filterset
return context
class MinutesListView(FilteredListView):
filterset_class = filters.MinuteFilterSet
paginate_by = 25
# ordering = '-case__case_filed_date'
# queryset = Minutes.objects.all()
queryset = Minutes.objects.distinct('case')
The current code shows distinct, unordered results. When I'm able to get ordered results, the cases (case_number) is duplicated. I've read the docs regarding distinct() with order_by() in Django/PostGreSQL but I'm still missing something.

How to get slugs from different models in the urls i.e path(<slug:slug1>/<slug:slug2>/)?

Im trying to get a ur pattern that looks like this WWW.domain.com/slug1/slug2, where slug1 is the foreignkey to slug to. Think of it like library.com//. The author and book are two different models, both with their own slug. Is there a way where i can import the slug from author to the detailview of the book and then use it in the urls for the book detailview?
This is how i imagine the path to look like:
path('brands/<slug:brand_slug>/<slug:model_slug>', views.Brand_ModelsDetailView.as_view(), name='model-detail'),
These are my models:
class Brand(models.Model):
brand_name = models.CharField(
max_length=50, help_text='Enter the brand name',)
slug = AutoSlugField(populate_from='brand_name', default = "slug_error", unique = True, always_update = True,)
def get_absolute_url(self):
"""Returns the url to access a particular brand instance."""
return reverse('brand-detail', kwargs={'slug':self.slug})
def __str__(self):
return self.brand_name
class Brand_Models(models.Model):
name = models.CharField(max_length=100)
brand = models.ForeignKey('Brand', on_delete=models.SET_NULL, null=True)
slug = AutoSlugField(populate_from='name', default = "slug_error_model", unique = True, always_update = True,)
def get_absolute_url(self):
"""Returns the url to access a particular founder instance."""
return reverse('model-detail', kwargs={'slug':self.slug})
def __str__(self):
return self.name
My current attempt at the views:
class Brand_ModelsDetailView(generic.DetailView):
model = Brand_Models
def get_queryset(self):
qs = super(Brand_ModelsDetailView, self).get_queryset()
return qs.filter(
brand__slug=self.kwargs['brand_slug'],
slug=self.kwargs['model_slug']
)
EDIT:
class RefrenceDetailView(generic.DetailView):
model = Refrence
def get_queryset(self):
qs = super(RefrenceDetailView, self).get_queryset()
return qs.filter(
brand__slug=self.kwargs['brand_slug'],
model__slug=self.kwargs['model_slug'],
slug = self.kwargs['ref_slug']
)
Your error is just with the get_absolute_url method of Brand_Models; because the detail URL takes two slugs, you need pass them both to reverse there.
return reverse('model-detail', kwargs={'brand_slug': self.brand.slug, 'model_slug':self.slug})

django-piston: how to get values of a many to many field?

I have a model with ManyToManyField to another model. I would like to get all the info on a particular record (including the related info from other models) return by JSON.
How to get django-piston to display those values? I would be happy with just primary keys.
Or can you suggest another option ?
I may be wrong, but this should do it:
class PersonHandler(BaseHandler):
model = Person
fields = ('id', ('friends', ('id', 'name')), 'name')
def read(self, request):
return Person.objects.filter(...)
You need to define a classmethod on the handler that returns the many-to-many data, I don't believe Piston does this automatically.
class MyHandler(BaseHandler):
model = MyModel
fields = ('myfield', 'mymanytomanyfield')
#classmethod
def mymanytomanyfield(cls, myinstance):
return myinstance.mymanytomanyfield.all()
My code:
Models:
class Tag(models.Model):
"""docstring for Tags"""
tag_name = models.CharField(max_length=20, blank=True)
create_time = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.tag_name
class Author(models.Model):
"""docstring for Author"""
name = models.CharField(max_length=30)
email = models.EmailField(blank=True)
website = models.URLField(blank=True)
def __unicode__(self):
return u'%s' % (self.name)
class Blog(models.Model):
"""docstring for Blogs"""
caption = models.CharField(max_length=50)
author = models.ForeignKey(Author)
tags = models.ManyToManyField(Tag, blank=True)
content = models.TextField()
publish_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s %s %s' % (self.caption, self.author, self.publish_time)
Handle:
class BlogAndTagsHandler(BaseHandler):
allowed_methods = ('GET',)
model = Blog
fields = ('id' 'caption', 'author',('tags',('id', 'tag_name')), 'content', 'publish_time', 'update_time')
def read(self, request, _id=None):
"""
Returns a single post if `blogpost_id` is given,
otherwise a subset.
"""
base = Blog.objects
if _id:
return base.get(id=_id)
else:
return base.all() # Or base.filter(...)
Works petty good.