Extracting specific data field from Django Rest Framework api - python

I've recently complete the Django Rest Framework api tutorial and am having a difficult time understanding specifically how it's used as a backend for an application I plan to develop (this is my first venture into backend development). To put more simply, I don't understand how querying will work from the front end. Navigating through the api with either the browser or httpie makes sense, but I'm at a loss for how a frontend extracts specified data from a model.
For example, let's say I have the following:
Models
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
highlighted = models.TextField()
Serializers
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'url', 'highlight')
Views
class SnippetViewSet(viewsets.ModelViewSet):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
If I'm a user on the other end of an application, how would I query 'language' inside of the Snippet model? How would I have access to whatever information is in 'language', and in what way would a frontend need to interact with my api to obtain this information?
My problem isn't necessarily how to build the api, but how to interact with it. Any help is greatly appreciated.
(Django 2.0, Python 3.5)

Ok, huge thanks to the Udemy course posted by Mark Winterbottom for the Django Rest Framework. I'll go ahead and leave this here for anybody else struggling with understanding some basic ideas in the Django Rest Framework.
JSON data is extracted by having the frontend hit urls determined by your api. So this becomes a question of "how do I implement some search functionality that's in a url?".
Django uses the Model, View, Controller pattern. A Model is what interacts with the database, and allows you to extract data from it without needing to understand how to query using actual SQL code (uses something called Object Relational Mapping to do this, or ORM, and your Models are in the model.py file). The Controller, how you interact with the pulled data to create/read/update/delete stuff in your api is saved in views.py (a bit counter intuitive, seeing as the View is what you would have in your templates folder [HTML pages and such]).
You can implement something called filters in your Controller (views.py) to allow you to search by specific information to get that ?search=whateveryouresearching url, by including the following:
from rest_framework import filters
and adding this to your ViewSet you want to search:
filter_backends = (filters.SearchFilter,) #allows for search functionality
search_fields = ('name','email') #which can be any Field in your viewset
This ?search=whateveryouresearching created by the filter is how some front end device will access specific searched information (such as a specific user input linke English or Mandarin inside 'language').

Related

How to make the django rest framework POST button work?

