i am a beginner in Django. i have the below simple django model (refer to below). My list view has worked perfectly fine in the https://localhost/simpleapp/. However, when i try DetailView via https:local host/simpleapp/1, it gives me a 404 cant found. I don't know where is the problem as i already defined the urls wit the regular expression ^(?P\d+)/$.
Model.py
class University(models.Model):
university_name = models.CharField(max_length = 50)
def __str__(self):
return self.university_name
class Student(models.Model):
last_name = models.CharField(max_length = 50)
first_name = models.CharField(max_length = 50)
age = models.PositiveIntegerField()
university = models.ForeignKey(University, on_delete=True)
def __str__(self):
return '{} {}'.format(self.first_name, self.last_name)
Views.py
class StudentList(generic.ListView):
model = models.Student
context_object_name = 'student_list'
template_name = 'simpleapp/student_list.html'
class StudentDetail(generic.DetailView):
model = models.Student
context_object_name = 'student_detail'
template_name = 'simpleapp/student_detail.html'
urls.py in app folder
urlpatterns = [
url(r'^$', views.StudentList.as_view(), name='student_list'),
url(r'^(?P<pk>\d+)/$', views.StudentDetail.as_view(), name='student_detail'),
]
urls.py in project folder
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', views.Index.as_view(), name='index' ),
url(r'^simpleapp/$', include('simpleapp.urls', namespace='simpleapp')),
]
student_detail.html
{% extends 'simpleapp/student_base.html' %}
{% block content %}
<h1> {{student_detail}}</h1>
{% endfor %}
{% endblock %}
You have a $ at the end of the pattern that includes the simpleapp urls, which means nothing more will be matched. So the basic /simpleapp/ URL works, but anything after that won't. Remove that $; only use it on full patterns, not includes.
url(r'^simpleapp/$', include('simpleapp.urls', namespace='simpleapp')),
Here Django will match all urls which begin with simepleapp/ (because of the beginning ^) and ends with it as well (because of the ending $).
/simpleapp/1 is not matched by the url matcher.
instead, try changing the url to
url(r'^simpleapp/', include('simpleapp.urls', namespace='simpleapp')),
this way, Any url starting with simepleapp will be matched
Related
I am working on my first solo project with Django and I have hit a problem that no amount of searching and reading similar post on SO have solved.
I am trying to filter a gallery of images by their category, so that when the user clicks on a picture it will result in a page showing all the images with the same category. This will use HTMX hopefully in the final product, but I'm trying and failing to implement it using regular Django views initially.
As I said, this is my first solo project, so I'm very much a beginner, I know this isn't a debug service but just wanted some pointers on where I could be going wrong. Another set of eyes as you will.
I followed the docs on dynamic filtering CBV. I have overwritten get_queryset passing the Category slug into the kwargs and I have overwritten the get_context_dataso I can pass slug into the template.
I am getting a Reverse for 'select' with arguments '('',)' not found. 1 pattern(s) tried: ['select/(?P<slug>[-a-zA-Z0-9_]+)\\Z'] error, so I belive the problem is in my template/URLconf.
Models. Media with a FK to it's Category
class Category(models.Model):
title = models.CharField(max_length=200, null=True)
slug = AutoSlugField(populate_from='title')`
class Media(models.Model):
timestamp = models.DateTimeField()
image = models.ImageField(upload_to="media")
url = models.URLField()
order = models.IntegerField(default=0)
visable = models.BooleanField(default=True)
categories = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
Views, IndexView is entire gallery and SelectView is image by category
class IndexView(ListView):
template_name = "main/index.html"
model = Media
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context ['main_images'] = Media.objects.filter(visable=True)
return context
class SelectView(ListView):
template_name = "main/select.html"
model = Media
def get_queryset(self):
self.category = get_object_or_404(Category, title=self.kwargs['slug'])
return Media.objects.filter(categories__title=self.category)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['slug'] = self.category
return context
URLconf with select being the relevant pattern.
app_name = "main"
urlpatterns = [
path("", views.IndexView.as_view(), name="home"),
path("about", views.AboutView.as_view(), name="about"),
path("contact", views.ContactView.as_view(), name="contact"),
path("select/<slug:slug>", views.SelectView.as_view(), name="select"),
]
Gallery template I have a for loop to display the IndexView. I think the problem is with the Href (which I want to take my to SelectView). I am passing slug in the {% url %} but think it should be image.categories__slug? I have tried this but it still doesn't work. I am stumped.
{% for image in main_images %}
<div class="cbp-item web-design print">
<a href="{% url "main:select" slug %}" class="cbp-caption cbp-singlePageInline">
<div class="cbp-caption-defaultWrap"> <img src="{{ MEDIA_URL }} {{ image.image.url }}"alt=""> </div>
{% endfor %}
Many thanks.
I think what you want is to access the slug field on the image.categories field for each iteration.
{% for image in main_images %}
...
<a href="{% url 'main:select' image.cateogries.slug %}" class="cbp-caption cbp-singlePageInline">
...
{% endfor %}
In addition to that, I'd recommend that you do a lookup for the receiving slug instead of the title on the Category model. For example, if you should save I love this day as the title, the slug field would have I-love-this-day.
What you have:
def get_queryset(self):
self.category = get_object_or_404(Category, title=self.kwargs['slug'])
return Media.objects.filter(categories__title=self.category)
title=self.kwargs['slug'] won't find a title if your passing I-love-this-day as the slug. I'd suggest using slug=self.kwargs['slug']. See the below updates:
def get_queryset(self):
# Also, the self keyword is not needed here either -> self.category
category = get_object_or_404(Category, slug=self.kwargs['slug']) # updated
return Media.objects.filter(categories__title=category.title) # updated
Additionally, I see where you're passing slug as a value via the context variable within the SelectView... I suggest you pass the category object explicitly via the context variable to the template where you can access the fields from your template if necessary.
Within the get_context_data():
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# context['slug'] = self.category
context['category'] = get_object_or_404(Category, slug=self.kwargs['slug'])
return context
Hellow, I am noob and I make instagram followers scraper on Django.
I make a function that should add 1 (only 1 cos it works really slow) new follower in to db which takes from already working sсraping functions and place it into class.
class ListOfFollowers(ListView):
model = Followers
context_object_name = 'followers_of'
template_name = 'insta/followers.html'
def get_follower(self, username):
loader = instaloader.Instaloader()
loader.login('***', '***')
profile = instaloader.Profile.from_username(loader.context, username)
followers = profile.get_followers()
followers_tuple = tuple(followers)
i = random.randint(0, len(followers_tuple) - 1)
login = followers_tuple[i].username
photo = followers_tuple[i].get_profile_pic_url()
url = f'https://www.instagram.com/{login}/'
mutual_subscription = followers_tuple[i] in profile.get_followees()
res = {'login': login, 'photo': photo, 'url': url, 'mutual_subscription': mutual_subscription}
return res
def add_followers(self):
username = WhoFollow.objects.get(follow_on__contains=self.kwargs['follow_id']).title
context = None
while not context:
try:
context = get_follower(username)
except:
next
context.update({'follow_on': self.kwargs['follow_id']})
res = Followers(context)
res.save()
def get_queryset(self):
return Followers.objects.filter(follow_on=self.kwargs['follow_id'])
function calls add_followers (try block is just because its not always working from 1st try)
My models
class WhoFollow(models.Model):
title = models.CharField(max_length=255)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('follow', kwargs={'follow_id': self.pk})
class Followers(models.Model):
login = models.CharField(max_length=255)
photo = models.ImageField(upload_to="photos/", blank=True)
url = models.URLField()
mutual_subscription = models.BooleanField(default=False)
time_add = models.DateTimeField(auto_now_add=True)
time_unfollow = models.DateTimeField(blank=True)
follow_on = models.ForeignKey(WhoFollow, on_delete=models.PROTECT)
def __str__(self):
return self.login
And my template
{% extends 'insta/Base.html' %}
{% block content %}
<h1>Who we find</h1>
<ul>
{% for l in object_list %}
<li>
<h5>{{l.login}}</h5>
</li>
{% endfor %}
</ul>
<!-- from there i dont understand what i should do too -->
<form action="{% url views.ListOfFollowers.}">
<button type="submit" onclick="">add another 1</button>
</form>
{% endblock %}
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', Home.as_view(), name='home'),
path('add/', AddWhoFollow.as_view(), name='add'),
path('follow/<int:follow_id>', ListOfFollowers.as_view(), name='follow'),]
Sorry for too many code but my head already broken on this task.
There are some issues with your code:
First, you have added the two methods get_follower() and add_followers() to the your ListView, but it is unclear how (if at all) they are called. It looks to me like you might be misunderstanding the concept of the ListView. The purpose of the ListView is to render a list of objects, not add something. So instead you want to create a new view for adding followers. You can just define a simple function view for that, does not have to be a CBV.
Second, each view needs to have it's own URL defined. You did not post your urls.py, but I suppose {% url views.ListOfFollowers.} in the template will not work. Instead, you need to define a URL name in your urls.py (one for each view) and out that in your template.
I was totaly misunderstand the concept of the CBV.
The answer is that i should do it inside CreateVeiw after form validation where i choose which login to scrap.
There is result:
class AddFollowers(CreateView):
form_class = AddFollower
model = Followers
template_name = 'insta/add_follower.html'
def get_success_url(self):
return reverse_lazy('home')
def form_valid(self, form):
# Here is a body of scraping script where i creating a list of objects to add in db
Followers.objects.bulk_create(objs=res)
return HttpResponseRedirect(f'http://127.0.0.1:8000/)
i am trying to create a detailview in django.. when i am clicking in the listview items.. the url in browser is shoing id .. like http://localhost:8000/blog/2
but it is giving 404 page not found error.. please see..
views.py
def detail_view(request, id=None):
movie = get_object_or_404(BlogPost, id=id)
context = {'BlogPost':BlogPost,
}
return render(request, 'blog/blogdetail.html', context)
urls.py
path('list', BlogList.as_view(), name='list'),
path('(?P<id>\d+)',detail_view, name='detail')
list.html
<div class="post-body">
{% for p in post %}
<blockquote>{{p}}</br></br>{{p.Date}}</blockquote>
{% endfor %}
the blogdetail.html page is in the same directory in which bloglist.html page is..
models.py
class BlogPost(models.Model):
title = models.CharField(max_length=500)
writer = models.CharField(max_length=150,default='my dept')
category =models.CharField(max_length=150)
image = models.ImageField(upload_to='images')
post = models.TextField(max_length=2000)
Date = models.DateField( default=datetime.date.today)
Do this:
<blockquote>{{p}}</br></br>{{p.Date}}</blockquote>
Here, we are adding path according to the name so that, it is not relative to the current path. Refs
EDIT
As pointed out by Melvyn. Use path like: path as this:
path('list', BlogList.as_view(), name='list'),
path('(<int:id>)',detail_view, name='detail')
within an app I have two models, named Course and Step. Every Step belongs to a Course and each Course has many steps. However, I'm having problem creating a detailview for Steps. For example when i go to the url 'http://127.0.0.1:8000/courses/1' it should display steps for course.objects.get(pk=1). However what i get back is just the page for course, i.e, http://127.0.0.1:8000/courses'.
Model
from django.db import models
# Create your models here.
class Course(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length= 255)
description = models.TextField()
def __str__(self):
return self.title
class Step(models.Model):
title = models.CharField(max_length = 255)
description = models.TextField()
order = models.IntegerField()
course = models.ForeignKey(Course)
def __str__(self):
return self.title
Url
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.course_list),
url(r'(?P<pk>\d+)/$', views.course_detail)
]
View
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from .models import Course, Step
def course_list(request):
courses = Course.objects.all()
return render(request, 'courses/course_list.html', {'courses': courses})
def course_detail(request, pk):
course = Course.objects.get(pk=pk)
return render(request, 'courses/course_detail.html', {'course': course})
course_detail.html
{% extends 'layout.html' %}
{% block title %}{{course.title}}{% endblock %}
{% block content %}
<article>
<h2>{{ course.title }} %</h2>
{{course.description}}
<section>
{% for step in course.step_set.all %}
<h3>{{ step.title }}</h3>
{{step.description}}
{% endfor %}
</section>
</article>
{% endblock %}
Main Urls
from django.conf.urls import url, include
from django.contrib import admin
from courses.views import course_list
from django.conf import settings
from django.conf.urls.static import static
from . import views
urlpatterns = [
url(r'^courses/', course_list),
url(r'^admin/', admin.site.urls),
url(r'^$', views.hello_world),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
I just can't seem to recognize where i went wrong
I think the you need these url mappings..! This should do the trick.
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^applicationName/$', views.ListView.as_view(), name='courses'),
url(r'^applicationName/(?P<pk>\d+)$', views.CourseDetailView.as_view(), name='course-detail'),
]
The problem is in your main urls.py file - this line makes any URL path starting with 'courses/' resolve to the course_list view:
url(r'^courses/', course_list),
So Django will never reach the course_detail view. Instead, you must "include" the application-specific URLs:
url(r'^courses/', include('myproject.myapp.urls'),
Where myproject is your main project name, and myapp is your app name (make sure you also registered your application under INSTALLED_APPS at your settings.py file).
I'm working on a Django Project in which I have a model (Order) which holds various orders received from customers. I'm trying to update one of the Order fields (status) via id using UpdateView (CancelOrder). I've written the UpdateView and modified the urls.py, but when I try to update the status of an order via url I get the error: No order found matching the query, despite having several orders stored. My question is, why is the UpdateView not seeing my model data? Have I missed something?
Views.py
from django.shortcuts import render, redirect, HttpResponse
from django.core.exceptions import *
from django.views.generic.edit import UpdateView
from menu.models import Item, Order, Customer
from menu.forms import OrderForm, CustForm, UpdateForm
from .serializers import ItemSerializer
from rest_framework import generics
class CancelOrder(UpdateView):
model = Order
field = ('status',)
urls.py
from django.conf.urls import url, patterns, include
from . import views
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = patterns('',
url(r'^$', views.CreateOrder, name='CreateOrder'),
url(r'^vieworder/', views.ViewOrder, name='ViewOrder'),
url(r'^confirmation/', views.ConfirmOrder, name='ConfirmOrder'),
url(r'^api/$', views.ItemList.as_view()),
url(r'^api/(?P<pk>[0-9]+)/$', views.ItemDetail.as_view()),
url(r'^cancel/(?P<pk>[0-9]+)/$', views.CancelOrder.as_view(), name='CancelOrder'),
)
urlpatterns = format_suffix_patterns(urlpatterns)
Model
class Order(models.Model):
order_date = models.DateField(default=timezone.now)
delivery_date = models.DateField(default=timezone.now)
status = models.CharField(max_length=10, default='open')
ordered_by = models.CharField(max_length=50, null=True)
#user input
name = models.CharField(max_length=50)
email = models.EmailField()
phone = models.CharField(max_length=50)
shipping_info = models.CharField(max_length=50, null=True)
billing_info = models.CharField(max_length=50, null=True)
notes = models.CharField(max_length=150)
total = models.DecimalField(default=0, max_digits=5, decimal_places=2)
surcharge = models.DecimalField(default=0, max_digits=5,decimal_places=2)
def __str__(self):
return self.name
Looking at the comments and doing a bit more research I realized that I didn't fully understand what I was trying to do; most importantly I didn't have a template. I've fixed the issue as follows:
views.py
class CancelOrder(UpdateView):
model = Order
fields = ('status',)
template_name = 'menu/order_form.html'
def get_success_url(self):
return reverse('confirm')
template. I've fixed the issue as follows:
urls.py
urlpatterns = patterns('',
...
url(r'^updateorder/(?P<pk>[0-9]+)/$', views.CancelOrder.as_view(), name='cancel')
)
urlpatterns = format_suffix_patterns(urlpatterns)
template
{% extends "menu/header.html" %}
{% block content %}
<form method="POST" action="">{% csrf_token %}
<div id='helper'>{% include 'menu/includes/helper.html' %}<div>
<input id="submit" type="submit" value="Cancel Order">
</form>
<p>*Type "cancelled" to cancel your order</p>
{% endblock %}
helper
{% for field in form %}
<div>
<div><span>{{field.errors}}</div></span>
<label>{{field.label_tag}}</label>
<div>{{field}}</div>
<div>
{% endfor %}
This solves the issue, thanks to everyone in the comments.