My view object 'has no attribute' {my attribute} in Django - django

Background
I'm trying to load a custom url (e.g. www.mysite.com/order-2523432) that will show a user details about their order.
Problem
I am trying to use the method order_id in my models.py in order to get the correct url. The problem is that I am getting the error:
'OrderDetailView' object has no attribute 'order_id'
Does anyone know what I can do to get order_id to work?
My views.py:
class OrderDetailView(DetailView):
model = Orders
template_name = "customer/orders.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
try:
context["orders"] = get_orders(self)
except RequestException as e:
logger.exception(e)
return context
My utils.py:
def get_orders(orders):
url = f"mysite.com/customer/{orders.order_id}"
method = "GET"
content_type = "application/json"
header = Sender(
credentials etc
).request_header
response = requests.request(
headers etc
)
response.raise_for_status()
return response.json()
My models.py:
class Orders(CustomModel):
table_name = models.CharField(max_length=256, unique=True)
#property
def order_id(self):
return f"order-{self.table_name}"
def get_absolute_url(self):
return reverse("order:edit", args=(self.id,))

you should use self.object or context['object'] or get_object() instead of passing self
please try this:
class OrderDetailView(DetailView):
model = Orders
template_name = "customer/orders.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
try:
context["orders"] = get_orders(context['object'])
except RequestException as e:
logger.exception(e)
return context

Related

TypeError: get_object() takes 1 positional argument but 2 were given [18/May/2021 18:27:12] "GET /api/Oxyegn/ HTTP/1.1" 500 94676

What i am trying to do is i am giving Choice Field and i am trying to
get all post when i pass that choice field to url as parameter for eg:
Oxygen, Plasma etc They are in my choice field which user has to
choose during posting post.
I want to get json format which we get whenever we do request to api
and i want that information based to choice filed i have given but
getting error.
Rest Api View
class PostRestApi(APIView):
def get_object(self, **kwargs):
try:
return Post.objects.get(help_type=kwargs.get('help_type'))
except Post.DoesNotExist:
raise Http404
def get(self, request, **kwargs):
posts = self.get_object(kwargs.get('help_type'))
serializer = PostSerializer(posts)
return Response(serializer.data)
> SERIALIZERS CLASS
class PostSerializer(serializers.Serializer):
title = serializers.CharField(max_length = 100)
content = serializers.CharField()
date = serializers.DateTimeField(default=timezone.now)
help_type = serializers.CharField()
My Post Model
CHOICES = (
("1", "Plasma"),
("2", "Oxygen"),
("3", "Bed"),
("4", "Emergency")
)
class Post(models.Model):
title = models.CharField(max_length = 100)
content = models.TextField()
date = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
help_type = models.CharField(max_length=300, choices = CHOICES, null=True)
url
path('api/<str:help_type>/', PostRestApi.as_view(), name='post-api')
Your method get_object takes only keyword arguments other than the positional argument self, hence instead of:
posts = self.get_object(kwargs.get('help_type'))
You should be writing:
posts = self.get_object(help_type=kwargs.get('help_type'))
Use def get_object(self, *args, **kwargs) so then if you use posts = self.get_object(kwargs.get('help_type')) you can access help_type=args[0] or if you use posts = self.get_object(help_type=kwargs.get('help_type')) you can access help_type=kwargs.get('help_type')
Its best if you declare an attribute as such def get_object(self, help_type, *args, **kwargs) and use it like return Post.objects.get(help_type=help_type)
class PostRestApi(APIView):
def get_object(self):
try:
return Post.objects.get(help_type=self.kwargs.get('help_type')) #Change1
except Post.DoesNotExist:
raise Http404
def get(self, request, **kwargs):
posts = self.get_object() #Change2
serializer = PostSerializer(posts)
return Response(serializer.data)
#Change1: def get_object(self, **kwargs): changed to def get_object(self): as get object takes self as the argument.
#Change2: posts = self.get_object(kwargs.get('help_type')) changed to posts = self.get_object(), as kwargs can be accessed from the self argument.

How to display parameter from URL to template in class based views in Django

