Get an url pk in a generic RESTful view? - django

I'm trying to manage my REST API like that :
http://xxx/users/userid[0-9]+/projects/projectid[0-9]+/tasks/taskid[0-9]+/
So I can access the JSON easily in my website. But, the thing is, I defined my view classes using the REST framework generic views. For example, here is my UserDetail view :
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
But of course I don't want all my users to be displayed, I just want my user with the ID userid to be displayed. I don't really know how to do it, I tried
queryset = User.objects.filter(id=userid)
but of course userid is not defined... Any help please ?
Edit : just to clarify, here is the url that leads to this view :
url(r'^users/(?P<pku>[0-9]+)/$', views.UserDetail.as_view(
), name='user-detail'),

First of all, If you want to use class based views, you should read some more about them. They are thoroughly explained on Django's docs and you can read about the specific generics of the framework you're using on the REST framework docs too. I'm not saying that you haven't read those, just that you seem to be missing some basic concepts that are explained there.
Now, to the problem at hand, if you look at the doc's of the generic view you're extending, you can see that it represents the endpoints for a single instance, meaning that it won't act on all your model's instances (as you seem to assume).
Also, you can see that this view is built on top of a series of other classes, the more critical one being GenericAPIView. On there you can see two things:
The queryset class field in this context is meant for filtering the posible instances you can manipulate, not obtaining the specific instance described on your url.
The lookup_field is the field that defines which attribute from your model will be used for getting the actual instance. You should define this field to whatever field you're going to use on your url to identify your object (generally it's pk). It's also important to note that the url should include a keyword argument corresponding to this value.
Internally, the view will take care of calling the get_object method, which usese the lookup_field value to find the specific model, and then feed that object to the serializer and return the result back to the client.
DISCLAIMER: I've never used Django REST framework, I put this answer togheter by reading the relevants docs and based on my experience.

I guess you need this:
Resolve function (django 1.4)
Then in your view class method you can do:
temp1, args, kwargs = resolve(self.request.path)

Related

Create multiple website templates with django cms or any tool

