DJANGO API REST FRAMEWORK: schema methods - django

Django 1.11.3, python 3.6
I have 2 classes in my view.py:
class ProductList(generics.ListAPIView):
class SampleList(generics.ListAPIView):
Please note the same superclass. Might be relevant: Product is an actual model, Sample is not, SampleList is just a method that calls Product.objects.all() (same code as in ProductList)
All the code inside those classes besides class names is IDENTICAL (including serializer) - I just copied the class and renamed the copy).
The client before it hits urls for those two gets the schema
schema = self.client.get(self.myAppApiUrl)
#works, returns the results
result1 = self.client.action(schema, ["products", "list"])
params = {"id" : some_id, }
#fails with this: coreapi.exceptions.LinkLookupError: Index ['samples']['list'] did not reference a link. Key 'list' was not found.
result2 = self.client.action(schema, ["samples", "list"], params)
When I print "schema", I see
products: {
list([page])
}
samples: {
read(id)
}
My questions are: what makes it to add "list" to schema in the first case and "read" in the second case? And how can I add "list" to the second case? Maybe some schema update needs to be done somehow? The API web server was restarted.
What does that message "Key 'list' was not found" mean? Does this failure have something to do with the params passed? Removing params from the client call does not change anything.
I am also somewhat curious about what is that "page" thing in list and what adds that and but that's not important.

Related

Why do I get an unexpected keyword argument?

I have created a model in my Djano project and the name of the model is Questions in which I have created a primary key called questionid. I am able to get all listings as summaries on one page however when I try to get a detailed listing of one query (say question number 4 out of the several in the table) by going to the http://127.0.0.1:8000/qanda/4 (here 4 is the question number), I get an error that says
TypeError at /qanda/4
question() got an unexpected keyword argument 'question_questionid'
Please see the code below
In my model's views file
def question(request):
questionsm = Questions.objects.order_by('-published_date').filter(is_published=True)
context = {
'questionid': questionsm
}
return render(request,'qanda/question.html', context)
In my model url file
path('<int:question_questionid>', views.question, name='question'),
I will appreciate any help. thanks
You are not passing the var to the view.
def question(request, **id_what_you_want**):
# and if you want an individual view, you should get by id
Questions.objects.get(pk=id_what_you_want)

Django creating model instances - Validation before creation? In manager class? What is manager class for?

Say I have a class "Book" and I want to hit an API to verify the book exists before creating my model.
Do I create my "BookManager" class, override create, hit the api, and throw an exception if not valid or create if valid?
Then in Book I'd write objects = BookManager()
And create a book with.
new_book = Book.objects.create(name)?
Basically, this feels like a good way to organize my code, but I'm not sure if this is intended use for the Manager class as opposed to only modifying the queryset.
Additionally, does anyone have a good reference on how to structure your django rest framework app? Folder structure etc
I will start with very basics. I am assuming you api calls are simple get requests for now which you can achieve with python http package.
(I am assuming the api is a third party api for now)
you can define a simple view let say view name be : bookM
Next you have defined you model with lets say a primary key, book_name, other_attrs, date
now when you hit you api within this view you can get the response from get request
requests.get(url = URL, params = PARAMS)
With this if you find the response sent back with some text or null you can act on model as below :
book= BookSave(
name = "book1",
)
book.save()
If this is not the case you can save error message in python variable and display while rendering html
You can use this view as api and do ajax call from web page, as well in this case you can just return back messages

Django tastypie, possible to return only metadata for a query

I have a Django Tastypie API set up.
I would like to query the database for the count of objects that match a name.
Is this possible on an existing model resource, or do I need to set up a new resource to handle this specific case? (This data is usually returned in the metadata part of the result? Is there an option just to return that from the paramaters?)
So if my url is usually like this:
http://127.0.0.1:8000/api/v1/library/?name__icontains=ABC
Can I add a parameter or change the url so that it only returns the metadata (I only want the number of libraries returned that have a name containing "ABC") rather than all the objects?
You can pass in a get param:
http://127.0.0.1:8000/api/v1/library/?name__icontains=ABC&meta_only=true
and add this method to your resource:
def alter_list_data_to_serialize(self, request, data):
if request.GET.get('meta_only'):
return {'meta': data['meta']}
return data
documentation : http://django-tastypie.readthedocs.org/en/latest/resources.html#alter-list-data-to-serialize

Django get() query not working

