Merge branch 'master' of code.ungleich.ch:ungleich-public/ungleich-learning-circle

This commit is contained in:
Nico Schottelius 2021-05-11 15:20:27 +02:00
commit 9e0091015e
161 changed files with 3680 additions and 19 deletions

View File

@ -7,5 +7,6 @@ into the ungleich clearning circle.
* [Balazs](https://code.ungleich.ch/llnu/ungleich-learning-circle-balazs): git@code.ungleich.ch:llnu/ungleich-learning-circle-balazs.git
* [Jin-Guk](https://code.ungleich.ch/kjg/ungleich-learning-circle): git@code.ungleich.ch:kjg/ungleich-learning-circle.git
* [Pedro](https://code.ungleich.ch/pedro/ungleich-learning-circle): git@code.ungleich.ch:pedro/ungleich-learning-circle.git
* [Sami](https://code.ungleich.ch/samialazar/learning-cicle): git@code.ungleich.ch:samialazar/learning-cicle.git
* [Youngjin](https://code.ungleich.ch/youngjin.han/ungleich-learning-circle): git@code.ungleich.ch:youngjin.han/ungleich-learning-circle.git

9
add-remotes.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
# Nico Schottelius, 2020-07-22
grep '^* \[' README.md | sed 's/.*\[\(.*\)].*: \(git@.*\)/\1 \2/' | (
while read name repo; do
name_small=$(echo $name | tr 'A-Z' 'a-z')
git remote add $name_small $repo
done
)

150
kjg/.emacs Normal file
View File

@ -0,0 +1,150 @@
;; Added by Package.el. This must come before configurations of
;; installed packages. Don't delete this line. If you don't want it,
;; just comment it out by adding a semicolon to the start of the line.
;; You may delete these explanatory comments.
(require 'package)
(add-to-list 'package-archives
'("melpa" . "http://melpa.org/packages/") t)
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
(package-initialize)
(global-set-key (kbd "<f3>") (lambda () (interactive) (find-file (concat "~/ungleich-learning-circle/kjg/learning-"(system-name)"-"(format-time-string "%Y")".org"))))
(global-set-key (kbd "C-x g") 'magit-status)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "<f8>") 'org-todo-list)
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(epg-gpg-program "/usr/local/bin/gpg")
'(org-agenda-files
(quote
("~/ungleich-learning-circle/kjg/todo.org" "~/learning.org")))
'(package-selected-packages (quote (org org-gnome org-dp ## which-key magit)))
'(python-shell-interpreter "python3")
'(send-mail-function (quote sendmail-send-it)))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)
(require 'epa-file)
(epa-file-enable)
(setq elpy-rpc-virtualenv-path 'current)
;(use-package elpy
; :ensure t
; :config
; (elpy-enable)
; (setq elpy-rpc-python-command "python3")
; (setq elpy-rpc-backend "jedi")
; (elpy-use-cpython (or (executable-find "python3")
; (executable-find "/usr/bin/python3")
; (executable-find "/usr/local/bin/python3")
; "python3"))
;; (elpy-use-ipython)
; (setq python-shell-interpreter-args "--simple-prompt -i")
; (add-hook 'python-mode-hook (lambda () (setq indent-tabs-mode nil))))
;(use-package ein :ensure t)
(setq elpy-rpc-python-command "python3")
(defvar myPackages
'(better-defaults ;; Set up some better Emacs defaults
elpy ;; Emacs Lisp Python Environment
flycheck ;; On the fly syntax checking
py-autopep8 ;; Run autopep8 on save
blacken ;; Black formatting on save
ein ;; Emacs IPython Notebook
material-theme ;; Theme
)
)
(elpy-enable)
;; Use IPython for REPL
;(setq python-shell-interpreter "jupyter"
; python-shell-interpreter-args "console --simple-prompt"
; python-shell-prompt-detect-failure-warning nil)
;(add-to-list 'python-shell-completion-native-disabled-interpreters
; "jupyter")
;; Enable Flycheck
(when (require 'flycheck nil t)
(setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
(add-hook 'elpy-mode-hook 'flycheck-mode))
;(setq mu4e-mu-binary "/usr/local/bin/mu")
;(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu/mu4e")
;(require 'mu4e)
;(setq
; mue4e-headers-skip-duplicates t
; mu4e-view-show-images t
; mu4e-view-show-addresses t
; mu4e-compose-format-flowed nil
; mu4e-date-format "%y/%m/%d"
; mu4e-headers-date-format "%Y/%m/%d"
; mu4e-change-filenames-when-moving t
; mu4e-attachments-dir "~/Downloads"
; mu4e-maildir "~/Maildir/ungleich" ;; top-level Maildir
;; note that these folders below must start with /
;; the paths are relative to maildir root
; mu4e-refile-folder "/Archive"
; mu4e-sent-folder "/Sent"
; mu4e-drafts-folder "/Drafts"
; mu4e-trash-folder "/Trash"
; mu4e-reply-to-address "jinguk.kwon@ungleich.ch"
; user-mail-address "jinguk.kwon@ungleich.ch"
; user-full-name "kjg")
;; this setting allows to re-sync and re-index mail
;; by pressing U
;(setq mu4e-get-mail-command "mbsync -a")
;(setq mail-host-address "mail.ungleich.ch")
;(setq send-mail-function 'smtpmail-send-it
; message-send-mail-function 'smtpmail-send-it
; user-mail-address "jinguk.kwon@ungleich.ch"
; smtpmail-starttls-credentials '(("smtp.ungleich.ch" 587 nil nil))
; smtpmail-auth-credentials "~/.authinfo.gpg"
; smtpmail-default-smtp-server "smtp.ungleich.ch"
; smtpmail-smtp-server "smtp.ungleich.ch"
; smtpmail-smtp-service 587
; smtpmail-smtp-user "jinguk.kwon@ungleich.ch"
; smtpmail-debug-info t
; smtpmail-debug-verb t)
;;starttls-extra-arguments nil
;;starttls-gnutls-program (executable-find "gnutls-cli")
;;smtpmail-warn-about-unknown-extensions t
;;starttls-use-gnutls t)
;(require 'smtpmail)
;;store org-mode links to messages
;(require 'org-mu4e)
;(define-key mu4e-headers-mode-map (kbd "C-c c") 'mu4e-org-store-and-capture)
;(define-key mu4e-view-mode-map (kbd "C-c c") 'mu4e-org-store-and-capture)
(setq org-directory (expand-file-name "~/ungleich-learning-circle/kjg/"))
;;store link to message if in header view, not to header query
(setq org-mu4e-link-query-in-headers-mode nil)
(setq org-capture-templates
'(("t" "todo" entry (file+headline (lambda() (concat "~/ungleich-learning-circle/kjg/todo-"(system-name)"-"(format-time-string "%Y")".org")) "Tasks")
"* TODO [#A] %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n")))
(setq org-log-done 'time)

3
kjg/IPv6/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
venv/
*.pyc
db.*

21
kjg/IPv6/overlap.py Normal file
View File

@ -0,0 +1,21 @@
from sys import argv
import ipaddress
# read the argument how to run this
try:
script, ip1, ip2 = argv
a = ip1.split('/')
b = ip2.split('/')
a = ipaddress.ip_network(a[0]).supernet(new_prefix=int(a[1]))
b = ipaddress.ip_network(b[0]).supernet(new_prefix=int(b[1]))
test1 = ipaddress.IPv6Network(a).overlaps(ipaddress.IPv6Network(b))
if test1 :
print("overlap")
else:
print("no overlap")
except:
print("wrong inpit")

52
kjg/IPv6/randomnet.py Normal file
View File

@ -0,0 +1,52 @@
from sys import argv
import argparse
import ipaddress
import random
#import getopt #option function
parser = argparse.ArgumentParser(description="Generating IPv6 networks")
parser.add_argument('--size', help="size")
parser.add_argument('string', nargs='+', help="network")
try:
args = parser.parse_args()
if argv[1] == '--size':
ipnet = argv[3]
size = 128 - int(argv[2])
else:
if len(argv) > 2 :
ipnet = argv[1]
size = 128 - int(argv[2])
else:
ipnet = argv[1]
size = 80
ip = ipnet.split('/')
ip2 = ipaddress.ip_network(ip[0]).supernet(new_prefix=int(ip[1]))
# minimum network
minNet = ipaddress.ip_network(ip[0]).supernet(new_prefix=128-size)
# seperate network
ip2first = ipaddress.IPv6Network(ip2)[0]
ip2last = ipaddress.IPv6Network(ip2)[-1]
minNetlast = ipaddress.IPv6Network(minNet)[-1]
# calculation network
maxRan = int(ip2last) - int(minNetlast) >> size
result = ipaddress.ip_address((random.randrange(0,maxRan) << size) + int(ip2first) )
resultNetwork = ipaddress.ip_network(result).supernet(new_prefix=128-size)
print(resultNetwork)
except:
info="""
wrong input
ex) --size 64 2001:db8::/40
or 2001:db8::/40 64
or 2001:db8::/40 #default size 48
"""
print(info)

21
kjg/IPv6/ula/manage.py Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ula.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

16
kjg/IPv6/ula/ula/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for ula project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ula.settings')
application = get_asgi_application()

View File

@ -0,0 +1,125 @@
"""
Django settings for ula project.
Generated by 'django-admin startproject' using Django 3.0.8.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'fj+%jfo4xd5rb(7w!7feda03q)y4md)*)e_rjw8i_gyab!6#-h'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["192.168.0.12", "testjg.django.lab.ungleich.ch", ]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ularegistry',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'ula.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'ula.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'kjg',
'USER': 'kjg',
'PASSWORD': 'kjg#test',
'HOST': 'localhost',
'PORT': '',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'

27
kjg/IPv6/ula/ula/urls.py Normal file
View File

@ -0,0 +1,27 @@
"""ula URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('ularegistry/', include('ularegistry.urls')),
path('admin/', admin.site.urls),
]

16
kjg/IPv6/ula/ula/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for ula project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ula.settings')
application = get_wsgi_application()

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class UlaregistryConfig(AppConfig):
name = 'ularegistry'

View File

@ -0,0 +1,13 @@
import ipaddress
def overlapip(ip1, ip2):
test1 = ipaddress.IPv6Network(ip1).overlaps(ipaddress.IPv6Network(ip2))
if test1 :
print("overlap")
return 0
else:
print("no overlap")
return 1

View File

@ -0,0 +1,16 @@
from django import forms
from netfields import CidrAddressField, NetManager
class ip(forms.Form):
inputIP = forms.CharField()
#inputIP = CidrAddressField()
class ip_random(forms.Form):
inputNetwork = forms.CharField()
NetworkName = forms.CharField()
NetworkDescription = forms.CharField()
class new_ip_random(forms.Form):
NetworkName = forms.CharField()
NetworkDescription = forms.CharField()

View File

@ -0,0 +1,22 @@
# Generated by Django 3.0.8 on 2020-07-29 13:34
from django.db import migrations, models
import netfields.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='IPs',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('inet', netfields.fields.CidrAddressField(max_length=43)),
],
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.0.8 on 2020-08-03 14:30
from django.db import migrations, models
import netfields.fields
class Migration(migrations.Migration):
dependencies = [
('ularegistry', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='ips2',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('inet2', netfields.fields.CidrAddressField(max_length=43)),
('inet2_name', models.CharField(max_length=200)),
('inet2_descrip', models.CharField(max_length=200)),
],
),
]

View File

@ -0,0 +1,17 @@
from django.db import models
from netfields import CidrAddressField, NetManager
# Create your models here.
class ips(models.Model):
inet = CidrAddressField()
objects = NetManager()
def __str__(self):
st = str(self.inet)
return st
class ips2(models.Model):
inet2 = CidrAddressField()
inet2_name = models.CharField(max_length=200)
inet2_descrip = models.CharField(max_length=200)

View File

@ -0,0 +1,29 @@
from sys import argv
import argparse
import ipaddress
import random
def createIP(ip):
ipnet = ip
size = 80
ip = ipnet.split('/')
ip2 = ipaddress.ip_network(ip[0]).supernet(new_prefix=int(ip[1]))
# minimum network
minNet = ipaddress.ip_network(ip[0]).supernet(new_prefix=128-size)
# seperate network
ip2first = ipaddress.IPv6Network(ip2)[0]
ip2last = ipaddress.IPv6Network(ip2)[-1]
minNetlast = ipaddress.IPv6Network(minNet)[-1]
# calculation network
maxRan = int(ip2last) - int(minNetlast) >> size
result = ipaddress.ip_address((random.randrange(0,maxRan) << size) + int(ip2first) )
resultNetwork = ipaddress.ip_network(result).supernet(new_prefix=128-size)
print(resultNetwork)
return resultNetwork

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- change something -->
{% if user.is_authenticated %}
<h3> {{ user.username }} welcome </h3>
<a href="{% url 'logout' %}">logout</a>
{% else %}
<a href="{% url 'signup' %}">signup</a>
<a href="{% url 'login' %}">login</a>
{% endif %}
{% block container %}
{% endblock %}
</body>
</html>

View File

@ -0,0 +1,14 @@
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="registry">
</form>
{% if ips_list %}
<ul>
{% for ips in ips_list %}
<li>{{ ips.inet }}</li>
{% endfor %}
</ul>
{% else %}
<p>No registered IP.</p>
{% endif %}

View File

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% block container %}
<h3>login</h3>
<form method="POST">
{% csrf_token %}
{{ login_form }}
<input type="submit" value="Submit"/>
</form>
{% endblock %}

View File

@ -0,0 +1,19 @@
{% extends 'base.html' %}
{% block container %}
<form action="" method="post">
{% csrf_token %}
<table>
{{ form2 }}
</table>
<input type="submit" value="random create">
</form>
{% if ips_listr %}
<ul>
{% for ips2 in ips_listr %}
<li>{{ ips2.inet2 }} {{ ips2.inet2_name}} {{ ips2.inet2_descrip }} </li>
{% endfor %}
</ul>
{% else %}
<p>No registered IP.</p>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,16 @@
<form action="" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="random create">
</form>
{% if ips_listr %}
<ul>
{% for ips2 in ips_listr %}
<li>{{ ips2.inet2 }} {{ ips2.inet2_name}} {{ ips2.inet2_descrip }} </li>
{% endfor %}
</ul>
{% else %}
<p>No registered IP.</p>
{% endif %}

View File

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% block container %}
<h3>sign-up</h3>
<form method="POST">
{% csrf_token %}
{{ signup_form }}
<input type="submit" name="Submit"/>
</form>
{% endblock %}

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,12 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('randomIP', views.randomIP, name='randomIP'),
path('newrandomIP', views.newrandomIP, name='newrandomIP'),
path('login/', views.login, name='login'),
path('logout/', views.logout, name='logout'),
path('signup/', views.signup, name='signup'),
]

View File

@ -0,0 +1,172 @@
from django.shortcuts import render
from django.http import HttpResponse
from .forms import ip_random, new_ip_random, ip
from ularegistry.models import ips, ips2
from django.shortcuts import redirect
from ularegistry.checkip import *
from ularegistry.randomcreate import *
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login as auth_login
from django.contrib.auth import logout as auth_logout
# Create your views here.
def index(request):
ips_list = ips.objects.values()
if request.method == "POST":
form = ip(request.POST)
print(form)
if form.is_valid():
ips_list2 = list(ips_list)
if not ips_list2:
print("test")
q = ips(inet=form.cleaned_data['inputIP'])
q.save()
overlapchk = 0
for value in ips_list2:
if overlapip(form.cleaned_data['inputIP'],value['inet']):
overlapchk = 1
else:
overlapchk = 0
break
if overlapchk:
print(overlapchk)
q = ips(inet=form.cleaned_data['inputIP'])
q.save()
return redirect('index')
else:
form = ip()
ctx = { 'form' : form,
'ips_list' : ips_list,
}
return render(request, 'index.html', ctx)
#return HttpResponse("Hello, world.")
def randomIP(request):
ips_listr = ips2.objects.values()
if request.method == "POST":
form = ip_random(request.POST)
print(form)
if form.is_valid():
while True:
newIP = createIP(form.cleaned_data['inputNetwork'])
ips_listr2 = list(ips_listr)
if not ips_listr2:
print("test")
q = ips2(inet2=newIP, inet2_name=form.cleaned_data['NetworkName'], inet2_descrip=form.cleaned_data['NetworkDescription'])
q.save()
break
overlapchk = 0
for value in ips_listr2:
if overlapip(newIP,value['inet2']):
overlapchk = 1
print(overlapchk)
q = ips2(inet2=newIP, inet2_name=form.cleaned_data['NetworkName'], inet2_descrip=form.cleaned_data['NetworkDescription'])
q.save()
break
else:
overlapchk = 0
if overlapchk:
break
return redirect('randomIP')
else:
form = ip_random()
ctx = { 'form' : form,
'ips_listr' : ips_listr,
}
return render(request, 'randomIP.html', ctx)
def newrandomIP(request):
ips_listr = ips2.objects.values()
if request.method == "POST":
form2 = new_ip_random(request.POST)
print(form2)
if form2.is_valid():
while True:
newIP = createIP("fd00::/8")
print("test3")
ips_listr2 = list(ips_listr)
if not ips_listr2:
print("test2")
q = ips2(inet2=newIP, inet2_name=form2.cleaned_data['NetworkName'], inet2_descrip=form2.cleaned_data['NetworkDescription'])
q.save()
break
overlapchk = 0
for value in ips_listr2:
if overlapip(newIP,value['inet2']):
overlapchk = 1
print(overlapchk)
q = ips2(inet2=newIP, inet2_name=form2.cleaned_data['NetworkName'], inet2_descrip=form2.cleaned_data['NetworkDescription'])
q.save()
break
else:
overlapchk = 0
if overlapchk:
break
return redirect('newrandomIP')
else:
form2 = new_ip_random()
ctx2 = { 'form2' : form2,
'ips_listr' : ips_listr,
}
return render(request, 'newrandomIP.html', ctx2)
def signup(request):
if request.user.is_authenticated:
return redirect('newrandomIP')
if request.method == 'POST':
signup_form = UserCreationForm(request.POST)
if signup_form.is_valid():
user = signup_form.save()
auth_login(request, user)
return redirect('login')
else:
print("fail singup")
else:
signup_form = UserCreationForm()
return render(request, 'signup.html', {'signup_form':signup_form})
def login(request):
if request.user.is_authenticated:
return redirect('newrandomIP')
if request.method == 'POST':
login_form = AuthenticationForm(request, request.POST)
if login_form.is_valid():
auth_login(request, login_form.get_user())
return redirect('newrandomIP')
else:
print("fail login")
else:
login_form = AuthenticationForm()
return render(request, 'login.html', {'login_form' : login_form})
def logout(request):
auth_logout(request)
return redirect('login')

View File

@ -11,3 +11,5 @@ It is used in some local place
start from FC00::/7
L must be 1.
Global ID is created randomly.
*** django #2

View File

@ -25,12 +25,13 @@ SECRET_KEY = '2kbmvs@pcbxn)kt#p9$)45=h#i8_b7^^l&l57mbe4%e=+k91-d'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
ALLOWED_HOSTS = [ "[2a0a:e5c1:114::12]", "127.0.0.1", "[2a0a:e5c1:151::12]", "testjg.django.lab.ungleich.ch", "[2a0a:e5c1:114::17]" ]
#ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@ -54,7 +55,7 @@ ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [

View File

@ -14,8 +14,11 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]

View File

@ -1,3 +1,21 @@
from django.contrib import admin
# Register your models here.
from .models import Question, Choice
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
list_display = ('question_text', 'pub_date', 'was_published_recently')
list_filter = ['pub_date']
search_fields = ['question_text']
admin.site.register(Question, QuestionAdmin)
#admin.site.register(Choice)

View File

@ -0,0 +1,32 @@
# Generated by Django 3.0.8 on 2020-07-06 15:51
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Question',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question_text', models.CharField(max_length=200)),
('pub_date', models.DateTimeField(verbose_name='date published')),
],
),
migrations.CreateModel(
name='Choice',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('choice_text', models.CharField(max_length=200)),
('votes', models.IntegerField(default=0)),
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question')),
],
),
]

View File

@ -1,3 +1,34 @@
import datetime
from django.db import models
from django.utils import timezone
# Create your models here.
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
#def was_published_recently(self):
#return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

View File

@ -0,0 +1,8 @@
li a {
color: green;
}
body {
#background-position: center center;
background: white url("images/background2.png") no-repeat fixed center center;
}

View File

@ -0,0 +1,9 @@
{% extends "admin/base.html" %}
{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}
{% block nav-global %}{% endblock %}

View File

@ -0,0 +1,12 @@
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>

View File

@ -0,0 +1,13 @@
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

View File

@ -0,0 +1,9 @@
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

View File

@ -1,3 +1,128 @@
from django.test import TestCase
import datetime
# Create your tests here.
from django.test import TestCase
from django.utils import timezone
from django.urls import reverse
from .models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is in the future.
"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
def test_was_published_recently_with_old_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is older than 1 day.
"""
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
old_question = Question(pub_date=time)
self.assertIs(old_question.was_published_recently(), False)
def test_was_published_recently_with_recent_question(self):
"""
was_published_recently() returns True for questions whose pub_date
is within the last day.
"""
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)
def create_question(question_text, days):
"""
Create a question with the given `question_text` and published the
given number of `days` offset to now (negative for questions published
in the past, positive for questions that have yet to be published).
"""
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)
class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
"""
If no questions exist, an appropriate message is displayed.
"""
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_past_question(self):
"""
Questions with a pub_date in the past are displayed on the
index page.
"""
create_question(question_text="Past question.", days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
def test_future_question(self):
"""
Questions with a pub_date in the future aren't displayed on
the index page.
"""
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse('polls:index'))
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_future_question_and_past_question(self):
"""
Even if both past and future questions exist, only past questions
are displayed.
"""
create_question(question_text="Past question.", days=-30)
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
def test_two_past_questions(self):
"""
The questions index page may display multiple questions.
"""
create_question(question_text="Past question 1.", days=-30)
create_question(question_text="Past question 2.", days=-5)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question 2.>', '<Question: Past question 1.>']
)
class QuestionDetailViewTests(TestCase):
def test_future_question(self):
"""
The detail view of a question with a pub_date in the future
returns a 404 not found.
"""
future_question = create_question(question_text='Future question.', days=5)
url = reverse('polls:detail', args=(future_question.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_past_question(self):
"""
The detail view of a question with a pub_date in the past
displays the question's text.
"""
past_question = create_question(question_text='Past Question.', days=-5)
url = reverse('polls:detail', args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)

View File

@ -2,6 +2,10 @@ from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]

View File

@ -1,3 +1,74 @@
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
#from django.http import Http404
from django.template import loader
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from django.utils import timezone
# Create your views here.
from .models import Choice, Question
#def index(request):
# latest_question_list = Question.objects.order_by('-pub_date')[:5]
# context = {'latest_question_list': latest_question_list}
# return render(request, 'polls/index.html', context)
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""
Return the last five published questions (not including those set to be
published in the future).
"""
return Question.objects.filter(
pub_date__lte=timezone.now()
).order_by('-pub_date')[:5]
#"""Return the last five published questions."""
#return Question.objects.order_by('-pub_date')[:5]
#def detail(request, question_id):
# #return HttpResponse("You're looking at question %s." % question_id)
# question = get_object_or_404(Question, pk=question_id)
# return render(request, 'polls/detail.html', {'question': question})
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
def get_queryset(self):
"""
Excludes any questions that aren't published yet.
"""
return Question.objects.filter(pub_date__lte=timezone.now())
#def results(request, question_id):
# #response = "You're looking at the results of question %s."
# #return HttpResponse(response % question_id)
# question = get_object_or_404(Question, pk=question_id)
# return render(request, 'polls/results.html', {'question': question})
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def vote(request, question_id):
#return HttpResponse("You're voting on question %s." % question_id)
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

2
pedro/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*pyc
django-tutorial/mysite/db.sqlite3

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,16 @@
"""
ASGI config for mysite project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_asgi_application()

View File

@ -0,0 +1,126 @@
"""
Django settings for mysite project.
Generated by 'django-admin startproject' using Django 3.0.8.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '37jgpv28n1x!f3-48h)4ad99&jz-ek$@e6uf*an5uve6%7atqq'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = [
"localhost",
"2a0a-e5c1-011f-0000-0000-0000-0000-0001.has-a.name"
]
# Application definition
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Europe/Madrid'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'

View File

@ -0,0 +1,22 @@
"""mysite URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]

View File

@ -0,0 +1,16 @@
"""
WSGI config for mysite project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_wsgi_application()

View File

@ -0,0 +1,26 @@
from django.contrib import admin
# Register your models here.
from .models import Choice, Question
# stacked: that's lot of space
#class ChoiceInline(admin.StackedInline):
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
# # this way we changed the order
#fields = ['pub_date', 'question_text']
# # different organization of fields
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date']}),
]
inlines = [ChoiceInline]
list_display = ('question_text', 'pub_date', 'was_published_recently')
list_filter = ['pub_date']
search_fields = ['question_text']
admin.site.register(Question, QuestionAdmin)

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'

View File

@ -0,0 +1,32 @@
# Generated by Django 3.0.8 on 2020-07-03 12:48
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Question',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question_text', models.CharField(max_length=200)),
('pub_date', models.DateTimeField(verbose_name='date published')),
],
),
migrations.CreateModel(
name='Choice',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('choice_text', models.CharField(max_length=200)),
('votes', models.IntegerField(default=0)),
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question')),
],
),
]

