Same-site iframes not able to connect in Django - html

The iframe displays that it cannot connect. I've tried using the default #xframe_options_exempt decorator on the view, aswell as django-csp's #csp_exempt to no avail.
The console errors given are:
Refused to display 'http://localhost:8000/new_pull/' in a frame because it set 'X-Frame-Options' to 'deny'.
and
Failed to load resource: the server responded with a status of 404 (Not Found)
view
#csp_exempt
#login_required
def new_pull(request):
"""Create a new pull request"""
if request.method != 'POST':
# No data submitted; create a blank form
form = PullForm()
else:
# POST data submitted; process data
form = PullForm(data=request.POST)
if form.is_valid():
new_pull = form.save(commit=False)
new_pull.owner = request.user
new_pull.save()
# Display a blank or invalid form.
context = {'form': form}
return render(request, 'learning_logs/new_pull.html', context)
base.html
{% if user.is_authenticated %}
<br>
<iframe src="{% url 'learning_logs:new_pull' %}" title="Pull request Iframe"></iframe>
<iframe src="learning_logs/new_pull.html" title="Pull request Iframe"></iframe>
{% endif %}
new_pull.html
<div class="pull container text-center border-top mt-5">
<h5 class="mt-2">Pull request</h5>
<p>New pull request:</p>
<form action="{% url 'learning_logs:new_pull' %}" method='post'>
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button name="submit" class="btn btn-green pl-2 pr-2">
<i class="fas fa-plus-circle"></i>
Create pull
</button>
{% endbuttons %}
<input type="hidden" name="next"
value="{% url 'learning_logs:bug_tracker' %}" />
</form>
</div>

Try adding this to Settings.py:
X_FRAME_OPTIONS = 'SAMEORIGIN'
By default, the X-Frame-Options are set to Deny
https://docs.djangoproject.com/en/3.0/ref/clickjacking/
This may not be your problem, as there are many things that could be causing this, such as CSP. Difficult to say for sure without my information.

First good to mention the documentation of the django-csp Configuring django-csp
Try to do first what's bones225 mentioned.
Esure header X-Frame-Options "SAMEORIGIN'; Note, you can check all your current headers in Response Headers in the Web Developer Tools (chrome: Network -> Name -> click on html page -> Headers will open on right side )
You may have directive CSP_DEFAULT_SRC = ("'self'") in place and no CSP_FRAME_SRC set.
Then add CSP_FRAME_SRC = ('localhost:8000') too.

Related

Form not submitting to correct url in django

Im making a web app in django and im having a problem with a form which isnt submitting to the correct place
searcc.html
<form method='POST', action='/saveApply'">
{% csrf_token %}
<div class="JobSub">
<input value="{{user.id}}" name="usrid">
<input value="{{comp.id}}" name="compid">
<button type="submit">Submit</button>
</div>
</form>
views.py
def saveApply(request):
current_user = request.user
if request.method == 'POST': # Foreign key to User is just the username
savedApply.objects.create(
user = request.POST.get('usrid'),
company = request.POST.get('company')
)
return render('main/profile.html') # Change later
return redirect('login')
The confusing thing is, when I press on the submit button Im not even getting sent to the login view. I am getting sent to the home page. I think the problem has something to do with the fact that this html page is getting included in another.
main.html
{% include 'main/search.html' %}
{% endblock %}
Main.html is also inheriting from another file
Urls.py
path('saveApply/', views.saveApply, name="saveApply"),
path('feed/', views.feed, name='feed'),

How to redirect to other page using submit button

