So I'm still a newbie in Django and I would like to have your advices regarding this point :
I have a User system in my application which extend from userena:
class FindUrGeekUserProfile(UserenaBaseProfile):
user = models.OneToOneField( User, unique = True, verbose_name ='userData', related_name='myProfile',db_index = True)
type = models.CharField(max_length = 2, choices = USER_TYPE, blank = True, null = True, db_index = True)
def __unicode__(self):
return 'Name: ' + self.user.username + ' Type: ' + self.type
When a User registers in my website he completes login, password and email fields.
The first time a user will connect though my website, he will see a page asking him what's his usertype : Type1 or Type2...
I want to verify in each login_registered view that the user has defined his type. Until now, i created a function I use in every registered view:
def checkUserType(user):
if(user.type != None)
return True
else:
retur False
#login_registered
def myView(request):
if (checkUserType(request.user)):
Continue....
else:
return redirect('setUserType') # Page where the user will set his type
Is there a better way to that in Django? Using some built in function ?
Thanky ou for your help
There's at least a better way:
#login_registered
def myView(request):
if not checkUserType(request.user):
return redirect('setUserType') # Page where the user will set his type
# user has the type, continue
Also, you could write a custom middleware, and do the check/redirect in process_request(). It could look like:
from django import http
from django.core.urlresolvers import reverse
class SetUserTypeMiddleware(object):
urls = ['/some/path/that/requires/user/type/',]
def process_request(self, request):
if not request.user.is_authenticated():
return
for url in urls: # customize url matching to your taste
if url in request.path_info:
return http.HttpResponseRedirect(reverse('setUserType'))
Middleware is a cool feature, it's simple and powerful. Just don't forget to register them in settings.MIDDLEWARE_CLASSES.
Related
I am trying to build a functionality where users have to enter the passcode to access the site.
If you go to this site it will ask for a password (123) before showing you the content:
https://www.protectedtext.com/djangoproj
I want to do it without forms.py.
URL OF THE PAGE --> TEMPLATE --> ASK FOR PASSCODE --> SHOW CONTENT IF PASSCODE MATCHES
models.py
from django.db import models
# Create your models here.
class Text(models.Model):
text = models.TextField(blank=True)
slug = models.SlugField(unique=True)
password = models.CharField(max_length=50)
def __str__(self):
return self.slug
views.py
from django.shortcuts import render
from .models import Text
import django.contrib.auth
# Create your views here.
def textview(request, slug):
obj= Text.objects.get(slug=slug)
return render(request, 'text/textpage.html', {'obj' : obj})
def home(request):
return render(request, 'text/index.html', {})
I have tried creating a new template for password but I am still not getting that functionality.
Thanks in advance
If I were you (and didn't want to use DRF), I would make something like this:
def check_password(*args, **kwargs): # decorator function for checking password
def wrapper(func):
if kwargs.get('password', None) == '123':
func() # show index, if password is corrent
else:
raise Exception('Access denied') # else raise the exception
return wrapper
def home(request):
try:
password = request.GET.get('password') # get password from given parameters
#check_password(password)
def show_index(): # create function, maybe better to make it out of scope
return render(request, 'text/index.html', {})
show_index() # call function
except:
print('Password was not given or it is incorrect, access denied')
return render(request, 'text/401.html', {})
I am practicing Django by creating a web application where I can email in a word, the application then translates it (from eng - spanish or vice versa) and sends me a few words each day to learn.
My problem:
I don't know where to put the webscraper code that translates search terms and I don't know how to trigger it when a search term is received so that the result can be added to the Results model
Models
I have two models currently. The first model contains my search terms and the second model contains the translation results - both inherit from an abstract model with common fields:
from django.db import models
from django.conf import settings
class CommonInfo(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Search(CommonInfo):
search_term = models.CharField(max_length=100)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True
)
def __str__(self):
return self.search_term
class Result(CommonInfo):
search = models.ForeignKey(
Search,
on_delete=models.SET_NULL,
null=True
)
translation = models.CharField(max_length=100)
example = models.TextField()
is_english = models.BooleanField(default=True)
def __str__(self):
return self.translation
My View
My view has a single entry point which receives an http POST request containing a parsed email from a Sendgrid parser. It extracts the word to be translated (from the subject line), then adds this to the searches model, linking it to the relevant user:
from vocab.models import Search
from django.views import View
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
import re
from users.models import CustomUser
#method_decorator(csrf_exempt, name='dispatch')
class Parser(View):
def post(self, request, *args, **kwargs):
#pull out the from field
sender = request.POST.get('from')
#regex the actual email, turn into a string and assign to result_email
result_email = re.search("(?<=<).*?(?=>)", sender).group(0)
#lookup to see if it exists in the DB and throw an error if not
if CustomUser.objects.filter(email=result_email).exists() == False:
return HttpResponse("You do not have an account, please sign up first", status=401)
#PARSING
# parse subject
subject = str(request.POST.get('subject'))
# find user ID from DB
user = CustomUser.objects.get(email=result_email)
Search.objects.create(search_term=subject, user=user)
return HttpResponse("OK")
The webscraper
I have created the outline of a web scraper that should take the searched word, create a url from it (to the SpanishDict website), it then uses BeautifulSoup to pull down a translation and example sentences:
from requests import get
from requests.exceptions import RequestException
from contextlib import closing
from bs4 import BeautifulSoup
#creates a url from the word
def url_creator(word):
return 'https://www.spanishdict.com/translate/' + str(word).lower()
# get request using the url
def simple_get(url):
try:
with closing(get(url, stream=True)) as resp:
if is_good_response(resp):
return resp.content
else:
return None
except RequestException as error:
log_error('Error during request to %s : %s ' % (url, error))
return None
# checks the get request response is HTML
def is_good_response(resp):
content_type = resp.headers['Content-Type'].lower()
return (resp.status_code == 200
and content_type is not None
and content_type.find('html') > -1)
# logs an error if there are any issues
def log_error(error):
print(error)
# creates a beautiful soup object from the raw html
def bs_html_maker(raw_html):
return BeautifulSoup(raw_html, 'html.parser')
# finds the translation and example for the word being searched
def first_definition_finder(bs_html):
return bs_html.find(class_="dictionary-neodict-indent-1")
# works out the language being searched (inferring it from the results of the get request)
def language_finder(bs_html):
if bs_html.find(id="headword-and-quickdefs-es"):
return False
elif bs_html.find(id="headword-and-quickdefs-en"):
return True
else:
raise Exception("The word you searched didn't return anything, check your spelling")
# returns the translation, the example sentences and what language the search was in in a dictionary
def result_outputter(bs_html):
translation_dictionary = {}
is_english = language_finder(bs_html)
definition_block = first_definition_finder(bs_html)
definition = definition_block.find(class_="dictionary-neodict-translation-translation").string
examples = examples = definition_block.find(class_="dictionary-neodict-example").strings
example_string = "%s - %s" % (next(examples), next(examples))
translation_dictionary["definition"] = definition
translation_dictionary["example"] = example_string
translation_dictionary["is_english"] = is_english
return translation_dictionary
# pulls it all together in one method which will ideally be called whenever a search is saved to the database and the results can then be used to add the translation to the database
def vocab_translator(word):
url = url_creator(word)
raw_html = simple_get(url)
bs_html = bs_html_maker(raw_html)
return result_outputter(bs_html)
My problem:
I don't know where to put the webscraper code that translates search terms and I don't know how to trigger it when a search term is received so that the result can be added to the Results model
Any help would be greatly appreciated. Any comments on my code would also be useful as I am currently learning Django and need any feedback you can give.
in my app folder I have views.py and bot.py.
The bot.py is main brain of my project, there are all my functions that 'do' main stuff(backend). I import them and use in Django. Now somehow I need to send data from django to bot.py. How to do that? I have:
views.py:
bot = Instagram()
class InstabotFormView(AjaxFormMixin, FormView):
form_class = LoginInstagramForm
template_name = 'instabot.html'
success_url = 'runinstabot.html'
def form_invalid(self, form):
response = super(InstabotFormView, self).form_invalid(form)
if self.request.is_ajax():
return JsonResponse(form.errors, status=400)
else:
return response
def form_valid(self, form):
response = super(InstabotFormView, self).form_valid(form)
login = form.cleaned_data.get('login')
password = form.cleaned_data.get('password')
tagi = form.cleaned_data.get('tags')
tags = []
tagi = tagi.split(',')
tags.extend(tagi)
print(tags)
if self.request.is_ajax():
print('It is AJAX')
bot.login(login,password)
bot.search(tags)
print(form.cleaned_data)
data = {
'message': "Succesfully opened Selenium."
}
return JsonResponse(data)
else:
return response
bot.py:
class Instagram(object):
...
def search(self,tags):
time.sleep(1)
search = self.driver.find_element_by_xpath('/html/body/span/section/nav/div[2]/div/div/div[2]/input')
search.clear()
search.send_keys(tags[self.nextTag], Keys.ENTER)
time.sleep(2)
self.driver.find_element_by_xpath(
'/html/body/span/section/nav/div[2]/div/div/div[2]/div[2]/div[2]/div/a[1]/div').click()
def changeTag(self):
#if a list gets to the end reset it
self.nextTag += 1
tagsNum = len(Instagram.tags)
if self.nextTag == tagsNum:
self.nextTag = 0
else:
self.tags[0 + self.nextTag]
return self.nextTag
After I run my script it writes:
AttributeError: 'Instagram' object has no attribute 'tags'
I know that Instagram.tags does not exist but how to use data from Django inside my bot.py? How to put instead of Instagram.tags , tags=[] from my Django class? Or is there a better solution?(maybe writing changeTag() in Django and returning data to bot.py?)
I have tried importing Django class inside bot.py but does not work
This has nothing to do with Django. You’re just dealing with Python classes. Classes define properties and methods for their instances. So if you initialize an instance of Instagram inside another object (a InstabotFormView) you can just assign values/objects to its properties.
Now if you add the tags = [] property to Instagram (initializing it with empty lost) then inside Django class you can set bot.tags to the tags and use that inside the Intagram methods.
I have a function that is run every view to correct slugs.
For example if the slug is /12-post-about-stuff and a user enters /12-post-abot_stof they will be redirected correctly. The problem is that the different views have different url patterns for example:
/posts/post_slug/
...
/posts/post_slug/comments/new
how to I write a function that redirects by fixing the slug name based on the current url?
Edit: I am applying a decorator to every view with a board_name and pk argument. What I don't know is how to dynamically return the new url because the url format is different for each view.
def correct_board_url_name(func):
def wrapper(request, board_slug):
try:
pk = int(board_slug.split('-')[0])
board = Board.objects.get(pk=pk)
if (board.slug != board_slug):
# This does not always work depending on what is entered
return redirect(request.get_full_path().replace(board_slug, board.slug, 1))
else:
return func(request, board_slug)
except:
raise Http404('')
return wrapper
A middleware is a good choice if you want to process requests in many different views.
class RedirectMiddleware(object):
def process_request(self, request):
if request.resolver_match.app_name == 'posts' \
and 'post_slug' in request.resolver_match.kwargs:
new_path = None
# your logic here
if new_path:
return redirect(new_path, permanent=True)
return
In settings:
MIDDLEWARE = [
# another middlewares here ...
'path.to.RedirectMiddleware',
]
I am using Django-registration and I have subclassed the BaseRegistrationView to customised a backend.
However, the HttpResponseRedirect fail to redirect to a new page when the condition is met.
The code is listed below:
class CustomRegistrationView(BaseRegistrationView):
def register(self, request, **cleaned_data):
captchaMatch = False
#check captcha
captchaValue = request.session.get('captcha')
captchaValueSubmitted = cleaned_data['captcha'] + "123"
if captchaValue != captchaValueSubmitted:
return HttpResponseRedirect(reverse('InvitationRequired'))
else:
self.captchaMatch = True
username, email, password = cleaned_data['username'], cleaned_data['email'], cleaned_data['password1']
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)
new_user = RegistrationProfile.objects.create_inactive_user(username, email,
password, site)
signals.user_registered.send(sender=self.__class__,
user=new_user,
request=request)
return new_user
def registration_allowed(self, request):
"""
Indicate whether account registration is currently permitted,
based on the value of the setting ``REGISTRATION_OPEN``. This
is determined as follows:
* If ``REGISTRATION_OPEN`` is not specified in settings, or is
set to ``True``, registration is permitted.
* If ``REGISTRATION_OPEN`` is both specified and set to
``False``, registration is not permitted.
"""
return getattr(settings, 'REGISTRATION_OPEN', True)
def get_success_url(self, request, user):
"""
Return the name of the URL to redirect to after successful
user registration.
"""
print "get successful url"
if self.captchaMatch:
return ('registration_complete', (), {})
else:
return HttpResponseRedirect(reverse('InvitationRequired'))
Can anyone help explain why the redirection is executed inside the function register ?
I guess the register method is supposed to return a user or None. Not an HttpRedirect object. Since I'm not familiar with this specific app, try to see how they handle failure on the original method and follow that policy (e.b. return None or raise an Exception).
Also, based on the comments on the get_success_url() method, I would expect the code to be like this:
def get_success_url(self, request, user):
"""
Return the name of the URL to redirect to after successful
user registration.
"""
if self.captchaMatch:
return ('registration_complete', (), {})
else:
return ('InvitationRequired', (), {})
I guess you should not return a HttpResponse instance, as the method is used to get the URL to be redirect to (not the redirection itself).