View File

@ -0,0 +1,27 @@
import datetime
from django.db import models
from django.utils import timezone
# Create your models here.
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
# bug
#return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -0,0 +1,10 @@
li a {
color: green;
}
body {
/* thanks: https://stackoverflow.com/questions/12605908/change-background-image-opacity/40366996#40366996 */
background-image: url("images/background.gif");
background-color: rgba(255,255,255,0.6);
background-blend-mode: lighten;
}

View File

@ -0,0 +1,12 @@
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>

View File

@ -0,0 +1,15 @@
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
{# <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> #}
{# refactor the hardcoded URL #}
{# <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> #}
{# use URL namespace #}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

View File

@ -0,0 +1,9 @@
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

View File

@ -0,0 +1,128 @@
import datetime
from django.test import TestCase
from django.utils import timezone
from .models import Question
from django.urls import reverse
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is in the future.
"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
def test_was_published_recently_with_old_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is older than 1 day.
"""
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
old_question = Question(pub_date=time)
self.assertIs(old_question.was_published_recently(), False)
def test_was_published_recently_with_recent_question(self):
"""
was_published_recently() returns True for questions whose pub_date
is within the last day.
"""
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)
def create_question(question_text, days):
"""
Create a question with the given `question_text` and published the
given number of `days` offset to now (negative for questions published
in the past, positive for questions that have yet to be published).
"""
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)
class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
"""
If no questions exist, an appropriate message is displayed.
"""
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_past_question(self):
"""
Questions with a pub_date in the past are displayed on the
index page.
"""
create_question(question_text="Past question.", days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
def test_future_question(self):
"""
Questions with a pub_date in the future aren't displayed on
the index page.
"""
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse('polls:index'))
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_future_question_and_past_question(self):
"""
Even if both past and future questions exist, only past questions
are displayed.
"""
create_question(question_text="Past question.", days=-30)
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
def test_two_past_questions(self):
"""
The questions index page may display multiple questions.
"""
create_question(question_text="Past question 1.", days=-30)
create_question(question_text="Past question 2.", days=-5)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question 2.>', '<Question: Past question 1.>']
)
class QuestionDetailViewTests(TestCase):
def test_future_question(self):
"""
The detail view of a question with a pub_date in the future
returns a 404 not found.
"""
future_question = create_question(question_text='Future question.', days=5)
url = reverse('polls:detail', args=(future_question.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_past_question(self):
"""
The detail view of a question with a pub_date in the past
displays the question's text.
"""
past_question = create_question(question_text='Past Question.', days=-5)
url = reverse('polls:detail', args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)

View File

@ -0,0 +1,17 @@
from django.urls import path
from . import views
# namespacing URLs
app_name = 'polls'
urlpatterns = [
# ex: /polls/
#path('', views.index, name='index'),
path('', views.IndexView.as_view(), name='index'),
# ex: /polls/5/
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
# ex: /polls/5/results/
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
# ex: /polls/5/vote/
path('<int:question_id>/vote/', views.vote, name='vote'),
]

View File

@ -0,0 +1,125 @@
from django.shortcuts import get_object_or_404, render
# Create your views here.
from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
from django.http import Http404
from django.utils import timezone
## simple index
#def index(request):
# return HttpResponse("Hello, world. You're at the polls index.")
## meaningful index
#def index(request):
# latest_question_list = Question.objects.order_by('-pub_date')[:5]
# output = ', '.join([q.question_text for q in latest_question_list])
# return HttpResponse(output)
## meaningful and templated index
#def index(request):
# latest_question_list = Question.objects.order_by('-pub_date')[:5]
# template = loader.get_template('polls/index.html')
# context = {
# 'latest_question_list': latest_question_list,
# }
# return HttpResponse(template.render(context, request))
## meaningful, templated and easy to write index
## and then we no longer need to import loader and HttpResponse
#def index(request):
# latest_question_list = Question.objects.order_by('-pub_date')[:5]
# context = {
# 'latest_question_list': latest_question_list,
# }
# return render(request, 'polls/index.html', context)
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
## has bug
# def get_queryset(self):
# """Return the last five published questions."""
# return Question.objects.order_by('-pub_date')[:5]
# refactor
def get_queryset(self):
"""
Return the last five published questions (not including those set to be
published in the future).
"""
return Question.objects.filter(
pub_date__lte=timezone.now()
).order_by('-pub_date')[:5]
## simple detail
#def detail(request, question_id):
# return HttpResponse("You're looking at question %s." % question_id)
## meaningful detail
#def detail(request, question_id):
# try:
# question = Question.objects.get(pk=question_id)
# except Question.DoesNotExist:
# raise Http404("Question does not exist")
# return render(request, 'polls/detail.html', {'question': question})
## meaningful and easy to write detail
#def detail(request, question_id):
# question = get_object_or_404(Question, pk=question_id)
# return render(request, 'polls/detail.html', {'question': question})
## refactor detail view
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
def get_queryset(self):
"""
Excludes any questions that aren't published yet.
"""
return Question.objects.filter(pub_date__lte=timezone.now())
#def results(request, question_id):
# response = "You're looking at the results of question %s."
# return HttpResponse(response % question_id)
# # real implementation of results
#def results(request, question_id):
# question = get_object_or_404(Question, pk=question_id)
# return render(request, 'polls/results.html', {'question': question})
# # refactor results view
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
#def vote(request, question_id):
# return HttpResponse("You're voting on question %s." % question_id)
# #real implementation of vote
def vote (request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

View File

@ -0,0 +1,9 @@
{% extends "admin/base.html" %}
{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls
{% endblock %}
{% block nav-global %}{% endblock %}

View File

@ -0,0 +1,53 @@
import ipaddress
import argparse
# for exit codes
import sys
def proc_args():
# src https://docs.python.org/3/library/argparse.html#description
parser = argparse.ArgumentParser(description='Compare two IPs and check if they are overlapped or not')
parser.add_argument('ip1', type=str,
help='IPv6 number 1')
parser.add_argument('ip2', type=str,
help='IPv6 number 2')
args = parser.parse_args()
return args
# - Write a python script that checks whether two IPv6 networks are overlapping
# - *overlap.py ip1 ip2*
def parse_ip(ip_arg):
if('/' in ip_arg):
ip_arg = ip_arg.split('/')[0]
else:
# if no network specified, assume a netmask of /48 for all of them
ip_arg = ip_arg + '/48'
# strict false to avoid -> https://stackoverflow.com/questions/40839147/ipaddress-module-valueerrors-has-host-bits-set-self
# strict is passed to IPv4Network or IPv6Network constructor. A ValueError is
# raised if address does not represent a valid IPv4 or IPv6 address, or if
# the network has host bits set. -> src https://docs.python.org/3/library/ipaddress.html#ipaddress.ip_network
return ipaddress.IPv6Network(ip_arg, False)
def main():
is_overlap=False
args = proc_args()
try:
ip1 = parse_ip(args.ip1)
ip2 = parse_ip(args.ip2)
except:
print('incorrect IPv6 address')
# src https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Network.overlaps
is_overlap = ip1.overlaps(ip2)
if(is_overlap):
print('overlap')
sys.exit(1)
else:
print('no overlap')
sys.exit(0)
if __name__ == "__main__":
main()

32
pedro/ipv6-stuff/overlap_run.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
run_program() {
echo "args:\n ip1: ${1}\n ip2: ${2}"
printf 'output: '
python3 overlap.py ${1} ${2}
echo "exit code: $?"
echo '----------------'
}
# - Use the following test IPv6 addresses:
# - 2001:db8::
# - 2001:db8:0:2::
# - 2001:db8:1::
# - Step 2: Make your script parse ipv6 networks (like
# 2001:db8::/48 and 2001:db8::/64) ) and check whether they overlap
ip1='2001:db8::'
ip2='2001:db8:0:2::'
run_program $ip1 $ip2
ip1='2001:db8::'
ip2='2001:db8:1::'
run_program $ip1 $ip2
ip1='2001:db8:0:2::'
ip2='2001:db8:1::'
run_program $ip1 $ip2
ip1='2001:db8::/48'
ip2='2001:db8::/64'
run_program $ip1 $ip2

Binary file not shown.

21
sami/django/mysite/manage.py Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

View File

@ -0,0 +1,130 @@
"""
Django settings for mysite project.
Generated by 'django-admin startproject' using Django 2.2.12.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'p+k-n&d40pt2yi@yyq1(u%+b!b4#yloa%1ct%#jibl41x9z1b@'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = '/static/'
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

View File

@ -0,0 +1,22 @@
"""mysite URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]

View File

@ -0,0 +1,16 @@
"""
WSGI config for mysite project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_wsgi_application()

View File

View File

@ -0,0 +1,7 @@
# Register your models here.
from django.contrib import admin
from .models import Question
admin.site.register(Question)

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'

View File

@ -0,0 +1,32 @@
# Generated by Django 2.2.12 on 2020-07-03 14:26
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Question',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question_text', models.CharField(max_length=200)),
('pub_date', models.DateTimeField(verbose_name='date published')),
],
),
migrations.CreateModel(
name='Choice',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('choice_text', models.CharField(max_length=200)),
('votes', models.IntegerField(default=0)),
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question')),
],
),
]