I am writing a view that retrieve an answer from game2.html, check the answer; if the answer is correct, the view will redirect user to correct.html, if the answer is incorrect, then user will be redirected to incorrect.html.
The problem now is after clicking the submit button, user won't be redirected. But the score is updated.
After I clicked submit button the url will change from http://localhost:8000/game2/ to http://localhost:8000/game2/?ans2=4&game2Answer=Submit instead of redirect to correct.html or incorrect.html
I guess it might be the problem of my submit button that doesn't trigger the redirect function, or it is the problem of the way I write redirect function in views, as the score is actually updated if the answer is correct.
So, how can i fix it to make it able to redirect to either correct.html or incorrect.html after going into the if-else statement.
morse_logs/views.py
#login_required()
def game2(request):
"""The Game2 page"""
if request.user and not request.user.is_anonymous:
user = request.user
def verifyGame2(val1):
user_score, created = userScore.objects.get_or_create(user=user)
if val1 == 4:
# user's score declared in model increase 5points
# display correct and 5 points added to user
user_score.score += 5
user_score.save()
return redirect('morse_logs:incorrect')
else:
# user's score declared in model has no point
# display incorrect and 0 point added to user
return redirect('morse_logs:incorrect')
ans2 = request.GET.get('ans2', '')
if ans2 == '':
ans2 = 0
verifyGame2(int(ans2))
return render(request, 'morse_logs/game2.html')
game2.html
{% extends "morse_logs/base.html" %}
{% block content %}
<title>GAME 2</title>
<div>
<h1>GAME 2</h1>
<h2>2 + 2 = ?</h2>
<form action="" method="post" >
<input type="number" id="ans1" name="ans1"/><br><br>
<input type="submit" name="game1Answer"/>
</form>
</div>
{% endblock content %}
morse_logs/correct.html
{% extends "morse_logs/base.html" %}
{% block content %}
<title>Correct!</title>
<div>
<h1>Congratulations! Your answer is CORRECT!</h1>
</div>
{% endblock content %}
morse_logs/incorrect.html
{% extends "morse_logs/base.html" %}
{% block content %}
<title>Inorrect...</title>
<div>
<h1>Unfortunately! Your answer is Incorrect!</h1>
</div>
{% endblock content %}
morse_logs/urls.py
from django.urls import path, include
from morse_logs import views
app_name = 'morse_logs'
urlpatterns = [
#The path() function is passed four arguments, two required: route and view, and two optional: kwargs, and name.
# Home Page
path(r'', views.index, name='index'),
# Page that shows all topics
path(r'topics/', views.topics, name='topics'),
path(r'cipher/', views.cipher, name='cipher'),
path(r'decipher/', views.decipher, name='decipher'),
path(r'tutorialIndex/', views.tutorialIndex, name='tutorialIndex'),
path(r'gameDirectory/', views.gameDirectory, name='gameDirectory'),
path(r'game1/', views.game1, name='game1'),
path(r'game2/', views.game2, name='game2'),
path(r'correct/', views.correct, name='correct'),
path(r'incorrect/', views.incorrect, name='incorrect'),
]
You should change your
redirect('morse_logs:incorrect.html')
to
redirect('url_name')
And also remove the app_name if you are using django version >2.0
First, I changed the template form method from "GET" to "POST" and add {% csrf_token %}.
Secondly, I changed the view into 2 parts:
1st part is when user first enter game2.html(GET request), it will render game2.html to user.
2nd part is basically what I have done before, but this time I added a case that respond to user's POST request, and from there to do redirections to either correct.html or incorrect.html
game2.html
{% extends "morse_logs/base.html" %}
{% block content %}
<title>GAME 2</title>
<div>
<h1>GAME 2</h1>
<h2>2 + 2 = ?</h2>
<form method="POST">
{% csrf_token %}
<input type="number" id="ans2" name="ans2"/><br><br>
<input type="submit" name="Submit"/>
</form>
</div>
{% endblock content %}
views.py
#login_required()
def game2(request):
"""The Game2 page"""
if request.method == "GET":
return render(request, 'morse_logs/game2.html')
elif request.method == "POST":
if request.user and not request.user.is_anonymous:
user = request.user
user_score, created = userScore.objects.get_or_create(user=user)
ans2 = request.POST.get('ans2', '') #fetch the POST data from template
if ans2 == '':
ans2 = 0
ans2 = int(ans2)
if ans2 == 4:
# user's score declared in model increase 5points
# display correct and 5 points added to user
user_score.score += 5
user_score.save()
return redirect(reverse('morse_logs:correct'))
else:
# user's score declared in model has no point
# display incorrect and 0 point added to user
return redirect(reverse('morse_logs:incorrect'))

