I am following the tutorial of Django REST Framework and when I try to curl http://127.0.0.1:8000/snippets, I get that error. I am new to Python/the Framework and Django, so I don't have a clue where to look at.
The code seems to be pretty fine, since I have double checked on github. Where do you think the error should be?
Snippet/serializers.py
from rest_framework import serializers
from snippets.models import Snippet
class SnippetSerializer(serializers.Serializer):
class Meta:
model = Snippet
fields = ('id', 'title','code','linenos','language','style')
class SnippetSerializer(serializers.Serializer):
pk = serializers.Field() # Note: `Field` is an untyped read-only field.
title = serializers.CharField(required=False,
max_length=100)
code = serializers.CharField(widget=widgets.Textarea,
max_length=100000)
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES,
default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES,
default='friendly')
def restore_object(self, attrs, instance=None):
"""
Create or update a new snippet instance, given a dictionary
of deserialized field values.
Note that if we don't define this method, then deserializing
data will simply return a dictionary of items.
"""
if instance:
# Update existing instance
instance.title = attrs.get('title', instance.title)
instance.code = attrs.get('code', instance.code)
instance.linenos = attrs.get('linenos', instance.linenos)
instance.language = attrs.get('language', instance.language)
instance.style = attrs.get('style', instance.style)
return instance
# Create new instance
return Snippet(**attrs)
snippet/urls.py
from django.conf.urls import patterns, url
urlpatterns = patterns('snippets.views',
url(r'^snippets/$', 'snippet_list'),
url(r'^snippets/(?P<pk>[0-9]+)/$', 'snippet_detail'),
)
snippet/views.py
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders its content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
#csrf_exempt
def 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)
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)
#csrf_exempt
def 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)
In your file urls.py, put quotes around snippets.urls.
Like this:
url(r'^',include('snippets.urls'))
Use serializers.ModelSerializer:
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title','code','linenos','language','style')
This lets DRF know to extract the fields and their types from the specified model class Snippet as parameters for the serializer. Your current version is using only serializers.Serializer. With the base Serializer class you need to define field variables for it to work. like this example:
class SnippetSerializer(serializers.Serializer):
pk = serializers.Field() # Note: `Field` is an untyped read-only field.
title = serializers.CharField(required=False,
max_length=100)
code = serializers.CharField(widget=widgets.Textarea,
max_length=100000)
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES,
default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES,
default='friendly')
Additionally, its probably a better practice for you to import your views from views.py like so:
from django.conf.urls import patterns, url
import views
urlpatterns = patterns('',
url(r'^snippets/$', views.snippet_list, name='snippet-list'),
url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail, name='snippet-detail'),
)
for me, what solved the problem is the file name.
make sure that the file serializers itself have no spelling issues and his name is the same as in the code.
Related
i've been learning Django for these past days and i'm trying to develop an url shortener. It's functional and works great but it misses something: Check if the URL already exists so it can return the short URL stored in db. At this moments it's just checks if the short url is unique and does not exist already, so it always create a new and unique short url for the same URL.
I've tried to use queryset's exists() in if ShortenerForm.objects.filter(url = cleaned_info['url']).exists(): but it always gave me an error object has no attribute 'cleaned_data'
How can i do that?
These are my files:
views.py
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from utils.shorty.form import ShortenerForm
from shorty.models import Shortener
# Create your views here.
def home(request):
template = "shorty/pages/index.html"
context = {}
context["form"] = ShortenerForm()
if request.method == "GET":
return render(request, template, context)
elif request.method == "POST":
used_form = ShortenerForm(request.POST)
if used_form.is_valid():
shortened_object = used_form.save()
new_url = request.build_absolute_uri("/") + shortened_object.shortcode
long_url = shortened_object.url
context["new_url"] = new_url
context["long_url"] = long_url
return render(request, template, context)
context["errors"] = used_form.errors
return render(request, "shorty/pages/index.html")
def redirect_url_view(request, shortened_path):
try:
shortener = Shortener.objects.get(shortcode=shortened_path)
shortener.redirectCount += 1
shortener.save()
return HttpResponseRedirect(shortener.url)
except:
raise Http404("Sorry this link does not exist")
form.py
from django import forms
from shorty.models import Shortener
class ShortenerForm(forms.ModelForm):
url = forms.URLField(
widget=forms.URLInput(
attrs={"class": "form-control", "placeholder": "Enter URL"}
)
)
class Meta:
model = Shortener
fields = ("url",)
models.py
from django.db import models
from utils.shorty.factory import create_short_url
# Create your models here.
class Shortener(models.Model):
startDate = models.DateTimeField(auto_now_add=True)
lastSeenDate = models.DateTimeField(auto_now=True)
redirectCount = models.PositiveIntegerField(default=0)
url = models.URLField()
shortcode = models.CharField(max_length=6, unique=True, blank=True)
class Meta:
ordering = ["-startDate"]
def __str__(self):
return f"{self.url} to {self.shortcode}"
def save(self, *args, **kwargs):
if not self.shortcode:
self.shortcode = create_short_url(self)
super().save(*args, **kwargs)
Thanks for your patience and time.
I am trying to create Rest API using DRF. Wanted to get detail by using UniqueId. I can use PK and get the output but wanna use unique id (token_id in my jobs Model) created in the model field.
Models.py
from django.db import models
from rest_api.util import unique_slug_generator
from django.urls import reverse
# Create your models here.
class Jobs(models.Model):
token_id = models.CharField(max_length=64, unique=True)
name = models.CharField(max_length=100)
url = models.URLField()
environment = models.CharField(max_length=100, null=True)
runtestnow = models.BooleanField(default=False)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('token_id', kwargs={'token_id':self.token_id})
class Queue(models.Model):
tokenid = models.ForeignKey(Jobs, on_delete=models.CASCADE)
date = models.DateField(auto_now=True)
def __str__(self):
return self.tokenid
class VM(models.Model):
vm_count = models.IntegerField(default=120)
def __str__(self):
return f"VM Count: {self.vm_count}"
Urls.py
from django.urls import path, include
from . import views
from .views import (RegisterTestMethodView,
RegisterTestMethodViewDetail,
CheckStatusView,
ReleaseTokenView
)
from rest_framework import routers
from rest_framework.authtoken.views import obtain_auth_token
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
router = routers.DefaultRouter()
router.register('jobs', views.JobsView)
urlpatterns = [
path('', include(router.urls)),
path('registertestmethod/', RegisterTestMethodView.as_view()),
path('registertestmethod/<int:pk>/',
RegisterTestMethodViewDetail.as_view()),
path('checkstatus/<int:pk>', CheckStatusView.as_view()),
path('checkstatus/<token_id>', CheckStatusView.as_view()),
path('releasetoken/<int:pk>', ReleaseTokenView.as_view()),
]
Serializers.py
from rest_framework import serializers
from .models import Jobs
from django.utils.crypto import get_random_string
class JobsSerializers(serializers.HyperlinkedModelSerializer):
token_id = serializers.CharField(default=get_random_string(length=25))
class Meta:
model = Jobs
fields = ('id', 'name', 'url','runtestnow','token_id')
class CheckStatusSerializers(serializers.HyperlinkedModelSerializer):
class Meta:
model = Jobs
fields = ('id','runtestnow')
class RegisterTestMethodSerializers(serializers.HyperlinkedModelSerializer):
class Meta:
model = Jobs
fields = ('id', 'name', 'url', 'environment', 'runtestnow', 'token_id')
Views.py
from rest_framework import viewsets, permissions, authentication
from .models import Jobs, VM, Queue
from .serializers import (JobsSerializers,
RegisterTestMethodSerializers,
CheckStatusSerializers)
import json
import datetime
import collections
collections.deque()
#3rd time
from rest_framework import generics
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.authentication import (SessionAuthentication,
BasicAuthentication,
TokenAuthentication)
from rest_framework.permissions import IsAuthenticated
from django.utils.crypto import get_random_string
with open('greet/static/greet/static/config.json', 'r') as
data_config:
data_ready = json.load(data_config)
totalVM = int(data_ready['totalVM'])
max_vm = int(data_ready['max_vm_count'])
grid_name = (data_ready['GridNameForDev'])
min_vm = int(data_ready['min_vm_count'])
class RegisterTestMethodView(APIView):
# authentication_classes = [SessionAuthentication,
TokenAuthentication, BasicAuthentication]
# permission_classes = [IsAuthenticated] # No access (not even
read if not authorized)
def get(self, request):
snippets = Jobs.objects.all()
serializer = RegisterTestMethodSerializers(snippets,
many=True)
return Response(serializer.data)
def post(self, request):
queue = VM.objects.all()
id_token = get_random_string(length=25)
if not queue:
queue = VM(vm_count=totalVM)
queue.save()
else:
for queue_obj in queue:
queue = queue_obj
if queue.vm_count > min_vm:
queue.vm_count -= max_vm
queue.save()
request.data["token_id"] = id_token
request.data["runtestnow"] = True
else:
request.data["token_id"] = id_token
request.data["runtestnow"] = False
serializer = RegisterTestMethodSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'TokenId': serializer.data['token_id'],
'RunTestNow': serializer.data['runtestnow'],
'VmCount': queue.vm_count,
'GridName': grid_name, 'Vm_left':
queue.vm_count}, status=status.HTTP_201_CREATED)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
class JobsView(viewsets.ModelViewSet):
queryset = Jobs.objects.all()
serializer_class = JobsSerializers
lookup_field = 'token_id'
class CheckStatusView(APIView):
"""
Retrieve, update or delete a snippet instance.
"""
def get_object(self, pk, token_id):
try:
return Jobs.objects.get(pk=pk)
except Jobs.DoesNotExist:
raise Http404
def get(self, request, token_id):
pk = request.GET.get('pk')
print(pk)
queue = VM.objects.get()
job_list = Jobs.objects.exclude(runtestnow=True)
filtered = Jobs.objects.filter(id=pk)
next_q = job_list.order_by('id').first()
waitlist = 1
return Response(
{"tokenid": token_id, "Runtestnow": False, "VMcount":
queue.vm_count,
'GridName': grid_name, 'waitlist #': waitlist,
'Vm_left':
queue.vm_count}, status=status.HTTP_201_CREATED)
def post(self, request, pk):
queue = VM.objects.get()
vm_count = queue.vm_count
job_list = Jobs.objects.exclude(runtestnow=True)
filtered = Jobs.objects.filter(id=pk)
next_q = job_list.order_by('id').first()
waitlist = int(pk-next_q.id + 1)
if next_q:
print(next_q.id)
if next_q.id == pk and queue.vm_count > min_vm:
queue.vm_count -= max_vm
filtered.update(runtestnow=True)
queue.save()
vm_used = max_vm
else:
filtered.update(runtestnow=False)
queue.save()
vm_used = 0
snippet = self.get_object(pk)
serializer = RegisterTestMethodSerializers(snippet)
return Response({"tokenid": serializer.data["id"],
"Runtestnow": serializer.data['runtestnow'], "VMcount":
vm_used,
'GridName': grid_name, 'waitlist #': waitlist ,
'Vm_left': queue.vm_count},
status=status.HTTP_201_CREATED)
class ReleaseTokenView(APIView):
"""
Retrieve, update or delete a snippet instance.
"""
def get_object(self, pk):
try:
return Jobs.objects.get(pk=pk)
except Jobs.DoesNotExist:
raise Http404
def delete(self, request, pk, format=None):
queue = VM.objects.get()
if not queue:
queue = VM(vm_count=totalVM)
if not self.get_object(pk):
print("Not Method Called...")
return
if queue.vm_count < totalVM :
queue.vm_count += max_vm
queue.save()
elif queue.vm_count + max_vm > totalVM:
queue.vm_count = totalVM
queue.save()
snippet = self.get_object(pk)
snippet.delete()
return Response(data={'Released': True},
status=status.HTTP_204_NO_CONTENT)
I can get information using but I wanna user token_id. I can do that using Serializers as it is in jobs.
If I do
localhost/jobs/xJcn8XxF2g9DmmwQwGS0Em754. # --> I get the output but I
# wanna use and I am aware
#that this will return all CRUD methods but how do I apply the
#business logic in Serializers.
localhost/checkstatus/xJcn8XxF2g9DmmwQwGS0Em754 . # --> I wanna
# apply business logic before getting the output. Which
# returns Response related to the PK as well.
What is the best way to do it?
Do I add it on serializer.py(how) or views.py?
I would appreciate it if you provide any helpful documents.
You should set lookup_field as token_id in your serializer and viewset.
Here is answer Django Rest Framework: Access item detail by slug instead of ID
Actually I was able to do it by some research. It seems like I have to pass a unique id (token_id) in URL and query using the same unique id (token_id) on the views.py. I was aware that there is modelviewset that does it effortlessly as mentioned by Ishak, but I wanted to use APIView and on top of that I wanted some business logic to be added. I probably have to do some more research on how to add logic to modelviewset. Here is my Solution.
Views.py
def get(self, request, token_id):
get_job = Jobs.objects.get(token_id=token_id)
pk = get_job.id
job_list = Jobs.objects.exclude(runtestnow=True)
next_q = job_list.order_by('id').first()
queue = VM.objects.get()
waitlist = int(pk) - int(next_q.id)
if waitlist == 1:
waitlist = 'You are next on the queue. :)'
return Response(
{"tokenid": token_id, "Runtestnow": False, "VMcount":
queue.vm_count,
'GridName': grid_name, 'waitlist #': waitlist, 'Vm_left':
queue.vm_count}, status=status.HTTP_201_CREATED)
Urls.py
path('checkstatus/<token_id>', CheckStatusView.as_view()),
We can always use the slug field, but I really wanted token_id as input. This should work fine for me as of now.
There might be some other way as well. Feel free to share.
I am creating a search application with Django.
I made an article model and a Feedback model that records the rating of articles.
After entering search box and displaying the search results, click one of the results then goes to the detail screen.
After selecting feedback on the detail screen and pressing the submit button, I want to save a search query to the feedback model.
I think that solution is to add a query in the URL like portal/search/?=query and read it, but I don't know how to code it. Also, could you teach me if there is an implementation method other than reading query in the URL?
Also, when I go back from the detail screen, I want to display the previous search results too.
Please comment if you have any questions.
Forgive for my poor English.
models.py
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
class KnowHow(models.Model):
BASIC_TAGS =(
('1','one'),
('2','two'),
('3','three'),
('4','four'),
('5','five'),
('6','six'),
)
CATEGORY =(
('1','Type2'),
('2','Type1'),
)
author = models.ForeignKey('auth.User',on_delete=models.CASCADE)
category = models.CharField(max_length=1,choices=CATEGORY,default='1')
title = models.CharField(max_length=200)
text = models.TextField(blank=True,default=' ')
# delault=' ':import system will give a error if text column is null
file = models.FileField(blank=True,upload_to='explicit_knowhows')
basic_tag = models.CharField(max_length=1,choices=BASIC_TAGS,default='1')
free_tags = TaggableManager(blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('portal:index')
class Feedback(models.Model):
EFFECT =(
('1','great'),
('2','maybe good'),
('3','bad'),
)
NOVEL =(
('1','I didn't know that'),
('2','I know, but I forgot'),
('3','I know this.'),
)
kh = models.ForeignKey(KnowHow, on_delete=models.PROTECT)
user = models.ForeignKey('auth.User',on_delete=models.CASCADE)
query = models.TextField(blank=True)
time = models.DateTimeField(auto_now_add=True)
efficacy = models.CharField(max_length=1,choices=EFFECT,default='1')
novelty = models.CharField(max_length=1,choices=NOVEL,default='1')
def __str__(self):
return self.time.strftime("%Y/%m/%d %H:%M:%S")
views.py
from django.urls import reverse, reverse_lazy
from django.http import HttpResponse
from django.views import generic
from django.views.generic.edit import ModelFormMixin
from django.shortcuts import redirect,get_object_or_404
from django.core.exceptions import PermissionDenied
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from .models import KnowHow
from taggit.models import Tag
from .forms import SearchForm,FeedbackForm
from django.db.models import Q
"""
Django Auth
The LoginRequired mixin
https://docs.djangoproject.com/en/2.0/topics/auth/default/#the-loginrequired-mixin
The login_required decorator
https://docs.djangoproject.com/en/2.0/topics/auth/default/#the-login-required-decorator
#login_required
"""
class IndexView(LoginRequiredMixin,generic.list.ListView):
model = KnowHow
#paginate_by = 5
ordering = ['-title']
# template_name = 'portal/KnowHow_list.html'
class DetailView(ModelFormMixin,LoginRequiredMixin,generic.detail.DetailView):
# from https://torina.top/detail/337/
model = KnowHow
form_class = FeedbackForm
template_name = 'portal/KnowHow_detail.html'
def form_valid(self, form):
kh_pk = self.kwargs['pk']
Feedback = form.save(commit=False)
Feedback.kh = get_object_or_404(KnowHow, pk=kh_pk)
Feedback.query=""
Feedback.user=self.request.user
Feedback.save()
return redirect('portal:search')
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
self.object = self.get_object()
return self.form_invalid(form)
class CreateView(LoginRequiredMixin, generic.edit.CreateView): # The LoginRequired mixin
model = KnowHow
fields = ['category','title','text','file','basic_tag','free_tags']
#template_name = 'portal/KnowHow_form.html'
def form_valid(self, form):
# This method is called when valid form data has been posted.
# It should return an HttpResponse.
# https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user
form.instance.author = self.request.user
return super(CreateView, self).form_valid(form)
class UpdateView(LoginRequiredMixin, generic.edit.UpdateView): # The LoginRequired mixin
model = KnowHow
fields = ['category','title','text','file','basic_tag','free_tags']
#template_name = 'portal/KnowHow_form.html'
class DeleteView(LoginRequiredMixin, generic.edit.DeleteView): # The LoginRequired mixin
model = KnowHow
success_url = reverse_lazy('portal:index')
def delete(self, request, *args, **kwargs):
result = super().delete(request, *args, **kwargs)
Tag.objects.filter(knowhow=None).delete()
return result
#template_name = 'portal/KnowHow_confirm_delete.html'
class SearchIndexView(LoginRequiredMixin, generic.ListView):
template_name="search/search_index.html"
model = KnowHow
def post(self, request, *args, **kwargs):
form_value = [
self.request.POST.get('basic_tag', None),
self.request.POST.get('free_tags', None),
]
request.session['form_value'] = form_value
self.request.GET = self.request.GET.copy()
self.request.GET.clear()
return self.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
basic_tag = ''
free_tags = ''
if 'form_value' in self.request.session:
form_value = self.request.session['form_value']
basic_tag = form_value[0]
free_tags = form_value[1]
default_data = {'basic_tag': basic_tag,
'free_tags': free_tags,
}
test_form = SearchForm(initial=default_data)
context['test_form'] = test_form
return context
def get_queryset(self):
if 'form_value' in self.request.session:
form_value = self.request.session['form_value']
basic_tag = form_value[0]
free_tags = form_value[1]
condition_basic_tag = Q()
condition_free_tags = Q()
if len(basic_tag) != 0 and basic_tag[0]:
condition_basic_tag = Q(basic_tag=basic_tag)
if len(free_tags) != 0 and free_tags[0]:
condition_free_tags = Q(free_tags__name__in=free_tags)
return KnowHow.objects.filter(condition_basic_tag & condition_free_tags).distinct()
else:
return KnowHow.objects.none()
#login_required
def help(request):
return HttpResponse("Member Only Help Page")
urls.py
from django.urls import path
from . import views
# set the application namespace
# https://docs.djangoproject.com/en/2.0/intro/tutorial03/
app_name = 'portal'
urlpatterns = [
# ex: /
path('', views.IndexView.as_view(), name='index'),
# ex: /KnowHow/create/
path('KnowHow/create/', views.CreateView.as_view(), name='create'),
# ex: /KnowHow/1/
path('KnowHow/<int:pk>/detail/', views.DetailView.as_view(), name='detail'),
# ex: /KnowHow/1/update/
path('KnowHow/<int:pk>/update/', views.UpdateView.as_view(), name='update'),
# ex: /KnowHow/1/delete
path('KnowHow/<int:pk>/delete/', views.DeleteView.as_view(), name='delete'),
# ex: /KnowHow/help/
path('KnowHow/help/', views.help, name='help'),
path('search/',views.SearchIndexView.as_view(), name='search')
]
There are several solutions for your problem.
First one is the exact solution you mentioned yourself. using a query string parameter like ?q= for KnowHow details view.
Using a SearchLog model and using that model's identifier. When someone hits the /search/ endpoint, you create a new SearchLog and pass the pk for this record to your front. Basically it would be just like ?q= option. instead you can use ?search_id= to bind the feedback to an specific SearchLog
Use user sessions. Bind the searched query to user's session and when they want to create a new Feedback use the query in their session.
For the first two options, you just need to create your urls for the detail links properly (in your search result page). In your template, do something like below:
# You are probably doing something like this
{% for r in results %}
{{r.name}}
{% endfor %}
# You should do this instead
{% for r in results %}
{{r.name}}
{% endfor %}
You can either pass the current_query in your context when rendering the template, or use javascript to get that value from browser's location / query string.
I changed get_context_data function in SearchIndexView to this:
in the last line before return add these two lines
context['basic_tag'] = basic_tag
context['free_tags'] = free_tags
And I changed html too.
{{ KnowHow.title }}
Thanks, #n1ma
Ok so I am trying to include the corrosponding Comment in my createAnswer View currently the url of the createAnswer page includes the pk ok the right comment so i need to get the comment by the id in the url.
My generic CreateView looks like this:
class createAnswer(CreateView):
model = Answer
fields = ['content']
def getComment(self, request):
???
comment = getComment()
def get_success_url(self):
this_path = self.request.get_full_path()
path_list = this_path.split('/')
def get_comment_id(self):
for i in range(len(path_list)):
if path_list[i].isdigit():
return path_list[i]
return '/blogcontact/comment/'+ get_comment_id(self)
def form_valid(self,form):
this_path = self.request.get_full_path()
path_list = this_path.split('/')
def get_comment_id(self):
for i in range(len(path_list)):
if path_list[i].isdigit():
return path_list[i]
form.instance.author = self.request.user
form.instance.comment = Comment.objects.get(id=get_comment_id(self))
return super().form_valid(form)
My Urls.py looks like this:
from django.urls import path
from . import views
from .views import createAnswer
urlpatterns = [
path('contact/comment/<int:pk>/newanswer', createAnswer.as_view(),
name='answer-create')
]<br>
I would like to save the Comment object in a variable so i Can use it in the html template like this {{comment}}
I think you you are confusing the function views and the Class Based Views (CBV), and you never import a request, it is just a parameter your views receive.
In a function view you do the following:
def my_view(request):
if request.method == 'POST':
# do some stuff
For CBV each method is a function:
from django.views.generic.edit import CreateView
class MyView(CreateView):
model = Answer
fields = ['content']
def get(self, request):
# do some stuff
def post(self, request):
# do some stuff
EDIT: To access the url parameters in class based views use self.kwargs, so you would access the comment pk by doing self.kwargs['pk']. Now you just need to get the comment and add it to the context data:
class CreateAnswer(CreateView):
model = Answer
fields = ['content']
def get_context_data(self, **kwargs):
kwargs['comment'] = Comment.objects.get(pk=self.kwargs['pk'])
return super().get_context_data(**kwargs)
def form_valid(self, form):
# do some stuff
I'm trying to learn DJango Rest so I made a litte test to see if I could obtain some things from the database, but I'm getting some problems.
Here's my models.py:
from django.db import models
# Create your models here.
class Stock(models.Model):
ticker = models.CharField(max_length=10)
open = models.FloatField()
close = models.FloatField()
volume = models.IntegerField()
def __str__(self):
return self.ticker
Here's my serializers.py:
from rest_framework import serializers
from .models import Stock
class StockSerializer(serializers.ModelSerializer):
ticker = serializers.CharField()
open = serializers.FloatField()
close = serializers.FloatField()
volume = serializers.IntegerField()
def create(self, validated_data):
return Stock.objects.check(**validated_data)
def update(self, instance, validated_data):
instance.ticker = validated_data.get('ticker', instance.ticket)
instance.open = validated_data.get('open', instance.open)
instance.close = validated_data.get('close', instance.close)
instance.volume = validated_data.get('volume', instance.volume)
instance.save()
return instance
class Meta:
model = Stock
fields = '__all__'
Here's my views.py:
from django.http import Http404
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Stock
from .serializers import StockSerializer
# List all stocks or create a new one
# stocks/
#api_view(['GET', 'POST'])
def stock_list(request, format=None):
if request.method == 'GET':
stocks = Stock.objects.all()
serializer = StockSerializer(stocks, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = StockSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#api_view(['GET', 'POST', 'DELETE'])
def stock_detail(request, pk, format=None):
try:
stock = Stock.objects.get(pk=pk)
except Stock.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = StockSerializer(stock)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = StockSerializer(stock, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
stock.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
And finally, here's my url.py:
from django.conf.urls import url
from django.contrib import admin
from rest_framework.urlpatterns import format_suffix_patterns
from companies import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^stocks/', views.stock_list),
url(r'^stocks/(?P<pk>[0-9]+)$', views.stock_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns)
I've been following this tutorial, but when it comes to the moment of making some requests (for this example I use this one: http http://127.0.0.1:8000/stocks/
I get this error message:
TypeError at /stocks/ stock_list() missing 1 required positional
argument: 'request'
I think that the problem is with the urls, but I'm not sure how to fix it.
Any ideas and some examples?
UPDATE: The problem was with the methods in view (they had an attibute self)
The general Get method works, but when I try to use POST
POST ERROR:
When I try this request: http --form POST http://127.0.0.1:8000/stocks/ ticker='SAM'
I get this error:
AttributeError at /stocks/ Got AttributeError when attempting to get a
value for field ticker on serializer StockSerializer. The
serializer field might be named incorrectly and not match any
attribute or key on the list instance. Original exception text was:
'list' object has no attribute 'ticker'.
You need to remove self.
Remember you are using functions not clases.
#api_view(['GET', 'POST'])
def stock_list(request, format=None):
if request.method == 'GET':
stocks = Stock.objects.all()
serializer = StockSerializer(stocks, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = StockSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Try views.stock_list.as_view() in urls.py