View File

@ -0,0 +1,40 @@
from django.db import models
# Create your models here.
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
from django.db import models
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,7 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]

View File

@ -0,0 +1,17 @@
# from django.shortcuts import render
# Create your views here.
#from django.urls import path
#from . import views
#urlpatterns = [
# path('', views.index, name='index'),
#]
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")

Binary file not shown.

21
sami/django/mysite2/manage.py Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite2.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

View File

@ -0,0 +1,121 @@
"""
Django settings for mysite2 project.
Generated by 'django-admin startproject' using Django 2.2.12.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'sb1cbc!m_esjnb381eh8!+(1$zi-%$h@ewu#3=cog+ls)d%)3z'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['2a0a-e5c0-10-bee-7994-d023-5c29-7091.has-a.name']
# Application definition
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'mysite2.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mysite2.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Europe/Zurich'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = '/static/'

View File

@ -0,0 +1,23 @@
"""mysite2 URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]

View File

@ -0,0 +1,16 @@
"""
WSGI config for mysite2 project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite2.settings')
application = get_wsgi_application()

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'

View File

@ -0,0 +1,32 @@
# Generated by Django 2.2.12 on 2020-07-10 14:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Question',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question_text', models.CharField(max_length=200)),
('pub_date', models.DateTimeField(verbose_name='date published')),
],
),
migrations.CreateModel(
name='Choice',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('choice_text', models.CharField(max_length=200)),
('votes', models.IntegerField(default=0)),
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question')),
],
),
]

View File

@ -0,0 +1,28 @@
import datetime
from django.db import models
from django.utils import timezone
# Create your models here.
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
#def was_published_recently(self):
#return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text

View File

@ -0,0 +1,9 @@
{% extends "admin/base.html" %}
{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
{% endblock %}
{% block nav-global %}{% endblock %}

View File

@ -0,0 +1,13 @@
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>
p

Some files were not shown because too many files have changed in this diff Show More