I saw swagger documentation of Flask and Django. In Flask I can design and document my API hand-written.(Include which fields are required, optional etc. under parameters sections).
Here's how we do in Flask
class Todo(Resource):
"Describing elephants"
#swagger.operation(
notes='some really good notes',
responseClass=ModelClass.__name__,
nickname='upload',
parameters=[
{
"name": "body",
"description": "blueprint object that needs to be added. YAML.",
"required": True,
"allowMultiple": False,
"dataType": ModelClass2.__name__,
"paramType": "body"
}
],
responseMessages=[
{
"code": 201,
"message": "Created. The URL of the created blueprint should be in the Location header"
},
{
"code": 405,
"message": "Invalid input"
}
]
)
I can chose which parameters to include, and which not. But how do I implement the same in Django? Django-Swagger Document in
not good at all. My main issue is how do I write my raw-json in Django.
In Django it automates it which does not allows me to customize my json. How do I implement the same kind of thing on Django?
Here is models.py file
class Controller(models.Model):
id = models.IntegerField(primary_key = True)
name = models.CharField(max_length = 255, unique = True)
ip = models.CharField(max_length = 255, unique = True)
installation_id = models.ForeignKey('Installation')
serializers.py
class ActionSerializer(serializers.ModelSerializer):
class Meta:
model = Controller
fields = ('installation',)
urls.py
from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
from modules.actions import views as views
urlpatterns = patterns('',
url(r'(?P<installation>[0-9]+)', views.ApiActions.as_view()),
)
views.py
class ApiActions(APIView):
"""
Returns controllers List
"""
model = Controller
serializer_class = ActionSerializer
def get(self, request, installation,format=None):
controllers = Controller.objects.get(installation_id = installation)
serializer = ActionSerializer(controllers)
return Response(serializer.data)
My questions are
1) If I need to add a field say xyz, which is not in my models how do I add it?
2) Quiet similar to 1st, If i need to add a field which accepts values b/w 3 provided values,ie a dropdown. how do I add it?
3) How I add an optional field? (since in case of PUT request, I might only update 1 field and rest leave it blank, which means optional field).
4) Also how do I add a field that accepts the json string, as this api does?
Thanks
I can do all of these things in Flask by hardcoding my api. But in Django, it automates from my models, which does not(as I believe) gives me the access to customize my api. In Flask, I just need to write my API with hands and then integrate with the Swagger. Does this same thing exist in Django?
Like I just need to add the following json in my Flask code and it will answer all my questions.
# Swagger json:
"models": {
"TodoItemWithArgs": {
"description": "A description...",
"id": "TodoItem",
"properties": {
"arg1": { # I can add any number of arguments I want as per my requirements.
"type": "string"
},
"arg2": {
"type": "string"
},
"arg3": {
"default": "123",
"type": "string"
}
},
"required": [
"arg1",
"arg2" # arg3 is not mentioned and hence 'opional'
]
},
Would this work:
class TriggerView(APIView):
"""
This text is the description for this API
mykey -- My Key parameter
"""
authentication_classes = (BasicAuthentication,)
permission_classes = (IsAuthenticated,)
def post(self, request, format=None):
print request.DATA
return Response(status=status.HTTP_202_ACCEPTED)
the POST request:
Authorization:Basic YWRtaW46cGFzcw==
Content-Type:application/json
{"mykey": "myvalue"}
Related
Previously I had been working with the back-end, but after few months of not coding, I'm now not really comfortable with the code I have now. So I use Djoser and I have this in my project settings.py file
...
'SERIALIZERS': {
'user_create': 'backend.accounts.serializers.UserCreateSerializer',
'user': 'backend.accounts.serializers.UserCreateSerializer',
'user_delete': 'djoser.serializers.UserDeleteSerializer',
}
...
This should override the default Djoser serializer, but as I can see it does nothing.
/auth/users/me/ - Returns this
{
"email": "test#gmail.com",
"id": 1,
"username": "test"
}
but I have this as my serializer inside backend/accounts/serializers
class UserCreateSerializer(UserCreateSerializer):
delete_request = DeleteUserSerializer(read_only=True)
class Meta(UserCreateSerializer.Meta):
model = User
fields = (
'id',
'email',
'username',
'password',
'delete_request',
)
Why does it not override?
/users/me/ endpoint is handled by current_user key in djoser serializers dict, so you should add it:
'SERIALIZERS': {
# [...]
'current_user': 'backend.accounts.serializers.UserSerializer',
# [...]
}
You can have more information about djoser serializers on the documentation.
They say:
Key 'user' is used for general users whereas 'current_user' lets you set serializer for special /users/me endpoint. They both default to the same serializer though.
And by the way I think you should create a serializer inheriting from djoser.serializers.UserSerializer and not from djoser.serializers.UserCreateSerializer for user and cuttent_user keys.
I know I am not the first person to ask this question, but I still couldn't find an answer for my situation.
I have a Django environment that works very well, I know I only have one (1) settings.py file and I know that my environment accesses it correctly.
I recently added a new endpoint to my project. I defined its URL in urls.py
urlpatterns = [
...
url(PREFIX + r"^v1/alerts/debug$", alerts_views_v1.debug_trigger_alert_notification),
...
]
It is connected to a method that is in a the file alerts/views_v1.py but is not in any particular class:
#api_view(["POST"])
def debug_trigger_alert_notification(request):
"""
Trigger an Alert. i.e. Create an Alertnotification.
This function is meant to be called by the scheduler service.
"""
workspace_slug = request.data.pop("workspace")
with in_database(workspace_slug, write=True):
serializer = AlertNotificationSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response()
When I send a request to this URL, I receive the following 500 error:
ImproperlyConfigured at /v1/alerts/debug
settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.
In my settings.py file, my DATABASES variable seems correct (though it is built in a roundabout way):
DEFAULT_DATABASES = {
"default": { # This DB is supposed to always have the latest version of the schema described by the Django Model
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ["REFERENCE_DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ["DB_HOST"],
"PORT": os.environ["DB_PORT"],
}
}
# Retrieve all existing workspace databases:
try:
_existing_workspace_database_names = ExistingWorkspace(
db_user=DEFAULT_DATABASES["default"]["USER"],
db_host=DEFAULT_DATABASES["default"]["HOST"],
db_password=DEFAULT_DATABASES["default"]["PASSWORD"],
).list_existing_workspaces()
except Exception as e:
log.critical("settings.py: Error retrieving list of existing databases.")
raise e
else:
log.info("settings.py: Successfully retrieved list of existing databases.")
WORKSPACE_DATABASES = {
db_name_to_slug(existing_workspace_database_name): {
"ENGINE": "django.db.backends.postgresql",
"NAME": existing_workspace_database_name,
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ["DB_HOST"],
"PORT": os.environ["DB_PORT"],
}
for existing_workspace_database_name in _existing_workspace_database_names
}
DATABASES = {**DEFAULT_DATABASES, **WORKSPACE_DATABASES}
DATABASE_ROUTERS = ["dynamic_db_router.DynamicDbRouter"]
What can I do?
I am trying to insert a data table in my current project. I was wondering if it is possible to insert one whole table inside one particular Django Model. If I let the user fill this table, like in the example below:
How could I send that data into my model after POST?
As you stated in the comment under the question, your table has got fixed fields which should correspond to your already prepared database model - each table column is a separate model attribute. So the only thing you need to do is send each row input by the user as a separate entry in the JSON POST request which your code will convert into a model class instance and save it to the database. The JSON sent in the POST request could look something like this:
{
"table_entries": [
{
"sku": "22A",
"name": "2B",
"description": "2C",
"price": "2D",
"size": "2E"
},
{
"sku": "3A",
"name": "3B",
"description": "3C",
"price": "3D",
"size": "3E"
},
...
]
}
The functionality you're asking for is quite well covered in the Django REST Framework (DRF), a toolkit to build Web APIs. The general pipeline will be:
Receive the POST request in views.py
Use a model serializer that you need to prepare to convert the request data to a Python object
Save this object in the database
So the views could look something like that (based on examples from the DRF views docs):
from myapp.models import Table
from myapp.serializers import TableSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
class TableView(APIView):
"""
Create a new entry in the Table.
"""
def post(self, request, format=None):
table_entries = request.data["table_entries"]
for entry in table_entries:
# serialize each row
serializer = TableSerializer(data=entry)
if serializer.is_valid():
# you can store the objects in some list and if the're all fine
# use serializer.save() for each of them to save them into the db
else:
# At least one of the entries data is corrupted. You probably want
# to reject the whole request
# ...
This is to show you the general workflow, because the question is quite broad. To go further into details I strongly advise to have a look into the DRF tutorial, as it covers well the topic.
i have a django-restframwork project where i have set MEDIA_URL in settings.py file. the problen is when serialize a model i get the file name with media prefixed.
Here the response i am getting
{
"employees": [
{
"id": 1,
"name": "neki",
"doc": "/media/simple-nature-wallpapers-free-download-for-desktop-45.jpg"
}
]
}
But i want the response without media prefixed like this
{
"employees": [
{
"id": 1,
"name": "neki",
"doc": "simple-nature-wallpapers-free-download-for-desktop-45.jpg"
}
]
}
I have two solutions. Both of them have some problems
I can remove MEDIA_URL from setting.py file (Problem is i cant access the file from storage)
Or i can save the file name as models.CharField(). (Problem is i cant save file from ModelSerializer automatically)
So my Question is how to solve these problem.
Override the to_represenataion() method of serializer
class YourSerializer(.....):
# your code
def to_representation(self, instance):
rep = super(YourSerializer,self).to_representation(instance)
try:
rep['doc'] = rep['doc'].split('/')[-1]
except KeyError:
return rep
return rep
If you sahre your serializer and views, i can help you better. but the short answer is:
if you send this response with post method , you can override create method in your views(if you are using generics.CreateAPIView). if get, override retrive and ... .
and then change your response as you want. you access to your response data there.
share your view and serializer for more cleare answer.
I'm using djangorestframework (which I love) and I am attempting to POST some data from the front end to the REST view/serializer waiting to accept it.
When I log into the REST API back end (that django rest provides for users to be able to test their queries), I can submit this information, and it will successfully pass the information to the back end and save the object:
{
"user": 1,
"content": "this is some content",
"goal":
{
"competencies[]": [
32
],
"active": false,
"completed": false,
"user": 1
}
}
But, when I run the POST request, it fails, stating that:
{"goal": ["This field is required."]}
So that's interesting. It works from the back end, but not the front.
Here's my code for added help:
//the ajax request
$.ajax({
// obviates need for sameOrigin test
crossDomain: false,
//adds a CSRF header to the request if the method is unsafe (the csrfSafeMethod is in base.html)
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
//needed because we're setting data, I think.
type: "POST",
//target API url
url: '/api/goal-status/add',
data: this_instead,
//on success, reload the page, because everything worked
success: function(){
location.reload();
alert("In the goal-add click listener");
},
//we'll have to find something better to do when an error occurs. I'm still thinking through this. There will probably just have to be some standardized way of going about it.
error: function(){
alert('An error ocurred!');
}
});
And this is the view that is responding to the request:
class AddGoalStatus(generics.CreateAPIView):
serializer_class = GoalStatusSerializer
permission_classes = (
permissions.IsAuthenticated,
)
And the corresponding models:
class Goal(TimeStampedModel):
"""A personalized Goal that a user creates to achieve"""
completed = models.BooleanField(default=False)
user = models.ForeignKey(User)
competencies = models.ManyToManyField(CoreCompetency)
def __unicode__(self):
return self.user.get_full_name()
class GoalStatus(TimeStampedModel):
"""As goals go on, users will set different statuses towards them"""
content = models.TextField(max_length=2000)
goal = models.ForeignKey(Goal, related_name="goal_statuses")
def __unicode__(self):
return self.goal.user.get_full_name() + ": " + self.content
class Meta:
verbose_name_plural = "Statuses"
verbose_name = "Goal Status"
And here's the serializer for completeness:
class GoalSerializer(serializers.ModelSerializer):
competencies = serializers.PrimaryKeyRelatedField(many=True, read_only=False)
class Meta:
model = Goal
class GoalStatusSerializer(serializers.ModelSerializer):
goal = GoalSerializer()
class Meta:
model = GoalStatus
As Tom Christie says in here:
django rest framework create nested objects "Models" by POST
Django Rest Framework does not allow you to write to a nested serializer.
It looks like there is work being done on building out this functionality, but I don't know if it is done yet:
https://github.com/tomchristie/django-rest-framework/tree/writable-nested-modelserializer
In the meantime see this thread for ideas on how to work around this limitation:
https://groups.google.com/forum/#!topic/django-rest-framework/L-TknBDFzTk