How to perform a query by using URL with question mark in Django? - django

It seems like the original URL querying function has been removed from Django 3.1. Does anyone know how to do it with a new package?
The url.py:
urlpatterns = [
re_path(r'^portfolio/(?P<title>[\w-]+)/$' , BlogApp_View.displayPortfolio, name='displayPortfolio'),
path('portfolio/', BlogApp_View.selectPortfolio, name='selectPortfolio'),]
The view.py
def displayPortfolio(request):
title = request.GET.get('title')
portfolio = Article.objects.filter(articleType__name__contains = "Portfolio", title=title)
print(title)
DICT = {}
return render(request, 'Article/', DICT)
The problem is now if I visit http://127.0.0.1:8000/Blog/portfolio/?title=A_UAV_Positioning_Approach_Using_LoRa/, it will skip the re_path shows in url.py.
Instead, it goes to the path one.
I have tried str:title method but that is actually not what I want. I prefer using the question mark pattern to finish the query.

The part after the questionmark is the querystring [wiki] and is not part of the path. This thus means that regardless what patterns you write, you can not distinguish on this, since the path patterns, regardless whether it is a path or re_path, are never matched against a URL with a query string.
You thus should write a single view, and inspect the request.GET query dict (which is a dictionary-like representation of the query string and see if it contains a value for title.
Your urlpatterns thus look like:
urlpatterns = [
path('portfolio/', BlogApp_View.selectPortfolio, name='selectPortfolio'),
]
and in the view, you can see if it contains a title:
def selectPortfolio(request):
if 'title' in request.GET:
# contains a ?title=…
title = request.GET.get('title')
portfolio = Article.objects.filter(
articleType__name__contains='Portfolio',
title=title
)
data = {'portfolio': portfolio}
return render(request, 'some_template.html', data)
else:
# contains no ?title=…
# …
return …

Related

django - No User matches the given query. Page Not found 404: User post list view breaks post detail view

I'm fairly new to django and trying to build a message board app. Everything's been running smoothly up until I tried to add functionality to display a list of posts by author. I got it working but then my post detail view started throwing a 'No User matches the given query. Page Not found 404' error and I can't seem to figure out why. Can anyone help?
views.py
class UserPostList(generic.ListView):
model = Post
# queryset = Post.objects.filter(status=1).order_by('-created_on')
template_name = 'user_posts.html'
paginate_by = 6
def get_queryset(self):
"""
Method to return posts restricted to 'published' status AND to
authorship by the user whose username is the parameter in the
url.
"""
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(
status=1, author=user
).order_by('-created_on')
class FullPost(View):
def get(self, request, slug, *args, **kwargs):
"""
Method to get post object.
"""
queryset = Post.objects.filter(status=1)
post = get_object_or_404(queryset, slug=slug)
comments = post.comments.order_by('created_on')
liked = False
if post.likes.filter(id=self.request.user.id).exists():
liked = True
return render(
request,
"full_post.html",
{
"post": post,
"comments": comments,
"liked": liked
},
)
# I'll be adding a comment form in here too
urls.py
urlpatterns = [
...
path('<slug:slug>/', views.FullPost.as_view(), name='boards_post'),
...
path('<str:username>/', views.UserPostList.as_view(), name='user_posts'),
...
]
Error message
(When trying to view a single post (previously working) after adding the UserPostList view and route)
Using the URLconf defined in mhcmsgboard.urls, Django tried these URL patterns, in this order:
1. admin/
2. summernote/
3. register/ [name='register']
4. profile/ [name='profile']
5. login/ [name='login']
6. logout/ [name='logout']
7. new/ [name='create_post']
8. <slug:slug>/update/ [name='update_post']
9. <slug:slug>/delete/ [name='delete_post']
10. <str:username>/ [name='user_posts']
The current path, test-post/, matched the last one.
for <str:name> in path "-" not allowed to use in name,
when you use Slug both paths are equal.
urlpatterns = [
...
path('<slug:slug>/', views.FullPost.as_view(), name='boards_post'),
...
path('<slug:username>/', views.UserPostList.as_view(), name='user_posts'),
]
there are 2 simple ways
use sub path for one or both paths : user_post/<slug:username>/
Use re_path and define the regex to change path
exp:
re_path(r'^(?P\<username>\w+)/$', views.UserPostList.as_view()),
The problem is that you match update_post, delete_post and user_posts URL's to the root. As the error message explains, the current request is made against user_posts. And it seems that you don't have a user called test-post.
You could solve it e.g. with the following URL conf:
urlpatterns = [
...
path('board/<slug:slug>/', views.FullPost.as_view(), name='boards_post'),
...
path('posts/<str:username>/', views.UserPostList.as_view(), name='user_posts'),
...
]
That way, each path is unique and Django knows which View it has to call.

django restframwork Put and DELETE doesn't work

Get and post work pretty well for me .
but put and delete i use "U_repo_name" to look in table
i got the error message :
Page not found (404)
Request Method: PUT
Request URL: http://localhost:8000/gitapi/repo/authoo/
Using the URLconf defined in gitit.urls, Django tried these URL patterns, in this order:
admin/
gitapi/ [name='gitapi']
gitapi/ repo/
gitapi/ repo/str:U_repo_name
this is my model :
class UserRepos(models.Model):
U_repo_name =models.CharField( max_length=50)
this is my url :
urlpatterns = [
path('repo/',view=userreposapi),
path('repo/<str:U_repo_name>',view=userreposapi),
]
project urls :
urlpatterns = [
path('admin/', admin.site.urls),
path('gitapi/',include('gitapi.urls')),
]
this is my serializer :
class UserReposSerializer(serializers.ModelSerializer):
class Meta:
model = UserRepos
fields ='__all__'
and this is my views :
#csrf_exempt
def userreposapi(request,id=0):
if request.method=='GET':
userrepos = UserRepos.objects.all()
userreposserializer = UserReposSerializer(userrepos , many=True)
return JsonResponse(userreposserializer.data , safe=False)
elif request.method=='POST':
userrepos_data=JSONParser().parse(request)
userreposerializer = UserReposSerializer(data=userrepos_data)
if userreposerializer.is_valid():
userreposerializer.save()
return JsonResponse("added successfully!!",safe=False)
return JsonResponse("failed to add",safe=False)
elif request.method=='Put':
userrepos_data=JSONParser().parse(request)
userrepos = UserRepos.objects.get(U_repo_name=userrepos_data['U_repo_name'])
userreposserializer=UserReposSerializer(userrepos,data=userrepos_data)
if userreposserializer.is_valid():
userreposserializer.save()
return JsonResponse("updated successfully", safe=False)
return JsonResponse("failed to update",safe=False)
elif request.method=='DELETE':
userrepos = UserRepos.objects.all()
userrepos.delete()
return JsonResponse("deleted",safe=False)
Hi! I see a few issues with your code that might be causing this problem.
request.method is always full capitalized, so you should use the string 'PUT' instead of 'Put' on this line:
elif request.method=='Put':
You are adding a trailing slash to your route when trying to access it (/gitapi/repo/authoo/), but the pattern set in urlpatterns doesn't have this trailing slash:
path('repo/<str:U_repo_name>',view=userreposapi),
You can use re_path() instead of path() to set a regex URL pattern that works whether you add a trailing slash or not:
re_path(r'repo/(?P<U_repo_name>\w+)/?', view=userreposapi),
(?P<U_repo_name>\w+) creates a named group called U_repo_name that matches any word character ([a-zA-Z0-9_]) from one to more times. /? matches a single optional /.
Your route 'repo/<str:U_repo_name>' captures a string in the variable U_repo_name. This variable is provided to the view userreposapi() as a keyword argument, but the view currently only accepts the id kwarg. You should either add the U_repo_name kwarg as an optional argument or make the view accept other keyword arguments with **kwargs:
# Both are valid:
def userreposapi(request, id=0, U_repo_name=None):
...
def userreposapi(request, id=0, **kwargs):
...
Fixing these 3 issues should make the route work.
I think the trailing slash in the url is the problem. I should be not there.
http://localhost:8000/gitapi/repo/authoo # here I removed the trailing slash.

list index out of range error from previous view when rendering a different view

Apologies if I'm missing something daft here but I'm new to Django and I can't work this out.
I'm creating a basic reddit style app focusing on cryptocurrency. I have a view which gets price data from an API and displays it as well as any posts specific to that coin:
views.py:
def coin_posts(request, id):
if request.method == 'GET':
coin_display = {}
post = Post.objects.filter(coin_name=id)
api = 'https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=%s&order=market_cap_desc&per_page=100&page=1&sparkline=false' % id
response = requests.get(api)
data = response.json()
coin = data[0]
coin_data = Coins(
coin_id = coin['id'],
coin_name = coin['name'],
coin_price = coin['current_price'],
market_cap = coin['market_cap'],
rank = coin['market_cap_rank'],
price_change = coin['price_change_24h'],
slug = coin['symbol'],
image_url = coin['image']
)
coin_data.save()
coin_display = Coins.objects.filter(coin_id=id)
return render(request, 'coins.html', {
'post': post,
'coin_display': coin_display,
'post_form': PostForm()
},
)
I want to be able to click on each post to view any comments related to said post, as I haven't got that far yet I just wish to be able to view that single post on another page. So each post has the following link on the template:
Comments
and here are the corresponding URLs and view:
urlpatterns = [
path('', views.index, name="index"),
path('<str:id>/', views.coin_posts, name='coin_posts'),
path('<slug:slug>/', views.post_detail, name='coin_detail'),
]
def post_detail(request, slug):
post = Post.objects.filter(slug=slug)
return render(request, 'coin_detail.html', {
'post': post,
},
)
The problem is when I click on the link, I get the error: list index out of range
Which is referencing the coin = data[0] in the first view.
I can see that it's trying to populate the database, but because there's no GET data there's no list to index. My question is why is that happening? If I've clicked a link which calls the post_detail function, why is it executing the code in the coin_posts function?
I think the problem is in the url paths. The path of coin_posts "str:id/" is equal to the path of post_detail 'slug:slug/'. The only difference between these two urls is that str will accept only string while slug will match any slug string consisting of ASCII letters or numbers, plus the hyphen and underscore characters (reference).
Try defferenciating the path adding a different path for example:
urlpatterns = [
path('', views.index, name="index"),
path('coin_posts/<str:id>/', views.coin_posts, name='coin_posts'),
path('post_detail/<slug:slug>/', views.post_detail, name='coin_detail'),
]

Best practice for validating a date in url in django?

I have a logging system, where users can log several symptoms for any given day. Im getting the date as slug in my url, but I need to validate it. Which one is best practice, and why?
make a validator function in the class view and use it there
add a hidden form field, and write a custom DateValidator for it?
You can define a path converter that will parse date objects. You can define a custom pattern with:
# app_name/converters.py
class DateConverter:
regex = '[0-9]{4}-[0-9]{2}-[0-9]{2}'
format = '%Y-%m-%d'
def to_python(self, value):
return datetime.strptime(value, self.format).date()
def to_url(self, value):
return value.strftime(self.format)
Next we can register that path converter [Django-doc] and work with:
from app_name.converters import DateConverter
from django.urls import path, register_converter
register_converter(DateConverter, 'date')
urlpatterns = [
# …
path('some/path/<date:date>/', some_view),
# …
]
This will pass a single date parameter to the view, which is a date object, you thus can work with:
def some_view(request, date):
# …
If you thus visit the path /some/path/2021-10-17, date will be a date(2021, 10, 17) object.

Page view refers to id, whil path is not asking for one

I want to load a default django page. Nothing fancy. However, the error I get, hints at an id that is incorrectly set.
"Field 'id' expected a number but got 'zoekboek'."
The confusing things here (I am a django beginner, so I wouldn't be surprised if this is not confusing at all for you):
the path for this page in the urls.py is not asking for an id.
the view is not querying anything yet (I found some posts that had similar errors,
but related to a filter).
the debug info points to another view that indeed is requesting an id.
when I add a slash at the beginning of the path, the error is gone!
The code
urls.py
urlpatterns = [
path('', views.scholen, name='scholen'),
path('<school_id>', views.school_detail, name='school_detail'),
path('<school_id>/<groep_id>', views.school_groep, name='school_groep'),
path('<school_id>/<groep_id>/<UserProfile_id>', views.leerling_page, name='leerling_page'),
path('zoekboek', views.zoekboek, name='zoekboek'),
]
views.py
from django.shortcuts import render, redirect, reverse, get_object_or_404
from books.models import Book, Rating
from .models import School, Groep
from profiles.models import UserProfile, Hobby, Sport
from django.contrib.auth.models import User
# Create your views here.
def scholen(request):
"""
Homepage for participating
schools.
"""
scholen = School.objects.all()
context = {
'scholen': scholen,
}
return render(request, 'schools/school_landing.html', context)
def school_detail(request, school_id):
"""
Details of individual schools.
"""
school = get_object_or_404(School, pk=school_id)
groep = Groep.objects.filter(school=school)
context = {
'school': school,
'groep': groep,
}
return render(request, 'schools/school_detail.html', context)
def school_groep(request, school_id, groep_id):
"""
Details of groep.
"""
school = get_object_or_404(School, pk=school_id)
groep = get_object_or_404(Groep, pk=groep_id)
a = groep.naam
kinderen = UserProfile.objects.filter(groep=a)
context = {
'school': school,
'groep': groep,
'kinderen': kinderen,
}
return render(request, 'schools/school_groep.html', context)
def leerling_page(request, school_id, groep_id, UserProfile_id):
"""
Personal page of school kids.
"""
profile = get_object_or_404(UserProfile, pk=UserProfile_id)
# If viewer is owner of page, viewer can edit
owner = False
if request.user == profile.user:
owner = True
context = {
'profile': profile,
'owner': owner,
}
return render(request, 'schools/leerling_page.html', context)
def zoekboek(request):
"""
Page for kids to search their favorite book
"""
context = {
}
return render(request, 'schools/zoek_boek.html', context)
Is this enough information?
Simple fix: move path('zoekboek', views.zoekboek, name='zoekboek'), from the last place to the second place in your urls.
Why?
Because Django URLs are resolved using regular expressions; the docs say here in point 3:
Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL, matching against path_info.
Since your URL path path('<school_id>', views.school_detail, name='school_detail'), is very generic, it matches any string including the string zoekboek; so the request to zoekboek falls into the second line in your URL conf and gets routed to the view school_detail() and a school_id is expected for that view.
Suggestion: to make the URL handling easier and so you can order the URL paths however you like, you could change the URL a bit and add a prefix (for example school/) so that not any string matches the URL paths. For example, this schould work:
urlpatterns = [
path('', ...),
path('school/<school_id>', ...),
path('school/<school_id>/<groep_id>', ...),
path('school/<school_id>/<groep_id>/<UserProfile_id>', ...),
path('zoekboek', ...),
]