Django - System architecture for reusing user registration form on multiple pages

I was figuring how to reuse the same registration form and view on multiple templates and pages, and in different formats. E.g. on the page, in a modal etc. I am however some trouble in figuring out the best practice for solving this problem. One thing I am actively trying to avoid is repeating myself, but I can't seem to find a solution that is satisfying enough.
At the moment I have one central view that handles user registrations that looks like this. At the moment it can only handle to output one form on the signup_form template, but I want to extend that to the index page and be able to be outputted in a modal as well.
Views.py
def signup(request):
template_name = 'core/authentication/signup_form.html'
custom_error_list = []
if request.method == "POST":
form = SignUpForm(request.POST)
if form.is_valid():
#Check for duplciate email
email = form.cleaned_data.get('email')
username = form.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(username=username).exists():
custom_error_list.append("A user with that email already exists")
else:
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
subject = 'Activate your StockPy Account'
sender = '' #Insert sender address here
message = render_to_string('core/authentication/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user)
})
user.email_user(subject, message)
return redirect('authentication:account_activation_sent')
else:
form = SignUpForm()
return render(request, template_name, {'form': form, 'custom_error_list': custom_error_list})
#Activate the user as he/she clicks the email verification link which lead to tihs view
def activate(request, uidb64, token):
try:
#Using a [:1] is ad-hoc solution to get rid of the starting 'b' symbol
uid = force_text(urlsafe_base64_decode(uidb64[1:]))
user = User.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.profile.email_confirmed = True
user.save()
login(request, user)
return redirect(template_name)
else:
return render(request, 'core/authentication/account_activation_invalid.html')
forms.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
class LoginForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['email','password']
class SignUpForm(UserCreationForm):
email = forms.EmailField(max_length=254, widget=forms.TextInput(attrs={'placeholder': 'Email...', 'class' : 'form-control', 'pattern' : '[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,3}$'}))
class Meta:
model = User
fields = ['email', 'username', 'password1', 'password2']
def __init__(self, *args, **kwargs):
super(SignUpForm, self).__init__(*args, **kwargs)
self.fields['username'].widget = forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Username...',
})
self.fields['password1'].widget = forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Password...',
'type': 'password',
})
self.fields['password2'].widget = forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Password again...',
'type': 'password',
})
My signup form currently looks like this.
signup_form.html
{% extends 'base.html' %}
{% load static %}
<!-- End Navbar -->
{% block page-header %}
<div class="section section-signup" style="background-image: url({% static 'core/assets/img/bg8.jpg' %}); background-size: cover; background-position: top center; min-height: 700px;">
<div class="container">
<div class="row">
<div class="card card-signup" data-background-color="orange">
<form class="form" method="POST" action="">
{% csrf_token %}
<div class="header text-center">
<h4 class="title title-up">Sign Up</h4>
<div class="social-line">
<a href="#twitter" class="btn btn-neutral btn-twitter btn-icon btn btn-round">
<i class="fa fa-twitter"></i>
</a>
<a href="#facebook" class="btn btn-neutral btn-facebook btn-icon btn-lg btn-round">
<i class="fa fa-facebook-square"></i>
</a>
<a href="#google" class="btn btn-neutral btn-google btn-icon btn-round">
<i class="fa fa-google-plus"></i>
</a>
</div>
</div>
<div class="card-body">
<!-- Output error messages -->
{% for field in form %}
<div style="color:red; list-decorations:none;" class="text-center">
{{ field.errors.as_text }}
</div>
{% endfor %}
{% for error in custom_error_list %}
<div style="color:red;" class="text-center">
* {{ error }}
</div>
{% endfor %}
<!-- Output all fields -->
{% for field in form %}
<div class="input-group form-group-no-border">
<span class="input-group-addon">
<i class="now-ui-icons
{% if field.name == 'email' %} ui-1_email-85{% endif %}
{% if field.name == 'username' %} users_circle-08{% endif %}
{% if field.name == 'password1' %} ui-1_lock-circle-open{% endif %}
{% if field.name == 'password2' %} ui-1_lock-circle-open{% endif %}
"></i>
</span>
{{ field }}
<!-- Give input box red border if data is not valid -->
{% if field.errors %}
<script>
var element = document.getElementById("{{ field.id_for_label }}");
element.classList.add("form-control-danger");
</script>
{% endif %}
</div>
{% endfor %}
<div class="text-center">
Already registered? Log in here
</div>
<!-- If you want to add a checkbox to this form, uncomment this code -->
<!-- <div class="checkbox">
<input id="checkboxSignup" type="checkbox">
<label for="checkboxSignup">
Unchecked
</label>
</div> -->
</div>
<div class="footer text-center">
<button type="submit" class="btn btn-neutral btn-round btn-lg">Get Started</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock page-header %}
And a small example snippet of my index.html of how I want to implement it ish.
index.html
<div class="main">
<div class="section section-about-us">
<div class="container">
<div class="col-md-8 ml-auto mr-auto text-center">
{{ form }}
</div>
</div>
</div>
</div>
I have really tried to find a smooth way of doing this, but without result unfortunately.
It seems as though you already know how to implement the same form in multiple templates, but you've having trouble avoiding repetition in your code. To that end, here are some suggestions for reducing the amount of repetition you'll encounter when duplicating this form across multiple pages:
Validate data within your form rather than your view. Currently, you are checking for duplicate e-mail addresses within views.py. If you duplicated your form, you'd have to re-write that code all over again. Instead, why not move it into forms.py in a custom cleaning method (see Django docs on custom form cleaning).
Write functions for actions that will be repeated. For example, currently, you are sending an activation e-mail to your user within views.py. It makes more sense to write a function within your user/models.py called something like send_activation_email(). Whenever you want to send an activation e-mail to a user, you can then call user.send_activation_email() rather than duplicating your entire block of activation e-mail code (see Django docs on model methods).
Use inclusion tags to avoid repetition in your templates. If there's a block of code that you find yourself repeating in your templates, you can use Django's inclusion tags to include a snippet of HTML across multiple templates. This allows you to serve the same form in multiple locations without re-writing your code. If you want to style your form differently across multiple pages, you could wrap it in DIVs with different IDs and use CSS to style the form differently depending on which DIV it's wrapped in. (see Django docs on inclusion tags)

