Objects and attribute errors on browser, after server runs - django

I'm new to Django and I'm working on an app that display the objects of a primary key. The server runs fine but I get an error on the browser that says:
'master_courses' objects has no attribute 'masterCourses_slug'
The code looks like this:
from django.shortcuts import render, redirect
from .models import master_courses, course_category, course_series
def single_slug(requests, single_slug):
categories = [c.course_slug for c in course_category.objects.all()]
if single_slug in categories:
matching_series = course_series.objects.filter(course_category__course_slug=single_slug)
series_urls = {}
for ms in matching_series.all():
part_one = master_courses.objects.filter(course_series__course_series=ms.course_series).earliest("date_added")
series_urls[ms] = part_one return render(request, "main/category.html", {"the_series": series_urls})
masterCourses = [ m.masterCourses_slug for m in master_courses.objects.all()]
if single_slug in masterCourses:
return HttpResponse(f"{single_slug} is a single slug.")
The error points to the code below (which is on the last line of the code above:
masterCourses = [ m.masterCourses_slug for m in master_courses.objects.all()]
if single_slug in masterCourses:
return HttpResponse(f"{single_slug} is a single slug.")
The error isn't on the code section, but on the browser.
Any suggestions on how I could Sol this please.

Related

Django can't recognize 0,1,2 precisely in url

my_app/views.py
from django.http import HttpResponse,HttpResponseRedirect
articles = {
'index' : "Hello this is a view inside my_app",
'simple' : 'simple views',
'sports' : 'Sports Page',
'finance' : 'Finance Page',
'politics' : "Politics Page"
}
def news_view(request, topic) :
try :
return HttpResponse(articles[topic])
except:
raise Http404("404 GENERIC ERROR")
def num_page_view(request,num):
topics_list = list(articles.keys())
topic = topics_list[num]
return HttpResponseRedirect(topic)
my_app/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('<int:num>',views.num_page_view),
path('<str:topic>/',views.news_view),
]
when i type /my_app/0, django automatically change 0 0/, so i think Django can't recognize that this page's parameter is pure int. It continues until I type 0,1,2
But when i type more than 2 (ex. /my_app/3), it works as i intended
(1. enter /my_app/3 2. redirect to /my_app/finance/)
I don't know why Django do recognize the int parameter more than 2 but not 0,1,2.
Expected
enter /my_app/0
redirect to /my_app/index/
But...
enter my_app/0
url is automatically changed to my_app/0/
can't redirect to the page so i got an error

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', ...),
]

pylint(undefined-variable) on return render and object has no attribute errors

I'm working on a simple project with foreign keys on each model. The program worked well until I tried rendering the fetched data to a template.
When I tried getting a simple HttpResponse, it worked well, but rendering to a template gives me an error.
I get an error that states Undefined variable 'required' pylint(undefined-variable)
My code looks like this:
from django.shortcuts import render, redirect
from .models import master_courses, course_category, course_series
def single_slug(requests, single_slug):
categories = [c.course_slug for c in course_category.objects.all()]
if single_slug in categories:
matching_series = course_series.objects.filter(course_category__course_slug=single_slug)
series_urls = {}
for ms in matching_series.all():
part_one = master_courses.objects.filter(course_series__course_series=ms.course_series).earliest("date_added")
series_urls[ms] = part_one
return render(request, "main/category.html", {"the_series": series_urls})
The error points to the last line of the code, which is:
return render(request, "main/category.html", {"the_series": series_urls})
And it says undefined variable 'request' pylint(undefined-variable)
Other return statements work well except for that statement within the for loop as I've mentioned above.
Any suggestions on how I can solve this please?
I believe the problem is that your setting your first argument for single_slug as requests, as opposed to request, which is what your calling at the bottom after render.
from django.shortcuts import render, redirect
from .models import master_courses, course_category, course_series
def single_slug(request, single_slug):
categories = [c.course_slug for c in course_category.objects.all()]
if single_slug in categories:
matching_series = course_series.objects.filter(course_category__course_slug=single_slug)
series_urls = {}
for ms in matching_series.all():
part_one = master_courses.objects.filter(course_series__course_series=ms.course_series).earliest("date_added")
series_urls[ms] = part_one
return render(request, "main/category.html", {"the_series": series_urls})
Try it like above.

get() in Google Datastore doesn't work as intended