View below prints list of all posts done by certain user. User was a parameter taken from the URL and is working fine.
How do I extract **kwarg -> 'username' and display it on the template as a variable?
Things commented out in the code have been tried.
views.py
class AuthorPostIndexView(ListView):
model = Person
template_name ='authorpostindex.html'
context_object_name = 'author_post'
#1)
#date=request.GET.get('username','') -> wrong as varibales in classes
#is not possible?
#-> this works fine:
def get_queryset(self):
username = self.kwargs['username']
queryset = Person.objects.get(username=username).post.all()
return queryset, (username,'')
#-> attempts to extract username kwarg:
#2)
# def get_context_data(self, **kwargs):
# context = super(AuthorPostIndexView, self).get_context_data(**kwargs)
# context['username'] = self.username
# return context
#3)
# #property
# def username(self):
# return self.kwargs['username']
expected result
template.html
<h1>{{username}}</h1> -> username from the URL should be displayed
Error messages:
1)'request' is not defined (shell)
2) 'AuthorPostIndexView' object has no attribute 'username' (template)
3) Reverse for 'post_detail' with arguments '('',)' not found. 1 pattern(s) tried: ['post\/(?P[0-9]+)$'] (template)
ps. Still not working after advices:
Solutions looks similar however I think I have problem with getting the kwarg argument out of the method. In addition I lost confidence on what to put in the template.
Can I return two arguments in the function like that?
class AuthorPostIndexView(ListView):
model = Post
template_name ='authorpostindex.html'
context_object_name = 'author_post'
def get_queryset(self):
queryset = super().get_queryset()
username = self.kwargs['username']
return (queryset.filter(authors__username=username),username)
Or in one of the suggested solution I have added method to the view
def get_context_data(self, **kwargs):
context = super(AuthorPostIndexView, self).get_context_data(**kwargs)
context['username'] = self.kwargs['username']
return context
...and then what about template
authorpostindex.html
{{context}}
or
{{username}}
or
{{context.username}}
That is not working
try this
def get_context_data(self, **kwargs):
context = super(AuthorPostIndexView, self).get_context_data(**kwargs)
context['username'] = self.kwargs['username']
# or
context['username'] = self.request.GET.get('username', None)
return context
hope it helps

How to use GET and queryset in classed based views?

i have two models with random farmers and animals (names / weight ) and i want to use the GET method, in my template, to apply a filter in my view on my models. For instance: show me all data with the name "xyz"
this was my approach:
models.py
class Farmer(models.Model):
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=40)
city = models.CharField(max_length=40)
<...>
class Animal(models.Model):
name = models.CharField(max_length=40)
weight = models.DecimalField(max_digits=5, decimal_places=2)
species = models.ForeignKey('Species', on_delete=models.CASCADE)
farmer = models.ForeignKey('Farmer', related_name='farmername', on_delete=models.CASCADE)
<...>
so this is my template. when i submit a value it will show up in my browser adress
template.html
<...>
<form action="" method="GET">
name: <input type="text" name="q"><br>
<input type="submit" value="Search">
</form>
<...>
this was my approach to fit in the GET method and Q into my view
views.py
from django.views.generic import TemplateView
from django.views.generic import View
from django.shortcuts import render
from django.db.models import Q
<...>
class HomeView(TemplateView):
template_name = 'farmapi/search.html'
http_method_names = ['get']
def get(self, request):
query = request.GET.get("q")
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
context['farmers'] = Farmer.objects.filter(Q(first_name__icontains=query)|Q(last_name__icontains=query))
context['animals'] = Animal.objects.filter(Q(name__icontains=query))
return context
This is the Error Message i get
ValueError at /data/search/
The view farmapi.views.HomeView didn't return an HttpResponse object.
It returned None instead.
so as far as i understand i should use a if statement?
class HomeView(TemplateView):
template_name = 'farmapi/search.html'
http_method_names = ['get']
def get(self, request):
query = request.GET.get("q")
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
if query is not None and query != '':
context['farmers'] = Farmer.objects.filter(Q(first_name__icontains=query)|Q(last_name__icontains=query))
context['animals'] = Animal.objects.filter(Q(name__icontains=query))
return context
if query is None and query != '':
context['farmers'] = Farmer.objects.all()
context['animals'] = Animal.objects.all()
return context
Unfortunately this does not work, i received the same error message. i would appreciate it, if someone has a hint or maybe knows some nice django tutorials with the topic "query, request via templates and filters" - i searched for hours, but most stuff was query and python shell related.
Update
Solution
So instead of using classed based view i use now a function and it worked.
def search(request):
query = request.GET.get("q")
if query is not None and query != '': # <----
farmers = Farmer.objects.filter(Q(first_name__icontains=query)|Q(last_name__icontains=query))
animals = Animal.objects.filter(Q(name__icontains=query))
context = {'animals': animals,
'farmers': farmers}
return render(request, 'farmapi/search.html', context)
else: # <----
farmers = Farmer.objects.order_by("-id")[0:2]
animals = Animal.objects.order_by("-id")[0:2]
context = {'animals': animals,
'farmers': farmers}
return render(request, 'farmapi/search.html', context)
however i wished there was a class based way.
I would try the following adjustment
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
if query is not None and query != '': # <----
context['farmers'] = Farmer.objects.filter(Q(first_name__icontains=query)|Q(last_name__icontains=query))
context['animals'] = Animal.objects.filter(Q(name__icontains=query))
return context
else: # <----
context['farmers'] = Farmer.objects.all()
context['animals'] = Animal.objects.all()
return context
Your conditions for the if and else statements are a bit confusing, so I suspect that for some inputs neither condition triggered and None was therefore returned.
So instead of using classed based view i use now a function and it worked.
def search(request):
query = request.GET.get("q")
if query is not None and query != '': # <----
farmers = Farmer.objects.filter(Q(first_name__icontains=query)|Q(last_name__icontains=query))
animals = Animal.objects.filter(Q(name__icontains=query))
context = {'animals': animals,
'farmers': farmers}
return render(request, 'farmapi/search.html', context)
else: # <----
farmers = Farmer.objects.order_by("-id")[0:2]
animals = Animal.objects.order_by("-id")[0:2]
context = {'animals': animals,
'farmers': farmers}
return render(request, 'farmapi/search.html', context)
however i wished there was a class based way.
p.s i posted this so i can later close this Thread or is there a way to close my own question if i answered it?