Django : HTML form action directing to view (or url?) with 2 arguments

Started learning django about a week ago and ran into a wall. Would really appreciate any enlightenment...
models.py
class data(models.Model):
course = models.CharField(max_length = 250)
def __str__(self):
return self.course
html
Converted the objects in models.course to schlist
<link rel="stylesheet" type="text/css" href="{% static '/chosen/chosen.css' %}" />
<form action={% views.process %} method="GET">
<div>
<h4 style="font-family:verdana;">First Course: </h4>
<select data-placeholder="Course" style="width:350px;" class="chosen-select" tabindex="7">
<option value=""></option>
{% for item in schlist %}
<option> {{ item }} </option>
{% endfor %}
</select>
</div>
</br>
<div>
<h4 style="font-family:verdana;">Second Course:</h4>
<select data-placeholder="Course" style="width:350px;" class="chosen-select" tabindex="7">
<option value=""></option>
{% for item in schlist %}
<option> {{ item }} </option>
{% endfor %}
</select>
</div>
</br>
<input type="submit" value="Compare!" />
</form>
urls.py (having my doubts if this works..)
urlpatterns = [
url(r'^(\d+)/(\d+)$',views.process, name = 'process'),
]
view.py
def process(request,q1 ,q2):
obj1= get_object_or_404(Schdata, course = q1)
obj2= get_object_or_404(Schdata, course = q2)
........
Was wondering if it is possible for the form action to direct the action to
(1) view.py or (2) url.py (and eventually to a view.py) with 2 arguments selected?
If so how should the form action be? {{view ?}} or {{url ?}}. Am I missing out the definition of my arguments in my HTML?
Directing to views.py:
User input is CharField, could use get_object_or_404 to get the model pk. However when defining my urls.py I would get a Noreverse error as my url arguments is the primary key.
Directing to urls.py:
Url arguments is primary key. From the way I see it, I need to magically convert my User input Charfield to a pk before passing it to urls.py
Is there a (or) function for get() in django? E.g get_object_or_404(pk = q1 or course = q1)?
Would really appreciate any advice. Been staring at this for hours.
You are trying to use the reverse resolution of urls in Django.
In your html file correct form action url to the following and method should be POST:
<form action={% url 'process' %} method="POST">
In case you are trying to pass parameters along then use this:
<form action={% url 'process' request.user.id 4 %} method="POST">
Reference:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Yes i'm late but it can help others for better understanding how Django processes the request.
Django 3.0 pattern
How Django processes the request
Basic :
First Django check the matching URL.
If URL is matched then calling the defined view to process the request. (Success)
If URL not matched/found the Django invokes error Page Not Found
In detail reading :
Official Django Documentations How Django processes a request
These are your URL patterns :
urlpatterns = [ path('profile/edit/<int:pk>/',views.editprofile, name='editprofile'),]
Third argument in urlpatterns is for if you want to change the url pattern from current to this :
urlpatterns = [ url('profile/edit/user/id/<int:pk>',views.editprofile, name = 'editprofile'),]
You don't need to redefine url pattern in all Templates where you using url name.
For Example :
This is my template profile.html where i used the url name instead of hard coded url.
<a class="item" href="{% url 'editprofile' user.id %}" >Edit profile </a>
Solution of your problem :
.html
Only use url name instead of hard coded url in your templates and pass arguments.
<form action={% process no_of_arguments %} method="POST">
views.py
Here you can process your request
def process(request,no_of_arguments):
Become good django developer
You can also use Django ModelForms for your model.
Using model forms or simple form you can do multiple things
Modular approach
Write server side validation in related form instead of doing in views.py
Readable code - Clean code