Can Django be used to create a website for creating custom websites depending on the user needs? There will be more than one template and each user will have a custom url for their websites.
I don't know if this can this be achieved with Django CMS.
Sure, it is possible but it requires ton of work, because you need to write bunch of templates, or/and logic that handles templates.
You could write TemplateMixin, that depending on passed domain, or kwarg in url changes the template in the View. So, for example, it could look like that:
class TemplateMixin:
template_name = None
request = None
model = None
def get_template_names(self):
"""
Return a list of template names to be used for the request.
Must return a list. May not be called if render_to_response() is overridden.
"""
db_settings = Settings.objects.get_or_create()[0]
if self.template_name is None:
raise ImproperlyConfigured(
'TemplateResponseMixin requires either a definition of '
'\"template_name\" or an implementation of \"get_template_names()\"')
template = db_settings.website_template
ready_template = '/'.join([template, self.template_name])
return [ready_template]
There are also solutions for handling multiple domains, so you could detect what current domain is via self.request in get_template_names method. The templates are handled by prefix. The kwargs also should be in self.kwargs, so you can detect which site you need to present via custom namespace url.
You can also create WebsiteSettings model that handles various templates, and is manageable via simple custom dashboard panel, and belongs to user, or user groups. The fields that it should have is 'template' with choices attribute, relation to User (or CustomUser model), and bunch of settings you want to give a user (or you could have different model('s) for that).
The solution I bring here is simple to show the idea - but it can be insufficient, to accomplish what you really want you must write the whole mixins, views etc. logic yourself.

DRF: How to access "context" inside custom DecimalField class?

I am subclassing the DecimalField class from Django RestFramework and need to access context. Formatting for decimal fields includes settings that are user-selectable, so I need to access the user object (which, I assume, should be inside context) inside the to_representation() method.
Via debug, I've looked at all properties of self inside my CustomDecimalField class, but, of course, I can't see class methods, so I don't know if there's an appropriate "get" method to get context. I've tried self.context (as a property), self.get_context(), and self.getcontext(), but none worked.
I found this announcement re: require_context:
https://www.django-rest-framework.org/community/3.11-announcement/
...but it seems to be valid only for validation and default value methods.
This seems like such a simple thing; hard to believe it is so difficult.
You have to manually set the user inside the context. So, in your view:
serializer = YourSerializer(your_data, context={'user': request.user})
And you will then be able to access it in your to_representation() method:
def to_representation(self, instance):
user = self.context.get("user")
Please see the documentation for more information.

Can I decorate a Django REST Framework ModelViewSet Methods?

Django REST Framework ModelViewset offers the standard methods to update / create / retrieve objects. I would like to overwrite these method in the sense that they should keep their original behaviour as given by ModelViewSet, but just add to that a check in the beginning if the incoming request contains a certain query parameter. How can I do that?
Eg. I would like to have
class MyRessourceViewSet(viewsets.ModelViewSet):
queryset = MyRessource.objects.all()
serializer_class = MyRessourceSerializer
def create(self, request):
# Check if "key" query param is in request
if "key" in self.request.data:
create(request) # <<-- HERE call the "default" create method.
To call the default behavior, you can do super().create(request). Often when overriding a method, we add behavior before or after doing this.
Note that "decorate" has a technical meaning in Python and this isn't it. If you are interested in learning more, you can google something like "python decorator".

How do I know what functions are run in Generic Views?

I am new to Django and scratching my head with the following question
how do I know which function is run in specific processes?
for example in below view, retrieve function is executed. I flipped the documentation, however, could not find anything named retrieve to overwrite
class ProfileRetrieveAPIView(RetrieveAPIView):
serializer_class = ProfileSerializer
def retrieve(self, request, username, *args, **kwargs):
print("hey yo i am running 01")
try:
profile = Profile.objects.select_related('user').get(
user__username=username
)
except Profile.DoesNotExist:
raise
serializer = self.serializer_class(profile)
return Response(serializer.data)
In general the generic views in Django Rest Framework are made by inheriting from various mixins. It is also documented which mixin a view is inheriting from. For example the documentation for RetrieveAPIView which you use is as follows:
Used for read-only endpoints to represent a single model instance.
Provides a get method handler.
Extends:
GenericAPIView,
RetrieveModelMixin
So you can override get here if needed (it actually calls the retrieve method here). If you further follow the link for RetrieveModelMixin you will see that it's documentation has this line:
Provides a .retrieve(request, *args, **kwargs) method, that implements
returning an existing model instance in a response.
Here we can see it mentions that it provides a retrieve method. So you just need to check the documentation for the super classes for a respective class if you want to know what method is used by it.
Note: If all else fails when searching the documentation consider simply looking at it's the source code on GitHub or in your own IDE.
;)
According to DRF documentation, there is a default mapping the views and the router:
list is for GET on a list of objects, like /users/
retrieve is for GET on a single object, like /users/3/
create is for POST on a non-detailed endpoint, like /users/
update is for PUT on a detailed endpoint, like /users/3/
partial_update is for PATCH on a detailed endpoint, like /users/3/
destroy is for DELETE on a detailed endpoint, like /users/3/
Those are the expected/standard mappings within DRF views and viewsets
You can view some examples here: https://www.django-rest-framework.org/api-guide/generic-views/#mixins

How to reuse existing admin models to display a custom Queryset?

I'm writing my first application in Django, and now that the base is covered, I try to enhance a bit the admin part to ease up my life.
I have two classes in my model:
class Puzzle(models.Model):
puzzle_pieces = models.ForeignKey(PuzzlePieces,on_delete=models.CASCADE)
class PuzzlePieces(models.Model):
puzzle_pieces = models.CharField(max_length=255, default='empty')
with admin models in place too:
class PuzzlePiecesAdmin(admin.ModelAdmin):
class PuzzleAdmin(admin.ModelAdmin):
I want to define in the PuzzlePiecesAdmin class a custom action to display (reusing the format defined in PuzzleAdmin) all the puzzles which are linked to the selected puzzle_pieces
I know how to create custom actions,
def show_related_puzzles(modeladmin, request, queryset):
I've seen on the internet different ways to filter directly within the PuzzleAdmin class,
but not how to set the queryset from the outside.
But I don't understand how to launch the display of an instance of PuzzleAdmin limited to the queryset I will define within show_related_puzzles.
Could anyone explain me how to proceed?
Thanks in advance
OK, I found the start of an answer in the following:
https://stackoverflow.com/a/1652377/12505071
the standard changelist view accepts normal queryset filter parameters as GET arguments. So you can do:
/admin/puzzles/puzzle/?puzzle_pieces__pk=21
I finally found out by trial and error how to add another filter:
/admin/puzzles/puzzle/?difficulty__id__exact=35&puzzle__pk=560
Could anybody tell me how to add a second value for the same parameter?