I have a model like this:
class Ad(models.Model) :
title = models.CharField(
max_length=200,
validators=[MinLengthValidator(2, "Title must be greater than 2 characters")]
)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
text = models.TextField()
# Shows up in the admin list
def __str__(self):
return self.title
A Viewset like this:
class AdViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows ad to be viewed or edited.
"""
queryset = Ad.objects.all()
serializer_class = AdSerializer
class AdSerializer(serializers.ModelSerializer):
class Meta:
model = Ad
fields = ['id', 'title', 'price', 'text']
I have made the router that I didn't include here because I don't think it's needed to show my issue.
In the Django Rest Framework in /api/ads/ I can see all my previous ads created using the django admin and below a form to post data which looks like this:
When I click on the POST button of the form,it doesn't make a POST request it just reload the page. I can confirm it from the Firefox devtool and the server log, no POST request are made.
So my question is this: how to make this POST button works as expected so I can check my serialiser and everything work as it should ?
Edit: After testing, put, patch, and delete button also don't work, they don't send put/patch/delete header, just get header like post
After a lot of research I found the issue was with ublock origin.
Ublock origin was preventing the browser from making request on localhost so I deactivated it and now it work as expected.
Check your adblocker if you have the same issue.

django rest framework - username field not rendering in browsable api html form

The Django Rest Framework is not displaying username field in my browsable api html form but when I comment down the username in below code it is showing username field in my browsable api html form. I am new to Django so anyone can please help me here
from rest_framework import serializers
from .models import Note
class NoteSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='note-detail', lookup_field='pk')
#username = serializers.StringRelatedField(many=False)
class Meta:
model = Note
fields = ['url', 'id', 'username', 'note_text', 'created_date', 'updated_date']
A StringRelatedField is used to denote relations where the target result is computed using the __str__ method. If you look at the source code, you will notice that a StringRelatedField is just read only. Since the value cannot be edited, you don't see it in the browsable API HTML form.
Once you comment that line, the foreignkey relationship is used and it returns the id of the user. In that case, you do see the field username in the form but the value is not a string but an integer.
I don't think there is a way to make a StringRelatedField editable in the form. For more information please have a look at the relates SO post.
The model serializers will automatically generate a set of fields for you based on the model.

Implementing one to many between an article and page models in Wagtail

I'm trying to setup a Wagtail site with an article to pages structure but I'm struggling. A review article for example may have an introduction page, a benchmark page and a conclusion page. I want to work out how to allow this relationship in wagtail and have it so that editors can add multiple pages to the same article on the same page. I can imagine the pages interface looking a bit like how you have content, promote and settings on pages but with the ability to add, rename and reorder pages. I've tried using a foreign key on a page model that links to an article but I can't get it to be shown in the admin the way I want.
Here is the django version of model layout I was looking to use. You have a parent article that is then made up of one or multiple pages. The pages should be editable, orderable and be created from within one panel in the admin with streamfields:
Class Article(models.Model)
STATE_DRAFT = 0
STATE_REVIEW= 1
STATE_PUBLICATION = 2
STATE_HIDDEN = 3
​
STATE = (
(STATE_DRAFT, 'draft'),
(STATE_REVIEW, 'pending review'),
(STATE_PUBLICATION, 'ready for publication'),
(STATE_HIDDEN, 'hide and ignore'),
)
title = models.CharField(_('title'), max_length=256)
slug = models.SlugField(
_('slug'), unique=True, blank=True, default='', max_length=256
)
description = models.TextField(
_('description'), max_length=256, blank=True, default=''
)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='article'
)
publication = models.DateTimeField(
null=True, blank=True, default=None, db_index=True, help_text='''
What date and time should the article get published
'''
)
state = models.PositiveIntegerField(
default=0, choices=STATE, help_text='What stage is the article at?'
)
featured = models.BooleanField(
default=False,
help_text='Whether or not the article should get featured'
)
​
class Page(Page):
article = models.ForeignKey(
'Article', on_delete=models.CASCADE, related_name='pages'
)
title = models.CharField(max_length=256)
number = models.PositiveIntegerField(default=1) # So pages are ordered
body = models.TextField(blank=True)
As per my comment I don't think you'll be able to achieve everything you're looking for short of implementing an entirely bespoke CMS - but if you're able to bend the UI and data modelling requirements, then Wagtail's RoutablePageMixin is one possible way of achieving the general pattern of editing an article as a single unit, while presenting it as multiple pages on the front-end.
In this approach, you'd make Article a Wagtail Page model, with all of the sub-page content defined as fields (or InlinePanel child models) on that model. (If you want to split the content entry into tabs within the editing interface, see Customising the tabbed interface, although this won't support dynamically adding / reordering them.) You'd then define a URL route and template for each subpage of the article:
from wagtail.core.models import Page
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
class ArticlePage(RoutablePageMixin, Page):
intro = StreamField(...)
main_page = StreamField(...)
conclusion = StreamField(...)
#route(r'^$')
def intro_view(self, request):
render(request, 'article/intro.html', {
'page': self,
})
#route(r'^main/$')
def main_page_view(self, request):
render(request, 'article/main_page.html', {
'page': self,
})
#route(r'^conclusion/$')
def conclusion_view(self, request):
render(request, 'article/conclusion.html', {
'page': self,
})
In this example the three sub-pages are hard-coded, but with some more work (perhaps an InlinePanel child model with a slug field and a StreamField) you could make the subpages dynamic.
I saw gasman already provided an answer to you question, but I'm still going to write up an answer for two reasons:
I think you need some more pointers as to why gasmans' proposal is a better solution than yours, but it's way to much to write in a comment.
I have implemented a similar solution before, where there is a top level 'Article'-like object with multiple reorderable child objects, where the actual content resides.
Why you should make Article a Page subclass
You chose not to make Article a subclass of Page, and you said it was because the Article itself does not contain any content, only metadata about an article. That is not a very strange thought process, but I think you're looking at the wrong requirements for your Article model.
Let's look at Wagtail's own Page model. What kind of functionality does it provide out of the box?
It provides a tree structure with parent and child pages, so that your page can be placed somewhere in the hierarchy of your website
It provides a slug_field, so that Wagtail can automatically handle linking to your page.
It provides functionality for drafting, publishing and unpublishing.
Wagtail doesn't dictate anything about content, leaving you to decide what kind of content you want to put on your Page subclass, if any. Examples of Pages that do not have a body would be:
Contact forms.
Blog index pages.
Good questions you could ask when deciding whether you want a Model to be a subclass of a Page are:
Do I want this object to have it's own url?
Do I want to be able to place this object somewhere inside my website hierarchy?
Do I want to have SEO advantages for the object?
Do I want to be able to publish/unpublish this object or not?
In your case of the Article, you could say yes to almost al these question, so it'd be wise to make it a Page subclass. That way, you don't have to reinvent the wheel.
How you define the actual 'body' of your page is up to you.
You can place the actual content in either snippets, or subpages to that Article. Or you can even choose to create a list of StreamFields inside your model.
How to implement ordered subcontent.
I have implemented a structure like this before.
The way I did this was very similar to what gasman proposes.
In my case, I needed to create a website where you could find an object (like you article) and display different types of explanation modules for it. For each document, I created a ArticlePage, and for each explanation module, I created a snippet called ExplanationModule.
I then created a through model with an ordering, and added a RoutablePageMixin to the class like gasman explains.
The structure looks something like this:
#register_snippet
class ArticlePageModule(models.Model):
...
title = models.CharField(max_length=100)
body = StreamField(LAYOUT_STREAMBLOCKS, null=True, blank=True)
panels = [
FieldPanel('title'),
StreamFieldPanel('body'),
]
class ArticlePageModulePlacement(Orderable, models.Model):
page = ParentalKey('articles.ArticlePage', on_delete=models.CASCADE, related_name='article_module_placements')
article_module = models.ForeignKey(ArticlePageModule, on_delete=models.CASCADE, related_name='+')
slug = models.SlugField()
panels = [
FieldPanel('slug'),
SnippetChooserPanel('article_module'),
]
class ArticlePage(Page, RoutablePageMixin):
# Metadata and other member values
....
content_panels = [
...
InlinePanel('article_module_placements', label="Modules"),
]
#route(r'^module/(?P<slug>[\w\-]+)/$')
def page_with_module(self, request, slug=None):
self.article_module_slug = slug
return self.serve(request)
def get_context(self, request):
context = super().get_context(request)
if hasattr(self, 'article_module_slug'):
context['ArticlePageModule'] = self.article_module_placements.filter(slug = self.article_module).first().article_module
return context
What this does is the following:
Create a ArticlePageModule snippet, which is just some kind of content, like a title and a body.
Create a ArticlePageModulePlacement which links a ArticlePage to a module, and adds the following:
A slug
An Ordering (Because it subclasses the Orderable mixing)
Create a ArticlePage which does two things:
Define a ArticlePageModuleplacement panel, which allows you to add ArticlePageModulePlacements
Subclass RoutablePagemixin, as described in gasman's answer.
This provides you with a Wagtail-proof, reusable and robust way of creating Articles with SubContent.
The modules don't show up in tabs, but will be shown on the page's layout page under a panel called 'Modules'.

How To Separate Objects In Django Admin?

I have an app called 'Product' with the following models.py:
class Product(models.Model):
product_id = models.CharField(max_length=50)
pub_date = models.DateTimeField(default=datetime.now)
title = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
user = models.ForeignKey(User, on_delete=models.CASCADE)
featured = models.BooleanField(default=False)
I want to have two separate sections in Django Admin: Products and Featured Products, depending if featured = True or False.
So by default all products are listed under the Products section. But if featured = True they will be moved to Featured Products section. Can you please help me how to do that? Thanks in advance.
Three steps:
Write a proxy model for model Product.
Change the default manager to only returns featured products.
Register your proxy model in the admin like any other model.
You can read more about it here: Using Proxy Models to Customize the Django Admin
There are a couple of ways to do this. The simplest perhaps is to create a database view, and then encapsulate it using a django model. You can create a view like so in your database console:
CREATE VIEW view_name AS
SELECT columns
FROM tables
[WHERE conditions];
Once you have done that, you can reference the view in django like so:
class FeaturedProduct(modes.Model):
attr1 = models.CharField()
class Meta:
managed = False
db_table = '<name of your view here>'
Make sure that managed is set to False. Here is the relevant documentation for that. You want to do that because django is not creating this model for you, but rather you are creating it yourself.
Another way to do this would be to create a custom Manager. These managers allow you to modify the objects attribute of your model, allowing you to set a queryset that you want. I think you'd want to take a look at the Manager documentation and you can take a look at defining custom querysets for your objects.

django admin filter forein key model when creating

I have 2 models, one is fk of another. I want when creating model filter fk on username creating. I know how to do this in sql, but don't understand how to do in django. I thought about api, am I right? Or I can do it in models or admin interface?
class Post_links( models.Model):
post_id = ParentalKey('Post')
username_can_see=models.CharField(max_length=30, default='')
class Post( models.Model):
some_link =models.CharField(max_length=50, default='')
now on creating new post when I ll check links I want to see only the links can see current user. How can I write this&
Check out the docs, they are quite helpful an easy to read. Here the Django queryset docs https://docs.djangoproject.com/en/1.11/topics/db/queries/
The queryset is the way to query the DB using the Django ORM

Categories