Working with links in Django

I am working in a small blog application using Django. Sorry if the question is obvious, but I am a newbie. Actually it is my third since I started an online course. I have the following Queryset:
def all(request):
allTiles = Post.objects.values('title')
allPosts = Post.objects.all()[:3]
context = {'Posts': allPosts,"Titles":allTiles}
template = "home.html"
return render(request, template, context)
and the follwing html code:
<ol class="list-unstyled">
{% for singleTile in Titles %}
<li>{{singleTile.title}}</li>
{% endfor %}
</ol>
As you can see every title creates an link. Lets assume a person decides to read one of the posts. How can I use the title name and send a request back to the database to get the content of the post.
It is better to use the id or slug field for such task.
But if you surely want to use the title as the GET parameter then apply the urlencode filter to the field's value:
<a href="{% url 'post_detail' %}?title={{ singleTile.title|urlencode }}">
{{ singleTile.title }}
</a>
And the view will be something like this:
def post_detail(request):
post = get_object_or_404(Post, title=request.GET.get('title'))
return render(request, 'post_detail.html', {'post': post})
UPDATE: If you decide to go with the id/slug option then you can use the generic DetailView:
<a href="{% url 'post_detail' singleTile.id %}">
{{ singleTile.title }}
</a
urls.py:
from django.views.generic.detail import DetailView
from app.models import Post
url(r'^post/(?P<pk>\d+)/$', DetailView.as_view(model=Post),
name='post_detail')
You have to configure url first like
{% url 'app.views.post_id' singleTile.id %}</li>
In your urls
url(r'^post/(?P<post_id>\d+)/$', views.by_id, name='post_id'),
And in your views
def post_id(request, post_id):
allTiles = Post.objects.get(id=post_id)
return render(request, template, context)