Django class based views: Posting form data returns 302 Found status code

I'm using django's generic class based view CreateView to upload images to a book. Here's the code:
# models.py
class Upload(models.Model):
image = models.ImageField(upload_to=get_upload_path, help_text='Image to process')
uploader = models.ForeignKey(settings.AUTH_USER_MODEL, models.CASCADE, related_name='uploader')
language = models.ForeignKey(Language, models.CASCADE)
book = models.ForeignKey(Book, models.CASCADE)
def __str__(self):
return str(os.path.split(self.image.name)[-1].split('_', 1)[-1])
#models.permalink
def get_absolute_url(self):
return ('book:upload_new', (self.book.id,)) # upload_new is linked to the view below
def save(self, *args, **kwargs):
super(Upload, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
self.image.delete(False)
super(Upload, self).delete(*args, **kwargs)
# views.py
#method_decorator(login_required, name='dispatch')
class PictureCreateView(CreateView):
model = Upload
fields = ("image",)
book_id = None
def dispatch(self, *args, **kwargs):
# book_id is passed as a URL parameter
self.book_id = self.kwargs['book_id']
return super().dispatch(*args, **kwargs)
def get_context_data(self, **kwargs):
context = super(PictureCreateView, self).get_context_data(**kwargs)
context['book_id'] = self.book_id
return context
def form_valid(self, form, **kwargs):
book = Book.objects.get(id=self.book_id)
form.instance.book = book
form.instance.language = book.language
form.instance.uploader = self.request.user
self.object = form.save()
# Running the command below prints
# <TemplateResponse status_code=200, "text/html; charset=utf-8">
# implying the upload was successful
#
# print(self.render_to_response(context=self.get_context_data()))
return super(PictureCreateView, self).form_valid(form)
def form_invalid(self, form):
print(form.errors)
data = json.dumps(form.errors)
return HttpResponse(content=data, status=400, content_type='application/json')
When I'm trying to upload an image, I get a 302 Found error for this request (as seen in the my browser's dev tools) implying the page has moved temporarily. Apart from the headers, I'm unable to see a preview or response for this request. The upload was successful though (I checked in the admin page).
Someone had this issue before and the answer pointed out an error in the URL conf. However, the issue wasn't fully resolved and the OP still got a 302 status code.
What could be the reason for this?
By default form_valid method redirects with 302 code to the success_url (which can be generated dynamically by overriding get_success_url) . So this is the normal behavior and I think a good practice. So I would not change it.
But if you really want to, you can return any other response code, for example : a 200 code with similar content than the get
# views.py
#method_decorator(login_required, name='dispatch')
class PictureCreateView(CreateView):
...
def form_valid(self, form, **kwargs):
book = Book.objects.get(id=self.book_id)
form.instance.book = book
form.instance.language = book.language
form.instance.uploader = self.request.user
self.object = form.save()
context = self.get_context_data()
# You may have check and modify your context for a correct page
# May be: add new things
context["success"] = True
return self.render_to_response(context))

Django: Set kwargs value for excluded field in generic view

Hi I am trying since yesterday.
models.py
class Event(models.Model):
def get_absolute_url(self):
return reverse('events:event-detail', kwargs={'pk': self.pk})
class Kategorie(models.Model):
event = models.ForeignKey(Event)
sport = models.ForeignKey(Sport)
....
urls.py
url(r'^kategorie/(?P<pk>[0-9]+)/create/$', views.KategorieCreate.as_view(), name='kategorie-create'),
html
Neue Kategorie
views.py
class KategorieCreate(generic.CreateView):
model = Kategorie
fields = ['sport',...] # 'event' is excluded
template_name_suffix = '_create_form'
def get_context_data(self, **kwargs):
context = super(KategorieCreate, self).get_context_data(**kwargs)
context['event'] = kwargs.get(self.pk)
return context
I received:
NOT NULL constraint failed: events_kategorie.event_id
There's no point setting that value in the context; you need to do so in the form instance. This is well documented:
def form_valid(self, form):
form.instance.event_id = self.kwargs['pk']
return super(KategorieCreate, self).form_valid(form)
Note, I can't actually understand what value you are trying to insert there. It makes no sense to use a category PK as the id of the event.