this_category = Category.objects.get(name=cat_name)
gives error: get() takes exactly 2 non-keyword arguments (1 given)
I am using the appengine helper, so maybe that is causing problems. Category is my model. Category.objects.all() works fine. Filter is also similarily not working.
Thanks,
Do you have any functions named name or cat_name? If so, try changing them or the variable names you are using and trying again.
The helper maps the Django model manager (Category.objects in this case) back to the class instance of the model via the appengine_django.models.ModelManager. Through the inheritance chain you eventually come to appengine.ext.db.Model.get(cls, keys, **kwargs) so that is why you are seeing this error. The helper does not support the same interface for get that Django does. If you do not want to get by primary key, you must use a filter
To do your query, you need to use the GAE filter function like this:
this_category = Category.objects.all().filter('name =', cat_name).get()

Django : Setting a generic (content_type) field with a real object sets it to None

Update 3 (Read This First) :
Yes, this was caused by the object "profile" not having been saved. For those getting the same symptoms, the moral is "If a ForeignKey field seems to be getting set to None when you assign a real object to it, it's probably because that other objects hasn't been saved."
Even if you are 100% sure that it was saved, check again ;-)
Hi,
I'm using content_type / generic foreign keys in a class in Django.
The line to create an instance of the class is roughly this :
tag = SecurityTag(name='name',agent=an_agent,resource=a_resource,interface=an_interface)
Where both agent and resource are content_type fields.
Most of the time, this works as I expect and creates the appropriate object. But I have one specific case where I call this line to create a SecurityTag but the value of the agent field seems to end up as None.
Now, in this particular case, I test, in the preceding line, that the value of an_agent does contain an existing, saved Django.model object of an agent type. And it does.
Nevertheless, the resulting SecurityTag record comes out with None for this field.
I'm quite baffled by this. I'm guessing that somewhere along the line, something is failing in the ORM's attempt to extract the id of the object in an_agent, but there's no error message nor exception being raised. I've checked that the an_agent object is saved and has a value in its id field.
Anyone seen something like this? Or have any ideas?
====
Update : 10 days later exactly the same bug has come to bite me again in a new context :
Here's some code which describes the "security tag" object, which is basically a mapping between
a) some kind of permission-role (known as "agent" in our system) which is a generic content_type,
b) a resource, which is also a generic content_type, (and in the current problem is being given a Pinax "Profile"),
and c) an "interface" (which is basically a type of access ... eg. "Viewable" or "Editable" that is just a string)
class SecurityTag(models.Model) :
name = models.CharField(max_length='50')
agent_content_type = models.ForeignKey(ContentType,related_name='security_tag_agent')
agent_object_id = models.PositiveIntegerField()
agent = generic.GenericForeignKey('agent_content_type', 'agent_object_id')
interface = models.CharField(max_length='50')
resource_content_type = models.ForeignKey(ContentType,related_name='security_tag_resource')
resource_object_id = models.PositiveIntegerField()
resource = generic.GenericForeignKey('resource_content_type', 'resource_object_id')
At a particular moment later, I do this :
print "before %s, %s" % (self.resource,self.agent)
t = SecurityTag(name=self.tag_name,agent=self.agent,resource=self.resource,interface=self.interface_id)
print "after %s, %s, %s, %s" % (t.resource,t.resource_content_type,type(t.resource),t.resource_object_id)
The result of which is that before, the "resource" variable does reference a Profile, but after ...
before phil, TgGroup object
after None, profile, <type 'NoneType'>, None
In other words, while the value of t.resource_content_type has been set to "profile", everything else is None. In my previous encounter with this problem, I "solved" it by reloading the thing I was trying to assign to the generic type. I'm starting to wonder if this is some kind of ORM cache issue ... is the variable "self.resource" holding some kind proxy object rather than the real thing?
One possibility is that the profile hasn't been saved. However, this code is being called as the result of an after_save signal for profile. (It's setting up default permissions), so could it be that the profile save hasn't been committed or something?
Update 2 : following Matthew's suggestion below, I added
print self.resource._get_pk_value() and self.resource.id
which has blown up saying Profile doesn't have _get_pk_value()
So here's what I noticed passing through the Django code: when you create a new instance of a model object via a constructor, a pre-init function called (via signals) for any generic object references.
Rather than directly storing the object you pass in, it stores the type and the primary key.
If your object is persisted and has an ID, this works fine, because when you get the field at a later date, it retrieves it from the database.
However -- if your object doesn't have an ID, the fetch code returns nothing, and the getter returns None!
You can see the code in django.contrib.contenttypes.generic.GenericForeignKey, in the instance_pre_init and __get__ functions.
This doesn't really answer my question or satisfy my curiosity but it does seem to work if I pull the an_agent object out of the database immediately before trying to use it in the SecurityTag constructor.
Previously I was passing a copy that had been made earlier with get_or_create. Did this old instance somehow go out of date or scope?