Application development of raspberry school intelligent classroom
WEB programming operation 2
Development using Django framework and jQuery
Technical point
Django's project structure, advantages, disadvantages and positioning
Syntax of Django web page template
Django's built-in CSRF middleware and the principle of defending against network attacks
Syntax of Django built-in ORM model
How to use Session in the request to complete user login and user identification in Django
Django development process
Design project structure and generate project
The Django admin command generates the Django project folder and manually adds the required files
The Django admin instruction generates a sub application directory
Write Django web page template to define the relationship between web page links and windows
Write views Py and URLs Py content
Write a web page template in templates
Write database ORM model
Set engine for ORM model
Use manage Py migrate model to database application
Deploy to production environment
Generate Django project folder (development process)
First, use {pip install django} to install django and its dependent libraries
The second step is to build the project scaffold
Select a folder as the parent folder of the project folder
The command line {CD < file path >} enters the folder
{Django adminstartproject < project name >}
The third step is to establish sub applications
The command line {CD < file path >} goes to the project folder
{Django admin startapp < sub app name >}
In settings Py, find {installed_apps = [< some strings >]}, and add the sub application name just created as the element in it
Final generated directory:
The project name is Rasp_Server
The sub application is db, and the content is not shown
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-tB9Vttot-1625216482606)(C:/Users/YangTianJi/Desktop/images/image-20210702154104963.png)]
Django's project structure, advantages, disadvantages and positioning (technical points)
Project structure: MVC(Model View Controller) separated mode
- M: Model
- The business model uses the built-in < ORM model >
- V: View
- Via < views Py > defines the jump between windows and inputs data to them
- < web page templates > finish rendering (can be used in combination with the front-end framework)
- C: Controller
- Via < URL Py > defines which URLs will be assigned to which windows
- Deliver < static file > through a dedicated static file route. Note that the concept of static file here is not the same as that of static web page
Runtime: synchronous single thread
- The built-in runserver instruction has poor concurrency and is easy to lose response when IO is intensive
- This problem can be alleviated by using multi-threaded Web services (uwsgi, nginx) when deploying the server
Safety: good
- A variety of authentication methods are built in, and cross domain access is restricted to prevent related attacks
Django is not a server development framework, but a back-end Web application development framework
- The development process adopts the separation of network services and back-end application development
- Specializing in the generation of static high-capacity web pages and data blocks, and delivering dynamic web pages to the front end
Syntax of Django web page template (technical points)
Django web page template is directly rendered in the back-end server
To the front end is the complete web page (or some components in the web page) with replaced data
Because the replacement is executed directly through python script, it is very fast
The code that the backend inserts data into it:
from django.shortcuts import * #'*' indicates the components in all shortcuts def send_fakestudentlist(req, *args, **kwargs): if req.method != "GET": return HttpResponse("") context = {} def fakestudent(i): x = object() x.id = i x.name = "".join(random.sample("abcdefg"), 10) return x context["students"] = [fakestudent(i) for i in range(0, 100)] context["classid"] = 1 return render(req, "fakestudentlist.html", context)
Page template section:
<table id="studentlist"> {% for item in students %} <tr><td> <span class="'{{item.id}}'"> {{item.name}} </span> </td></tr> {% endfor %} </table> <script> var whichclass = "'{{classid}}'"; </script>
Write Django web page template (development process)
Create a new folder {templates} under the project folder (used to store template web pages)
Open a folder with the same name as the project name under the project folder and create a new file {views.py} (used to arrange windows and data)
Create a new folder {static} (used to store static files such as pictures and javascript scripts) under the project folder
Under the project folder, click settings Py, find the TEMPLATES item in {import os}, and modify the DIRS item in the TEMPLATES item. The results are shown in the following page
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", ], }, }, ]
Static routing configuration
Because of the equipment problem of raspberry pie, static routing needs some detailed operations
STATIC_URL = "/static/" STATIC_ROOT = os.path.join(BASE_DIR, "static") STATICFILES_DIRS = ( ("", os.path.join(STATIC_ROOT, "").replace("\\", "/")), )
CSRF attack and Django's defense scheme (technical point)
Full name of CSRF: cross site request Forge
- Students participating in the CTF competition call it a fake click event (or 'one sentence Trojan horse')
General principle: attack the website by falsely using the user's session information
- Http protocol is a very simple data transmission protocol (without identity tag), so any user state and operation context need to be stored by the browser, which is the so-called cookie
- session: the user information stored in the browser (actually part of the cookie) is used to tell the server which user this is
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-4Lj3bqk9-1625216482608)(C:/Users/YangTianJi/Desktop/images/image-20210702155024875.png)]
Defense method: homology strategy
- Only the cookies in the web pages sent by the server are allowed to POST requests to the server, so the cookies embedded in external web pages cannot be modified to the server
- How to distinguish whether a web page request is sent by the same web page?
- The server randomly generates a password (token), but the external web page cannot obtain the password (in fact, it can be obtained through XSS vulnerability). Therefore, for the user, the request sent by the user can be processed only if the token is included in the cookie
- A more advanced strategy is to generate a new token every time a request is sent, and then judge whether the user's next request is legal through this token In fact, this implementation is quite difficult, because when users browse the same site on multiple web pages, if they return to this page after sending POST requests on other pages, the token has actually changed, and the user's POST method of using this page will be regarded as illegal, which will seriously affect the user's access experience
Use Django middleware. csrf. CsrfViewMiddleware
Django has built-in middleware:
- django.middleware.csrf.CsrfViewMiddleware
- The middleware will automatically find the CSRF contained in the requested cookie_ Token and verify it
When making a POST request to a server built using the Django framework, you need to use CSRF_ There are two business scenarios for token:
- The first one: POST request by form submission
- Second: POST request using XHR (jQuery encapsulates XHR request in $. ajax method)
- Other parts have been quite automated, and these can be taken as considerations in development, rather than requiring particularly skilled technical points
POST request by form submission:
Just include one between the two form tags
{% csrf_token %}
, when Django renders a web page, it will automatically generate a token through the middleware as
<input type='hidden' name='csrf_token'>
It is automatically placed in the form, and the middleware will automatically verify the token when submitting
In other words, as an application developer, the only thing you need to do is add a line of code
POST request using XHR
In $ ajax method is a typical example. It should be noted that Django's defense scheme does not dynamically generate tokens, so once the user logs in, the CSRF in the cookie will be deleted_ The token will not change
Set all ajax requests on this page to csrf_token:
Get token with {% csrf_token%}
Use $ ajaxSetup set token
function csrfSafeMethod(method) { return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", '{{ csrf_token }}'); } } });
Database object oriented: ORM
Object relational mapping: Object Relational Mapping
Its function is to make a mapping between relational database and objects, so that when we operate the database, we don't need to deal with complex SQL statements, as long as we operate it as usual
The syntax (table creation) of ORM in django writes a declaration under the models file of the sub application:
from django.db import models from django.core.validators import * import random # Create your models here. class UserInfo(models.Model): username = models.CharField(max_length=30, unique=True) password = models.CharField(max_length=50) usertype = models.CharField( max_length=1, choices=(("t", "teacher"), ("s", "student")) ) files = models.CharField( validators=[validate_comma_separated_integer_list], max_length=1000, default="0," ) class Classrooms(models.Model): teacher = models.CharField( validators=[validate_comma_separated_integer_list], max_length=1000, default="0," ) student = models.CharField( validators=[validate_comma_separated_integer_list], max_length=1000, default="0," ) file = models.CharField( validators=[validate_comma_separated_integer_list], max_length=1000, default="0," ) question = models.CharField( validators=[validate_comma_separated_integer_list], max_length=1000, default="0," ) waitlist = models.CharField( validators=[validate_comma_separated_integer_list], max_length=1000, default="0," ) name = models.CharField(max_length=50) class Files(models.Model): name = models.CharField(max_length=50) class Questions(models.Model): title = models.CharField(max_length=50) stem = models.CharField(max_length=1000) choice = models.CharField( validators=[validate_comma_separated_integer_list], max_length=1000, default="0," ) class Text(models.Model): chars = models.CharField(max_length=1000) count = models.IntegerField(max_length=100, default=0) ok = models.IntegerField(max_length=1, default=0) class Recommend(models.Model): code = models.CharField( max_length=35, default="".join(random.sample("abcdefghijklmnopqrstuvwxyz1234567890", 35)), ) count = models.IntegerField(default=100)
Because there are no foreign keys in sqlite, some statements are annoying to process.
Execute under home directory
python manage.py makemigrations <Sub application name> python manage.py migrate
Migrate the model to the database engine
Using Echarts
<div id="container" style="height: 700px; width: 700px; margin: auto;"></div> <script src="/static/script/echarts.min.js"></script> <script type="text/javascript"> var dom = document.getElementById("container"); var myChart = echarts.init(dom); var app = {}; var option; var data = []; '{% for x in choice %}' data.push({ value: '{{x.count}}', name: '{{x.chars}}' }); '{% endfor %}' option = { legend: { top: 'bottom' }, toolbox: { show: true, feature: { mark: { show: true }, dataView: { show: true, readOnly: false }, restore: { show: true }, saveAsImage: { show: true } } }, series: [{ name: '{{name}}', type: 'pie', radius: [50, 250], center: ['50%', '50%'], roseType: 'area', itemStyle: { borderRadius: 8 }, data: data, }] }; if (option && typeof option === 'object') { myChart.setOption(option); } </script>
Echarts is a very convenient js plug-in, especially when used in combination with Django (especially when opening in a new web page), it can put data in almost without additional code.
Write Classroom web page template
There is only a little difference between teachers and students here. You only need to enclose the question setting and answer functions with if tags.
<html> <head> <link rel="stylesheet" type="text/css" href="/static/css/classroom.css"> <link rel="stylesheet" type="text/css" href="/static/css/navball.css"> <script src="/static/script/jquery-3.6.0.min.js"></script> <script src="/static/script/setajaxcsrf.js"></script> </head> <body> <div id=questionbox> <input type=text class=box1 name=quesname placeholder=Title> <textarea type=text name=stem class=box3 placeholder=stem></textarea> <div id=addchoice class=box2 οnclick=addchoice();>Add options</div> <div id=submit class=box2 οnclick=sumbitquestion();>Upload title</div> </div> <h1>classroom {{ classroom.name }}</h1> <div class=classroom> <h2>List of students to be reviewed</h2> <div> {% for item in waitlist %} {% if item %} <div class=ho> <span class=see> {{item}} </span> <span class=hi οnclick="removewai($(this).parent()[0], '{{item.id}}')">remove</span> <span class=hi οnclick="admitwai($(this).parent()[0], '{{item.id}}') ">adopt</span> </div> {% endif %} {% endfor %} </div> <h2>Student list</h2> <div id=studentlist> {% for item in student %} {% if item %} <div class=ho> <span class=see> {{item.username}} </span> <span class=hi οnclick="remove($(this).parent()[0], '{{item.id}}', 'student') ">remove</span> </div> {% endif %} {% endfor %} </div> <h2>Teacher list</h2> <div id=teacherlist> {% for item in teacher %} {% if item %} <div class=ho> <span class=see> {{item.username}} </span> </div> {% endif %} {% endfor %} </div> <h2>Problem list</h2> <div id=questionlist> {% for item in question %} {% if item %} <div class=ho> <span class=see> {{item.title}} </span> <span class=hi οnclick="remove($(this).parent()[0],'{{item.id}}','question')">remove</span> <span class=hi οnclick="gosee('{{item.id}}')">Answer situation</span> </div> {% endif %} {% endfor %} </div> <h2>Public documents</h2> <div id=filelist> {% for item in file %} {% if item %} <div class=ho> <span class=see> {{item.name}} </span> {% if usertype == 'teacher' or usertype == 't' %} <span class=hi οnclick="remove($(this).parent()[0],'{{item.id}}','file')">remove</span> {% endif %} <span class=hi οnclick="downloadfile('{{item.id}}');">download</span> </div> {% endif %} {% endfor %} </div> <h2>My files</h2> <div id=privatefilelist> {% for item in privatefile %} {% if item %} <div class=ho> <span class=see> {{item.name}} </span> {% if usertype == 'teacher' or usertype == 't' %} <span class=hi>{{item.id}}</span> <span class=hi οnclick="publicize('{{item.id}}',$(this).parent()[0])">upload</span> {% endif %} </div> {% endif %} {% endfor %} </div> </div> {% include "navball.html " with usertype='teacher' %} <script> // Handle issues related to the project var usertype = '{{ usertype }}'; const question = () => { if ($("#questionbox").css("display ") == "none ") $("#questionbox").css("display ", "block "); else $("#questionbox").css("display ", "none "); } var choicecount = 0; const addchoice = () => { $("#addchoice ").before( '<input type=text class=box4 placeholder=option' + ++choicecount + ' name=choice' + choicecount + '>' + '<div class=box2 οnclick=booold(this) id=' + choicecount + '>correct</div>' ); } const booold = (_this) => $(_this).text() == "correct" ? $(_this).text("error") : $(_this).text("correct"); const sumbitquestion = () => { var _data = { stem: $("[name=stem]").val(), name: $("[name=quesname]").val() } for (let x = 1;; x++) { if ($("[name=choice" + x + "]")[0]) _data["choice" + x] = $("[name=choice" + x + "]").val(); else break; if ($("#" + x)[0] && $("#"+ x).text() = =" correct ") _data[x] = 1; } $.ajax({ method: "POST", url: location.origin + "/uploadquestion/", data: _data, success: (data) => { if (data == '1' || data == 1) { $("#Questionbox "). Replacewith ('< div id =" questionbox "> < input type =" text "class =" box1 "name =" quesname "placeholder =" topic name "> < textarea type =" text "name =" stem "class =" box3 "placeholder =" topic stem "> < / textarea > < div id =" addchoice "class =" box2“ ο nclick="addchoice();"> Add option < / div > < div id = "submit" class = "box2" ο nclick="sumbitquestion();"> Upload the title < / div > < / div > '; $("#questionlist").append('<div class="ho"><span class="see">' + _data.name + '</span><span class="hi " ο Nclick = "removequestion" > remove < / span > < span class = "Hi" ο Nclick = "go (this)" > answer < / span > < / div >); } } }) } $("#questionbox ").on("mousedown ", (eve) => { var elem = $("#questionbox ")[0]; const dX = eve.clientX - elem.offsetLeft; const dY = eve.clientY - elem.offsetTop; const trackmousemove = (eve) => { $(document).on("mouseup ", () => $(document).unbind("mousemove ")); elem.style.left = eve.clientX - dX + 'px'; elem.style.top = eve.clientY - dY + 'px'; } $(document).on("mousemove ", trackmousemove); }) // Deal with matters related to students' participation and withdrawal const admitwai = (_thisp, _id) => { $(_thisp).css("colour ", "gray "); $.post(location.origin + "/admit/ ", { who: _id, }, () => { $(_thisp).remove(); }) } const removewai = (_thisp, _id) => { $(_thisp).css("colour", "gray"); $.post(location.origin + "/reject/ ", { who: _id, }, () => { $(_thisp).remove(); }) } const publicize = (_id, _thisp) => { console.log(_id); $(_thisp).css("colour", "gray"); $.post(location.origin + "/publicize/ ", { which: _id, }, () => { $("#filelist").append('<div class="ho"><span class="see">' + _id + '</span><span class="hi " ο Nclick = "remove ($(this). Parent() [0], '+ _id +', '+' 'file'" + ') "> remove < / span > < span class =" Hi " ο nclick="downloadfile( ' + _id + '); "> Download < / span > ') }) } const remove = (_thisp, _id, _what) => { $(_thisp).css("colour ", "gray "); $.post(location.origin + "/remove/" + _what + "/ ", { which: _id, }, () => { $(_thisp).remove(); }) } '{% if usertype == "s" or usertype == "student" %}' const mark = (_thisp, _id) => { $(_thisp).css("colour", "gray"); $.post(location.origin + "/mark/ " + _what + "/ ", { which: _id, }, () => { $(_thisp).remove(); }) } '{% endif %}' const gosee = (_id) => { location.href = location.origin + "/questionstatus/" + _id; } </script> </body> </html>
Deployment issues
First, the most important thing is to delete all pythcache and migrations folders, and then type all makemigration s again.
Then you can run the project on raspberry pie by setting django with pip.
Set boot in config file.
Achievement display
Screenshot of teacher interface 1
Screenshot 2 of teacher interface (this navigation bar can be dragged around)
When the mouse is not placed on it, it will turn into a ball (Huhu)
Click upload file to upload the file
(the database file name is a little short by my card, and the name is too long to be transmitted, so I transmitted it to vpn...) bad
Click the line above to enter the classroom interface
Teachers can click upload to add the files in "My Files" to the public files, and students can access the public files in teachers and download them.
Add Buddha jumping wall to public file...
Then the function of making questions is also realized in the classroom interface. The classroom makes questions through the question box in the upper left corner (at present, there are only multiple-choice questions).
(this thing can also be dragged around, and the mouse focus will be enlarged
Click Add option to add an option, and click "correct" and "error" to switch whether the option is right or wrong
Students can apply to enter the classroom interface in the main interface (when the mouse is placed on the login button, it will split into two options)
The main interface of the student user is different from that of the teacher, such as the content displayed by the ball
(the teacher column in the classroom is full of test users, and the database is not deleted completely
Students fill in the classroom id in the application to join box, and click unfocus to submit automatically.
Students can download public files or upload their own files as an online disk (others in the same classroom can't see it).
Move the mouse to this line and click the download button to download.
Students can also do questions by clicking on the questions in the question list (but it won't tell you right or wrong, and the teacher only knows how many candidates there are for each option)
The teacher answers the question by clicking on the question in the question list (but it does not support deleting the question)
In short, further style settings have not been made, but the basic requirements have been realized.
over~~~~
style="zoom:50%;" />
(the teacher column in the classroom is full of test users, and the database is not deleted completely
Students fill in the classroom id in the application to join box, and click unfocus to submit automatically.
Students can download public files or upload their own files as an online disk (others in the same classroom can't see it).
Move the mouse to this line and click the download button to download.
Students can also do questions by clicking on the questions in the question list (but it won't tell you right or wrong, and the teacher only knows how many candidates there are for each option)
The teacher answers the question by clicking on the question in the question list (but it does not support deleting the question)
In short, further style settings have not been made, but the basic requirements have been realized.
over~~~~