I'm building a basic blog from the Web Development course by Steve Hoffman on Udacity. This is my code -
import os
import webapp2
import jinja2
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape = True)
def datetimeformat(value, format='%H:%M / %d-%m-%Y'):
return value.strftime(format)
jinja_env.filters['datetimeformat'] = datetimeformat
def render_str(template, **params):
t = jinja_env.get_template(template)
return t.render(params)
class Entries(db.Model):
title = db.StringProperty(required = True)
body = db.TextProperty(required = True)
created = db.DateTimeProperty(auto_now_add = True)
class MainPage(webapp2.RequestHandler):
def get(self):
entries = db.GqlQuery('select * from Entries order by created desc limit 10')
self.response.write(render_str('mainpage.html', entries=entries))
class NewPost(webapp2.RequestHandler):
def get(self):
self.response.write(render_str('newpost.html', error=""))
def post(self):
title = self.request.get('title')
body = self.request.get('body')
if title and body:
e = Entries(title=title, body=body)
length = db.GqlQuery('select * from Entries order by created desc').count()
e.put()
self.redirect('/newpost/' + str(length+1))
else:
self.response.write(render_str('newpost.html', error="Please type in a title and some content"))
class Permalink(webapp2.RequestHandler):
def get(self, id):
e = db.GqlQuery('select * from Entries order by created desc').get()
self.response.write(render_str('permalink.html', id=id, entry = e))
app = webapp2.WSGIApplication([('/', MainPage),
('/newpost', NewPost),
('/newpost/(\d+)', Permalink)
], debug=True)
In the class Permalink, I'm using the get() method on the query than returns all records in the descending order of creation. So, it should return the most recently added record. But when I try to add a new record, permalink.html (it's just a page with shows the title, the body and the date of creation of the new entry) shows the SECOND most recently added. For example, I already had three records, so when I added a fourth record, instead of showing the details of the fourth record, permalink.html showed me the details of the third record. Am I doing something wrong?
I don't think my question is a duplicate of this - Read delay in App Engine Datastore after put(). That question is about read delay of put(), while I'm using get(). The accepted answer also states that get() doesn't cause any delay.
This is because of eventual consistency used by default for GQL queries.
You need to read:
https://cloud.google.com/appengine/docs/python/datastore/data-consistency
https://cloud.google.com/appengine/docs/python/datastore/structuring_for_strong_consistency
https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/
search & read on SO and other source about strong & eventual consistency in Google Cloud Datastore.
You can specify read_policy=STRONG_CONSISTENCY for your query but it has associated costs that you should be aware of and take into account.

crawlSpider seems not to follow rule

here's my code. Actually I followed the example in "Recursively Scraping Web Pages With Scrapy" and it seems I have included a mistake somewhere.
Can someone help me find it, please? It's driving me crazy, I only want all the results from all the result pages. Instead it gives me the results from page 1.
Here's my code:
import scrapy
from scrapy.selector import Selector
from scrapy.spiders import CrawlSpider, Rule
from scrapy.http.request import Request
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from githubScrape.items import GithubscrapeItem
class GithubSpider(CrawlSpider):
name = "github2"
allowed_domains = ["github.com"]
rules = (
Rule(SgmlLinkExtractor(allow=(), restrict_xpaths=('//*[contains(#class, "next_page")]')), callback='parse_items', follow=True),
)
def start_requests(self):
baseURL = 'https://github.com/search?utf8=%E2%9C%93&q=eagle+SYSTEM+extension%3Asch+size%3A'
for i in range(10000, 20000, +5000):
url = baseURL+str(i+1)+".."+str(i+5000)+'&type=Code&ref=searchresults'
print "URL:",url
yield Request(url, callback=self.parse_items)
def parse_items(self, response):
hxs = Selector(response)
resultParagraphs = hxs.xpath('//div[contains(#id,"code_search_results")]//p[contains(#class, "title")]')
items = []
for p in resultParagraphs:
hrefs = p.xpath('a/#href').extract()
projectURL = hrefs[0]
schemeURL = hrefs[1]
lastIndexedOn = p.xpath('.//span/time/#datetime').extract()
i = GithubscrapeItem()
i['counter'] = self.count
i['projectURL'] = projectURL
i['schemeURL'] = schemeURL
i['lastIndexedOn'] = lastIndexedOn
items.append(i)
return(items)
I didn't find your code on the link you passed, but I think the problem is that you are never using the rules.
Scrapy starts crawling by calling the start_requests method, but the rules are compiled and used on the parse method, which you are not using because your requests go directly from start_requests to parse_items.
You could remove the callback on the start_requests method if you want the rules to be applied on that level.