virtualenv
is a tool to create isolated Python environments.
to create a new environment
Before we do anything else we ' ll create a new virtual environment, using VIRTUALENV. This would make sure our package configuration was kept nicely isolated from any other projects we ' re working on.
# Create an isolated space virtualenv envsource env/bin/activate
Now the we ' re inside a virtualenv environment, we can install our package requirements.
# Install the required module PIP install djangopip install djangorestframeworkpip install pygments # We'll be using the-the code HIGHL Ighting
Note: To exit the VIRTUALENV environment at any time, just type deactivate
. For more information see the virtualenv documentation.
Entry
Summary : The Getting Started section creates a Django project.
Okay, we ' re ready to get coding. To get started, let's create a new project to work with.
# Create a project under Linux CD ~django-admin.py startproject tutorialcd tutorial[email protected]:~$ Tree tutorialtutorial├── Manage.py└──tutorial ├──__init__.py ├──settings.py ├──urls.py └──wsgi.py1 directory, 5 files
Once that's done we can create the app that we'll use to create a simple Web API.
# Create a Apppython manage.py Startapp snippets
We ' ll need to add our new snippets
app and the rest_framework
app to INSTALLED_APPS
. Let ' s edit the tutorial/settings.py
file:
# config file Installed_apps = (... ') Rest_framework ', ' snippets.apps.SnippetsConfig ',)
Please note this if you ' re using the Django <1.9, you need-to-replace with snippets.apps.SnippetsConfig
snippets
.
Okay, we ' re ready for roll.
Create a model that you can use
For the purposes of this tutorial we ' re going to start by creating a simple Snippet
model that I s used to store code snippets. Go ahead and edit the snippets/models.py
file. Note:good programming practices include comments. Although you'll find them in our repository version of this tutorial code, we had omitted them here's focus on the Cod E itself.
# models.py
From django.db import modelsfrom pygments.lexers import get_all_lexersfrom pygments.styles Import get_all_styleslexers = [item for item in Get_all_lexers () if ITEM[1]] Language_choices = sorted ([(Item[1][0], item[0]) for item in lexers]) style_choices = sorted (item, item) for item in Get_a Ll_styles ()) 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) class Meta: ordering = (' created ',) #排序字段
We ' ll also need to create a initial migration for our snippet model, and sync the database for the first time.
# Initialize database python manage.py makemigrations snippetspython manage.py Migrate
Create a serializer class
The first thing we need to get started in our Web API are to provide a a-to-be serialization and deserialization of the snippet instances into represent Ations such as json
. We can do this by declaring serializers, very similar to Django ' s forms. Create a file snippets
in the directory named serializers.py
and add the following.
#serializers. Pyfrom rest_framework Import serializersfrom snippets.models import Snippet, language_choices, Style_ Choicesclass Snippetserializer (serializers. Serializer): id = serializers. Integerfield (read_only=true) title = serializers. Charfield (Required=false, Allow_blank=true, max_length=100) code = serializers. Charfield (style={' base_template ': ' textarea.html '}) Linenos = serializers. Booleanfield (required=false) language = serializers. Choicefield (choices=language_choices, default= ' python ') style = serializers. Choicefield (choices=style_choices, default= ' friendly ') def create (self, validated_data): "" "Create and R Eturn a new ' Snippet ' instance, given the validated data. "" "Return Snippet.objects.create (**validated_data) def update (self, instance, Validated_data):" " Update and return an existing ' Snippet ' instance, given the validated data. "" "Instance.title = Validated_data.get (' title ', Instance.title) Instance.code = validated_data.get (' code ', instance.code) Instance.linenos = Validated_data.get (' Linenos ', Instance.linenos) Instance.language = Validated_data.get (' language ', instance.language) Instance.style = val Idated_data.get (' style ', Instance.style) Instance.save () Return instance
The first part of the serializer class defines the fields that get serialized/deserialized. The create()
and update()
methods define how fully fledged instances is created or modified when callingserializer.save()
A serializer class is very similar to a Django Form
class, and includes similar validation flags on the various fields, s Uch required
as, max_length
and default
.
The field flags can also control how the serializer should is displayed in certain circumstances, such as when rendering t o HTML. The flag above is {‘base_template‘: ‘textarea.html‘}
equivalent to using on widget=widgets.Textarea
a Django Form
class. This was particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial.
In fact, we can also use the ModelSerializer
class to save some time, as we ll see later, but for now we'll keep our serializer definition explicit.
Using the serializers Serializer
Summary : This section is all operated under the Python shell.
Before we go any further we ' ll familiarize ourselves with the using our new serializer class. Let's drop into the Django shell.
# python shell under Python manage.py shell
Okay, once we ' ve got a few imports out of the the the-a-, let's create a couple of code snippets to work with.
#from snippets.models Import snippetfrom snippets.serializers import Snippetserializerfrom rest_framework.renderers Import jsonrendererfrom rest_framework.parsers Import Jsonparsersnippet = Snippet (code= ' foo = "bar" \ n ') # Instantiate an object and fill in the Code field and save. Snippet.save () snippet = snippet (code= ' Print "Hello, world" \ n ') Snippet.save ()
We ' ve now got a few snippet instances to play with. Let's take a look at serializing one of those instances.
# serializer = Snippetserializer (snippet) #snippet是类Snippet的对象
Serializer.data # {' id ': 2, ' title ': U ', ' Code ': U ' print ' Hello, world ' \ n ', ' Linenos ': False, ' language ': U ' python ', ' sty Le ': U ' Friendly '}
At this point we ' ve translated the model instance into Python native datatypes. To finalize the serialization process we render the data into json
.
#content = Jsonrenderer (). Render (Serializer.data) content# ' {"id": 2, "title": "", "Code": "Print \ \" Hello, world\\ "\\n", "Linenos": false, "language": "Python", "style": "Friendly"} '
Deserialization is similar. First we parse a stream into Python native datatypes ...
#from django.utils.six Import bytesiostream = Bytesio (content) data = Jsonparser (). Parse (Stream)
... then we restore those native datatypes into a fully populated object instance.
#serializer = Snippetserializer (data=data) serializer.is_valid () # trueserializer.validated_data# OrderedDict ([' Title ', '), (' Code ', ' print ' Hello, world "\ n '), (' Linenos ', False), (' Language ', ' Python '), (' style ', ' friendly ')]) seria Lizer.save () # <snippet:snippet object>
Please note that the API is similar to forms. The similarity is even more pronounced when we start the writing views and the use of our serializer.
We can also instantiate querysets instead of model instances. To do this, we just add a flag to the many=True
serializer arguments.
#serializer = Snippetserializer (Snippet.objects.all (), many=true) serializer.data# [ordereddict (' id ', 1), (' title ', U "), (' Code ', u ' foo =" bar "\ n '), (' Linenos ', False), (' Language ', ' Python '), (' style ', ' friendly ')]), ordereddict ([' ID ' , 2), (' title ', U '), (' Code ', u ' print "Hello, world" \ n '), (' Linenos ', False), (' Language ', ' Python '), (' style ', ' friendly ')], ordereddict ([' ID ', 3), (' title ', U '), (' Code ', u ' print "Hello, World"), (' Linenos ', False), (' Language ', ' Python ') ), (' style ', ' friendly ')]]
Using Modelserializers
SnippetSerializer
Our class was replicating a lot of information that's also contained in the Snippet
model. It would be nice if we could keep our code more concise.
available Form
with Django Classes and ModelForm
class in the same way that the rest framework includes Serializer
Classes and ModelSerializer
class.
Let's take a look at using ModelSerializer
class to reconstruct our serializer. Open the file again snippets/serializers.py
, and replace the class with the SnippetSerializer
following.
#class Snippetserializer (serializers. Modelserializer): class Meta: model = Snippet Fields = (' id ', ' title ', ' Code ', ' Linenos ', ' language ', ' style ‘)
Serializers has a good property is that you can check all fields of a serializer instance by the printing its representation. Open the Django shell python manage.py shell
with, and then try the following:
#from snippets.serializers Import Snippetserializerserializer = Snippetserializer () print (repr (serializer)) # Snippetserializer (): # id = Integerfield (label= ' id ', read_only=true) # title = Charfield (Allow_blank=true, Max _length=100, Required=false) # code = Charfield (style={' base_template ': ' textarea.html '}) # Linenos = Booleanfield (required=false) # language = Choicefield (choices=[(' Clipper ', ' FoxPro '), (' Cucumber ', ' Gherkin '), (' Robotframework ', ' robotframework '), (' ABAP ', ' ABAP '), (' Ada ', ' Ada ') ... # style = Choicefield (choices=[(' Autumn ', ' Autumn '), (' Borland ', ' Borland '), (' BW ', ' bw '), (' colorful ', ' colorful ') ...
Notes ModelSerializer
that classes don ' t anything particularly magical, they is simply a shortcut for creating serializer Classe S
- A automatically determined set of fields.
- Simple default implementations for the
create()
and update()
methods.
use our serializer to write a normal Django view
Let's take a look at how to use the new serializer class to write some API views. We are not currently using any rest framework for other functions, we only write some general Django view functions.
Edit snippets/views.py
the file and add the following content.
#from django.http import HttpResponse, jsonresponsefrom django.views.decorators.csrf import Csrf_exemptfrom rest_ Framework.renderers Import jsonrendererfrom rest_framework.parsers import jsonparserfrom snippets.models Import Snippetfrom snippets.serializers Import Snippetserializer
The root of our API will be a view that supports listing all existing fragments, or creating a new fragment.
# @csrf_exemptdef Snippet_list (Request): "" " List all code snippets, or create a new snippet. " " if Request.method = = ' GET ': snippets = Snippet.objects.all () serializer = Snippetserializer (snippets, many= True) return Jsonresponse (Serializer.data, Safe=false) elif Request.method = = ' POST ': data = Jsonparser () . Parse (Request) serializer = Snippetserializer (data=data) if Serializer.is_valid (): serializer.save () return Jsonresponse (Serializer.data, status=201) return Jsonresponse (serializer.errors, status=400)
Note that because we want to be able to access this view function from a client that does not have CSRF token, we need to use csrf_exempt标记视图
the . This is not something you usually want to do, the rest framework view actually uses more obvious behavior than this, but it will now be used for our purposes.
We also need a view corresponding to an individual snippet and can be used to retrieve, update or delete the snippet.
# @csrf_exemptdef Snippet_detail (Request, PK): "" " Retrieve, update or delete a code snippet. " " Try: snippet = Snippet.objects.get (PK=PK) except snippet.doesnotexist: return HttpResponse (status=404) if Request.method = = ' GET ': serializer = Snippetserializer (snippet) return Jsonresponse (serializer.data ) elif Request.method = = ' PUT ': data = Jsonparser (). Parse (request) serializer = Snippetserializer ( Snippet, data=data) if Serializer.is_valid (): serializer.save () return Jsonresponse ( Serializer.data) return Jsonresponse (serializer.errors, status=400) elif Request.method = = ' DELETE ': snippet.delete () return HttpResponse (status=204)
Finally, we need to connect these view functions together. to create a snippets/urls.py
file:
#from django.conf.urls Import urlfrom Snippets Import viewsurlpatterns = [ url (R ' ^snippets/$ ', views.snippet_list), URL (r ' ^snippets/(? p<pk>[0-9]+)/$ ', Views.snippet_detail),]
We also need to tutorial/urls.py
The file connects to the root urlconf to contain the URL of our fragment application.
#from django.conf.urls Import url, includeurlpatterns = [ url (r ' ^ ', include (' Snippets.urls ')),]
It ' s worth noting that there is a couple of edge cases we ' re not dealing with properly at the moment. If we send malformed json
, or if a request is made with a method that the view doesn ' t handle and then we'll end up with a 5 XX "Server Error" response. Still, this ' ll does for now.
Test our first attempt on the Web API
Now we can start a sample server that runs our code snippet.
Exit Shell ...
Quit ()
... and start up Django ' s development server.
#python manage.py runservervalidating Models ... 0 Errors Founddjango version 1.11, using Settings ' tutorial.settings ' development server is running at http://127.0.0.1:800 0/quit the server with Control-c.
In another terminal window, we can test the server.
we can use Curl or Httpie to test our API . Httpie is a user-friendly HTTP client written in Python. Let's install it.
You can use Pip to install Httpie:
#pip Install Httpie
Finally, we can get a list of all the fragments:
#http http://127.0.0.1:8000/snippets/HTTP/1.1 ... [ { "id": 1, "title": "", "code": "foo = \" Bar\ "\ n", "Linenos": false, "language": "Python", " style": "Friendly" }, { "id": 2, "title": "", "code": "Print \" Hello, world\ "\ n", "Linenos": false, "language": " Python ", " style ":" Friendly " }]
Or we can get a specific snippet by referencing its ID:
#http http://127.0.0.1:8000/snippets/2/HTTP/1.1 ... { "id": 2, "title": "", "code": "Print \" Hello, world\ "\ n", "Linenos": false, "language": " Python ", " style ":" Friendly "}
Similarly, you can show the same by accessing these URLs in a Web browser?? The JSON.
API (II)