I'm working on a backend for an app and writing a function to retrieve data from several tables and then construct a httpresponse from that.
What I would like to do is get a vaccine, then all the diseases for that vaccine and then construct something(object, list, dict, ...) containing everything.
What I've got so far is:
def vaccinepack(request, country_id):
vaccines = Vaccine.objects.filter(diseases__countries__id=country_id)
diseases = []
json = serializers.get_serializer("json")()
response = HttpResponse()
for v in vaccines:
dis = Disease.objects.filter(vaccine=v.id)
disdata = ""
for d in dis:
disdata += json.serialize([d], ensure_ascii=False)
json.serialize([v, disdata], ensure_ascii=False, stream=response)
return response
But I'm running to trouble when serialising [v, disdata].
'list' object has no attribute '_meta'.
I'm rather new to Django so I'm not sure what's the proper way of doing this.
Here's my models:
class Disease(models.Model):
name = models.CharField(max_length=100)
text = models.CharField(max_length=2000)
countries = models.ManyToManyField(Country, blank=True)
def __unicode__(self):
return self.name
class Vaccine(models.Model):
name = models.CharField(max_length=100)
text = models.CharField(max_length=2000)
diseases = models.ManyToManyField(Disease, blank=True)
def __unicode__(self):
return self.name
The immediate cause of your error message is because you're passing a list object to the Django serializer, but it's expecting a QuerySet.
What I would do is to build up the data structure as a series of nested Python dictionaries, and then convert it all to JSON at the end with json.dumps(). (Note that's the actual built-in json library, which you've shadowed with the serializer.) Something like (untested):
serializer = serializers.get_serializer('python')
vaccine_list = serializer.serialize(vaccines)
for i, v in enumerate(vaccines):
diseases = v.diseases.all()
disease_list = serializer.serialize(diseases)
vaccine_list[i]['fields']['diseases'] = disease_list
data = json.dumps(vaccine_list)
Related
my models.py
class WebFieldType(models.Model):
WEBFIELD_CHOICES = ( ('FACEBOOK', 'fb'), ('INSTAGRAM', 'Insta') )
webfield_type = models.CharField(null=True, blank=True, max_length=30, choices=WEBFIELD_CHOICES)
def __unicode__(self):
return '{}'.format(self.webfield_type)
class WebTokens(models.Model):
token_name = models.TextField()
web_field_type = models.ManyToManyField(WebFieldType)
def __unicode__(self):
return '{}-{}'.format(self.token_name,self.web_field_type )
Now in shell if I do like:
WebFieldType.objects.all().values('webfield_type'), it is returning [{'webfield_type' : 'FACEBOOK'}, {'webfield_type' : 'INSTAGARAM'}]
But if I do like
WebTokens.objects.all().values('token_name','web_field_type') it is returning
[{'token_name' : 'some_token_name', 'web_field_type' : 1}]
As you can see in web_field_type it is returning id, but I need name.
Even tried using return '{}'.format(self.get_webfield_type_display()) in WebTokens model but in vain.
So basically I need everything that is stored in WebTokens model when I make a call to it.
You did not specify what is template_name attribute in the WebTokens model. But I'll try to get your point. What are doing is that you take the values from ManyToMany field which is in your case web_field_type: 1. So if you want to get all vallues from the model and serialize it, then it would be more complicated than this. Consider creating method in WebTokens model.
EDITED
#property
def web_field_type_types(self):
names = list()
for obj in self.web_field_type.all():
names.append(obj.get_type_display())
return str(names)
And then using it in your queries so you can get string of ids with
webtoken.web_field_type_types
I want to write all types of complex queries,
for example :
If someone wants information "Fruit" is "Guava" in "Pune District" then they will get data for guava in pune district.
htt//api/?fruit=Guava&?district=Pune
If someone wants information "Fruit" is "Guava" in "Girnare Taluka" then they will get data for guava in girnare taluka.
htt://api/?fruit=Guava&?taluka=Girnare
If someone wants information for "Fruit" is "Guava" and "Banana" then they will get all data only for this two fruits, like wise
htt://api/?fruit=Guava&?Banana
But, when I run server then I cant get correct output
If i use http://api/?fruit=Banana then I get all data for fruit which is banana, pomegranate, guava instead of get data for fruit is only banana. So I am confuse what happen here.
can you please check my code, where I made mistake?
*Here is my all files
models.py
class Wbcis(models.Model):
Fruit = models.CharField(max_length=50)
District = models.CharField(max_length=50)
Taluka = models.CharField(max_length=50)
Revenue_circle = models.CharField(max_length=50)
Sum_Insured = models.FloatField()
Area = models.FloatField()
Farmer = models.IntegerField()
def get_wbcis(fruit=None, district=None, talkua=None, revenue_circle=None, sum_insured=None, area=None,min_farmer=None, max_farmer=None, limit=100):
query = Wbcis.objects.all()
if fuit is not None:
query = query.filter(Fruit=fruit)
if district is not None:
query = query.filter(District=district)
if taluka is not None:
query = query.filter(Taluka=taluka)
if revenue_circle is not None:
query = query.filter(Revenue_circle= revenue_circle)
if sum_insured is not None:
query = query.filter(Sum_Insured=sum_Insured)
if area is not None:
query = query.filter(Area=area)
if min_farmer is not None:
query = query.filter(Farmer__gte=min_farmer)
if max_farmer is not None:
query = query.filter(Farmer__lt=max_farmer)
return query[:limit]
Views.py
class WbcisViewSet(ModelViewSet):
queryset = Wbcis.objects.all()
serializer_class = WbcisSerializer
def wbcis_view(request):
fruit = request.GET.get("fruit")
district = request.GET.get("district")
taluka = request.GET.get("taluka")
revenue_circle = request.GET.get("revenue_circle")
sum_insured = request.GET.get("sum_insured")
area = request.GET.get("area")
min_farmer = request.GET.get("min_farmer")
max_farmer = request.GET.get("max_farmer")
wbcis = get_wbcis(fruit, district, taluka,revenue_circle,sum_insured,area, min_farmer, max_farmer)
#convert them to JSON:
dicts = []
for wbci in wbcis:
dicts.append(model_to_dict(wbci))
return JsonResponse(dicts)
Serializers.py
from rest_framework.serializers import ModelSerializer
from WBCIS.models import Wbcis
class WbcisSerializer(ModelSerializer):
class Meta:
model = Wbcis
fields=('id','Fruit','District','Sum_Insured','Area','Farmer','Taluka','Revenue_circle',)
whats need changes in this code for call these queries to get exact output?
I don't think that you're actually calling that view, judging by your usage I presume you're calling the viewset itself and then ignoring the query params.
You should follow the drf docs for filtering but essentially, provide the get queryset method to your viewset and include the code you currently have in your view in that
class WbcisViewSet(ModelViewSet):
queryset = Wbcis.objects.all() # Shouldn't need this anymore
serializer_class = WbcisSerializer
def get_queryset(self):
fruit = self.request.query_params.get("fruit")
....
return get_wbscis(...)
In this model:
class Rank(models.Model):
User = models.ForeignKey(User)
Rank = models.ForeignKey(RankStructure)
date_promoted = models.DateField()
def __str__(self):
return self.Rank.Name.order_by('promotion__date_promoted').latest()
I'm getting the error:
Exception Value:
'str' object has no attribute 'order_by'
I want the latest Rank as default. How do I set this?
Thanks.
Update #1
Added Rank Structure
class RankStructure(models.Model):
RankID = models.CharField(max_length=4)
SName = models.CharField(max_length=5)
Name = models.CharField(max_length=125)
LongName = models.CharField(max_length=512)
GENRE_CHOICES = (
('TOS', 'The Original Series'),
('TMP', 'The Motion Picture'),
('TNG', 'The Next Generation'),
('DS9', 'Deep Space Nine'),
('VOY', 'VOYAGER'),
('FUT', 'FUTURE'),
('KTM', 'KELVIN TIMELINE')
)
Genre = models.CharField(max_length=3, choices=GENRE_CHOICES)
SPECIALTY_OPTIONS = (
('CMD', 'Command'),
('OPS', 'Operations'),
('SCI', 'Science'),
('MED', 'Medical'),
('ENG', 'Engineering'),
('MAR', 'Marine'),
('FLT', 'Flight Officer'),
)
Specialty = models.CharField(max_length=25, choices=SPECIALTY_OPTIONS)
image = models.FileField(upload_to=image_upload_handler, blank=True)
This is the Rank_structure referenced by Rank in Class Rank.
THe User Foreign key goes to the standard User table.
The reason that you’re getting an error is because self.Rank.Name is not a ModelManager on which you can call order_by. You’ll need an objects in there somewhere if you want to call order_by. We can’t help you with the django formatting for the query you want unless you also post the model definitions as requested by several commenters. That said, I suspect that what you want is something like:
def __str__(self):
return self.objects.filter(Rank_id=self.Rank_id).order_by('date_promoted').latest().User.Name
I have this model in my code:
class Conversation(models.Model):
participants = models.ManyToManyField(User, related_name="message_participants")
and I need to filter this "Conversation" model objects by the "participants" many-to-many field.
meaning: I have for example 3 User objects, so I want to retrieve the only "Conversation" objects that has this 3 Users in it's "participants" field.
I tried doing this:
def get_exist_conv_or_none(sender,recipients):
conv = Conversation.objects.filter(participants=sender)
for rec in recipients:
conv = conv.filter(participants=rec)
where sender is a User object and "recipients" is a list of User objects.
it won't raise error but it gives me the wrong Object of Conversation.
Thanks.
edit:
A more recent try lead me to this:
def get_exist_conv_or_none(sender,recipients):
participants=recipients
participants.append(sender)
conv = Conversation.objects.filter(participants__in=participants)
return conv
which basically have the same problem. It yields Objects which has one or more of the "participants" on the list. but what Im looking for is exact match of the many-to-many object.
Meaning, an Object with the exact "Users" on it's many-to-many relation.
edit 2: My last attempt. still, won't work.
def get_exist_conv_or_none(sender,recipients):
recipients.append(sender)
recipients = list(set(recipients))
conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0])
for participant in recipients[1:]:
conv.filter(participants=participant)
conv.filter(count=len(recipients))
return conv
Ok so I found the answer:
In order to make an exact match I have to chain-filter the model and then make sure it has the exact number of arguments it needs to have, so that the many-to-many field will have in it all the objects needed and no more.
I will check for the objects number using annotation: ( https://docs.djangoproject.com/en/dev/topics/db/aggregation/ )
ended up with this code:
def get_exist_conv_or_none(recipients):
conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0])
for participant in recipients[1:]:
conv = conv.filter(participants=participant)
conv = conv.filter(count=len(recipients))
return conv
For fast search using database index, I use this code:
class YandexWordstatQueue(models.Model):
regions = models.ManyToManyField(YandexRegion)
regions_cached = models.CharField(max_length=10000, editable=False, db_index=True)
phrase = models.ForeignKey(SearchPhrase, db_index=True)
tstamp = models.DateTimeField(auto_now_add=True)
class YandexWordstatRecord(models.Model):
regions = models.ManyToManyField(YandexRegion)
regions_cached = models.CharField(max_length=10000, editable=False, db_index=True)
phrase = models.ForeignKey(SearchPhrase, db_index=True)
Shows = models.IntegerField()
date = models.DateField(auto_now_add=True)
#receiver(m2m_changed, sender=YandexWordstatRecord.regions.through)
#receiver(m2m_changed, sender=YandexWordstatQueue.regions.through)
def yandexwordstat_regions_changed(sender, **kwargs):
if kwargs.get('action') in ['post_add', 'post_remove']:
instance = kwargs.get('instance')
l = list(instance.regions.values_list('RegionID', flat=True))
l.sort()
instance.regions_cached = json.dumps(l)
instance.save()
This adds overhead when saving, but now I can perform fast filter with this snippet:
region_ids = [1, 2, 3] # or list(some_queryset.values_list(...))
region_ids.sort()
regions_cahed = json.dumps(region_ids)
YandexWordstatQueue.objects.filter(regions_cached=regions_cached)
I'm able to return django models that have only CharFields/Dates/Integers, but now I'm trying to return models that have ForeignKey properties and I'm getting this error in Flex in my NetStatusEvent.NET_STATUS onError event handler:
m_info Object (#16491fe9)
code "NetConnection.Call.Failed"
description "HTTP: Status 500"
details "http://127.0.0.1:8000/gateway/"
level "error"
Here are the models that matter in models.py:
class RewardActBase(models.Model):
user = models.ForeignKey(User)
start_date = models.DateTimeField(blank=True, null=True)
progress_value = models.IntegerField(default=0)
coupon_act = models.ForeignKey(CouponAct)
class Meta:
abstract = True
class ChallengeAct(RewardActBase):
challenge = models.ForeignKey(Challenge)
def __unicode__(self):
return self.challenge.title'
class CouponAct(models.Model):
coupon = models.ForeignKey(Coupon)
earned_date = models.DateTimeField(blank=True, null=True)
redeemed_date = models.DateTimeField(blank=True, null=True)
expiration_date = models.DateTimeField(blank=True, null=True)
def __unicode__(self):
return self.coupon.title
Then when I want to get retrieve these object via pyamf, this is the method I'm using, which is giving me the error I listed above:
#login_required
def get_challenge_act(http_request, location_id):
user = http_request.user
c = ChallengeAct();
c.challenge = Challenge.objects.select_related().get(id=1)
c.start_date = datetime.now()
c.progress_value = 1
c.user = user
new_coupon_act = CouponAct()
new_coupon_act.coupon = Coupon.objects.select_related().get(id=c.challenge.coupon.id)
new_coupon_act.earned_date = datetime.now()
new_coupon_act.save()
c.coupon_act = new_coupon_act
c.save()
return c
The interesting thing is that if I change my get_challenge_act method to return a property of the ChallengeAct object, I don't get the error. So I can return properties or objects that belong to the ChallengeAct, but not the ChallengeAct itself. For example, the following code returns a Challenge object with no errors:
return c.challenge
So it appears that there is some problem returning a Django model with foreginkey models as properties? Am I doing something wrong?
By process of elimination, I found that it was the User object on the ChallengeAct that was causing the problem, and I got the ambiguous 500 error to go away by setting the user object to None after saving and right before returning.
#login_required
def get_challenge_act(http_request, location_id):
user = http_request.user
c = ChallengeAct();
c.challenge = Challenge.objects.select_related().get(id=1)
c.start_date = datetime.now()
c.progress_value = 1
c.user = user
new_coupon_act = CouponAct()
new_coupon_act.coupon = Coupon.objects.select_related().get(id=c.challenge.coupon.id)
new_coupon_act.earned_date = datetime.now()
new_coupon_act.save()
c.coupon_act = new_coupon_act
c.save()
c.user = None
return c
I'd love to hear why that happened though. Anyone have any ideas?
--update-- I found that I can see what the actual 500 error is by looking at the terminal log, after running my runserver command. So the actual error was:
Could not import "cpyamf.amf3": Disallowed C-extension or built-in module
I'm not sure what that is, or why I get it only when trying to include user object on my return result, but for now I can just not include the user object to avoid the error.