Django - passing get_slug method in JSON - django

I have a model with contains a get_slug definition:
def Specimen(models.Model):
...
def get_slug(self):
return '%s/%s-%d' % (slugify(self.longname),self.collection.collection_code, self.accessionnumber)
In my view I want to do this:
def show_detail(request):
specimens = Specimen.objects.filter(...)
specimen_data = []
for s in specimens:
specimen_tuple = (str(s.get_slug), format(s.latdecimal), format(s.longdecimal))
specimen_data.append(related_tuple)
context['specimen_data'] = simplejson.dumps(specimen_data)
But when I try to do something with the slug in js (though I have the same result in the shell) I find something like <bound method Specimen.get_slug of <Specimen: Specimen object>> instead of my slug.
How can I force the method to be evaluated prior to passing to JSON?
Any help much appreciated.

Try replacing s.get_slug with s.get_slug() so that you actually call your method.

Related

stringreplace on Django

I need to do the 'string replace' on all my queryset, but I receive the following error:
'QuerySet' object has no attribute 'replace'
def get_profilesJson_view(self):
queryset = Reports.objects.all().values('val_x','val_y').order_by('-time_end')[:1]
new_queryset = queryset.replace(';', ',')
reports_list = list(new_queryset)
return JsonResponse(reports_list, safe=False)
How can I do?
Is it possible to use the '.filter' function? I have not experience with Django
You will need to use Func() to achieve this. You'll need something like this:
def get_profilesJson_view(self):
queryset = Reports.objects.all().update(field_in_queryset_you_want_to_replace=Func(F('string_field'),
Value(';'), Value(','),
function='replace')
Compare with this answer.

Object of type 'Response' has no len() in DRF

ive combined two models. one model's field is annotated to another model's so they can merge. However, when I try to return the data, I get TypeError: object of type 'Response' has no len(). I've followed several examples on stackoverflow and it doesnt seem to be working.
Here's what I have:
class ExploreAPIView(generics.ListAPIView):
def get_queryset(self):
merged_queryset = Place.get_queryset(self.request.user)
usr_pks = [u.pk for u in merged_queryset]
queryset = Place.objects.filter(pk__in=usr_pks)
serialUser = UserSerializer( User.objects.annotate(time=Extract('date_joined','epoch')), many=True).data[:]
serialPlace = PlacesSerializer(queryset, many=True).data[:]
chained_list = sorted(serialPlace +serialUser, key=lambda x: x.get('time'))
return Response(chained_list)
I dont understand why it returns no len() when it returns items if i print out the chained_list
You're returning a Response from get_queryset. But that method is supposed to return a queryset, as the name implies.

django tastypie: how do I control RelatedField "fullness" with url parameter?

I'm using django tastypie to publish a model with a Related (ToOne) field to another model resource. The uri is:
/api/map/?format=json
I want to let the client include a full_pages url parameter to get the full related page resource: /api/map/?full_pages=1&format=json
I don't really understand the Relationship Fields docs, but I made a get_full callable:
def get_full(bundle):
if bundle.request.GET.get('full_pages', 0):
return True
return False
I tried passing the callable to the full argument of ToOneField:
from tastypie.contrib.gis import resources as gis_resources
class MapResource(gis_resources.ModelResource):
page = fields.ToOneField('pages.api.PageResource', 'page', full=get_full)
But when I check with pdb, get_full is never invoked.
So then I tried creating a custom FillableToOneField with a full attribute:
class FillableToOneField(fields.ToOneFIeld):
full = get_full
class MapResource(ModelResource):
page = FillableToOneField('pages.api.PageResource', 'page')
Again, get_full is never invoked.
Is there a better, easier way to do this?
After reading Amyth's answer and django-boundaryservice code, I got this to work by defaulting full to True and altering it in the dehydrate method on the Related PageResource:
class MapResource(gis_resources.ModelResource):
page = fields.ToOneField('pages.api.PageResource', 'page', full=True)
pages.api:
class PageResource(ModelResource):
...
def dehydrate(self, bundle):
if not bundle.request.GET.get('full_pages'):
bundle = bundle.data['resource_uri']
return bundle
You can simply achieve this under the dehydrate method as follows.
class MapResource(ModelResource):
page = fields.ToOneField('pages.api.PageResource', 'page')
def dehydrate(self, bundle):
if bundle.request.Get.get('full_pages'):
self.page.full = True
return bundle
and have them send a request as /api/map/?full_pages=True&format=json

Django: method call in django models

I have a model like this
class User(model):
username = XXX
addr1 = xxx
def get_username(self):
return self.username + 'some message'
def get_addr1(self):
return self.addr1 + 'some string'
and code I want to iterate through each objects and if function with get_+field.name exists then call that method, otherwise return the field itself.
Is there a way to do this? Below is pseudo code:
for field in each_obj._fields.itervalues():
if get_+fieldname exists then:
return that function call
else:
return self.field.name
you can call hasattr(obj, 'get_'+fieldname) to know if the method is there but the best to do that is to actually override __getattr__ in your class and just let Python do the rest.
Take a look at how I fake python attributes here http://ilian.i-n-i.org/faking-attributes-in-python-classes/ and also check for the alternative solution in the comments.
for var in obj.__dict__:
try:
print getattr(obj, 'get_%s' %var)()
except(AttributeError):
print var

Django: get the first object from a filter query or create

In Django, queryset provides a method called get_or_create that either returns an objects or creates an object.
However, like the get method, get_or_create can throw an exception if the query returns multiple objects.
Is there an method to do this elegantly:
objects = Model.manager.filter(params)
if len(objects) == 0:
obj = Model.objects.create(params)
else:
obj = objects[0]
get_or_create() is just a convenience function so there's nothing wrong with writing your own, like pavid has shown or
result = Model.objects.filter(field__lookup=value)[0]
if not result:
result = Model.objects.create(...)
return result
EDIT
As suggested, changed the [:1] slice (which returns a single-entry list) after the filter to [0] (which returns the actual object). The problem with this is it will raise an exception if there is not match to the query.
This will also raise a simliar exception:
Model.objects.filter(field_lookup=value).latest()
Looking at the question again, I'm not sure whether the original poster is looking to return multiple objects/rows, or just a way to get around raising an exception when retrieving a single object/row.
Here's another option?
results = Model.objects.filter(...)
if results.exists():
return results
else:
return Model.objects.create(...)
and another:
result = None
try:
result = Model.objects.get(...)
except Model.DoesNotExist:
result = Model.objects.create(...)
There's nothing wrong with raising & catching exceptions!
From django 1.6 there is a convenience method first() that returns the first result in a filter query, or None.
obj = Model.manager.filter(params).first()
if obj is None:
obj = Model.objects.create(params)
Here's a manager method that will allow you to extend this function elegantly
class FilterOrCreateManager(models.Manager):
"""Adds filter_or_create method to objects
"""
def filter_or_create(self, **kwargs):
try:
created = False
obj = self.filter(**kwargs).first()
if obj is None:
obj = self.create(**kwargs)
created = True
return (obj,created)
except Exception as e:
print(e)
Then ensure you add the manager to whichever model(s) you want to use this on:
class MyObj(models.Model):
objects = FilterOrCreateManager()
After that, you will be able to use it as you would get_or_create:
obj_instance, created = MyObj.filter_or_create(somearg='some value')
I just came across this question and wanted to contribute because no one has suggested actually catching the IndexError.
try:
obj = Model.objects.filter(params)[0]
except IndexError:
obj = Model.objects.create(params)
Do it in one line:
obj = Model.objects.filter(params).first() or Model.objects.create(params)
You can try this:
result = Model.objects.filter(field__lookup=value)[0]
if not result:
result = Model.objects.create(...)
return result
This works for me:
In your view, call something like this:
obj = Category.objects.get_or_create_category(form.cleaned_data.get('name'))
In your Model manager, create a function like this:
class CategoryManager(models.Manager):
def get_or_create_category(self, query):
try:
result = Category.objects.filter(name = query)[0]
except:
result = Category.objects.create(name = query)
return result
The logic is simple. First, try to retrieve the first Category object who's name matches the query string (which is provided by the form). If the retrieval fails (because it doesn't exist), create a new Category with the string as its name. Return the result for use in your view.