BBS (Imitate Blog Park System) Project 01 (Project Analysis, Table Structure Design, Registration Function Implementation)

Keywords: C Django Database JQuery JSON

Summary:

  • requirement analysis
  • Table structure design
  • Registration function implementation

1. Demand analysis:

  • Project Requirements (Product Manager, Architect, Development Team Leader talk to customer about project related requirements)
  • Project Design (Architect needs to think about: framework selection, database selection, main function modules, quotation: including duration, developer salary...)
  • Task Distribution (Development Team Leaders meet, project tasks are split, and distributed to groups)
  • Testing (self/local testing, tester testing, white-box testing - developers, black-box testing - testers)
  • Delivery Online (Operations & Maintenance with Online)

2. Project Analysis:

Table design:

  1. User table (UserInfo)
    First, we use the Django Web framework, so the user table inherits the structure of Django's auth_user table. We customize the creation of the UserInfo table, based on the auth_user table that was automatically created by the original Django

    Add some additional fields:
    User phone BigIntegerField Type
    User Avatar FileField type (specify upload_to=', default avatar file default='avatar/xxx.jpg')
    User creation time DateField type (set time to auto_now_add=True when new records are added)
    One-to-one blog field (blog)OneToOneField(to='Blog', null=True)
    What you need to know: user users will be a little complimentary (UpAndDown), Comment, and Blog)

  2. Personal Site Table (Blog)
    Site name (blog_name) CharField type, recommended length 32
    Site Title (blog_title) CharField type, recommended length 64
    Site Style Theme (blog_theme) CharField type, store css file path, recommended length 64
    You need to know that there are tags, categories, and articles on your site blog
  3. Article Tag Table
    Label name CharField type, recommended length 32
    One-to-many relationships: Blog (one)>>Tag (many):
    blog foreign key field ForeignKey(to='Blog',null=True)
  4. Category of Articles
    Classification name CharField type, recommended length 32
    One-to-many relationships: Blog (1)>>Category (many):
    blog foreign key field ForeignKey(to='Blog',null=True)
  5. Article Table
    Article Title CharField type recommended length 64
    Article Summary (desc) CharField type Recommended length 255
    Article content TextField Type
    Article Publishing Time (create_time) DateField type (set time to auto_now_add=True when new records are added)
    # Optimize the fields created by the query:
    Number of comments (comment_num) IntegerField type
    Point Ratio (up_num) IntegerField type
    Step count (down_num) IntegerField type
    The # Article table is associated with personal site blogs, Tag Tags, categorized Categories:
    One-to-many relationships:
    Blog (1)>>Article (many): Blog foreign key field ForeignKey(to='Blog',null=True)
    Category (1)>>Article (many): Catgory foreign key field ForeignKey(to='Category',null=True)
    Many-to-many relationships: (Here we manually create the third many-to-many Association table, Article2Tag)
    Tag >>> Article: tag many-to-many foreign key fields: ManyToManyField (to='Tag', through='Article2Tag', through_fields=('article','tag'))
  6. UpAndDown
    is_up BooleanField type, 0 for step-on, 1 for favor
    Dot-and-dot stepping is associated with user table UserInfo and Article table Articles:
    One-to-many relationships:
    UserInfo (1)>>UpAndDown (many): User foreign key field ForeignKey(to='UserInfo') A user can click on more than one favorite step, one may be just one user point
    Article (1) > > UpAndDown (many): An article can be clicked with multiple approvals by using the ForeignKey(to='Article') foreign key field of user. One step or approval may correspond to one article.
  7. Comment
    Comment content CharField Type Recommended length 255
    Create_time DateField type (set time to auto_now_add=True when adding new records)
    The comment table is associated with the user table UserInfo, the article table Article:
    One-to-many relationships:
    UserInfo (1)>>Comment: user foreign key field ForeignKey(to='UserInfo') One user can post multiple comments, one comment may only be published by one user
    Article (1)>>Comment: user foreign key field ForeignKey(to='Article') An article can have multiple comments, one comment may only correspond to one article
    parent ForeignKey Type ForeignKey(to='self') This is a special one that relates to itself

    Summary: Direct relationship diagram of BBS table:

Registration function implementation:

  1. Configuration environment:
    setting.py file
    1,Set Static File
    2,tell Django,Customize Create User Table
    3,Use MySQL Database, configure database parameters
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static'),
        os.path.join(BASE_DIR, 'app01/static')
    ]
    
    AUTH_USER_MODEL = 'app01.UserInfo'
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'bbs01',
            'HOST': '127.0.0.1',
            'PORT': 3306,
            'USER': 'root',
            'PASSWORD': '123'
        }
    }  
    # Note that in the init file:

     

      import pymysql
      pymysql.install_as_MySQLdb()

     

  2. Configure Django's form-related data:
    Create a new folder myform under the app01 folder, and then create a new myform.py file under this file, which is:
    from django import forms
    from app01 import models
    
    # Establish Django Of form form
    class MyForm(forms.Form):
        username = forms.CharField(
            max_length=8,
            min_length=3,
            label='User name:',
            error_messages={
                'required': 'User name cannot be empty',
                'max_length': 'Maximum username size is 8 bits',
                'min_length': 'Minimum 3-digit user name',
            },
            widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
        )
    
        password = forms.CharField(
            max_length=8,
            min_length=3,
            label='Password:',
            error_messages={
                'required': 'Password cannot be empty',
                'max_length': 'Maximum password 8 bits',
                'min_length': 'Minimum password 3 bits',
            },
            widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
        )
    
        confirm_password = forms.CharField(
            max_length=8,
            min_length=3,
            label='Confirm Password:',
            error_messages={
                'required': 'Confirmation password cannot be empty',
                'max_length': 'Confirm password up to 8 bits',
                'min_length': 'Confirm password minimum 3 bits',
            },
            widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
        )
    
        email = forms.EmailField(
            label='mailbox:',
            error_messages={
                'required': 'Mailbox cannot be empty',
                'invalid': 'Mailbox format error'
            },
            widget=forms.widgets.EmailInput(attrs={'class': 'form-control'})
        )
    
        # User names and passwords are checked twice using local and global hooks:
        # Global hook checks if password input is consistent:
        def clean(self):
            password = self.cleaned_data.get('password')
            confirm_password = self.cleaned_data.get('confirm_password')
            if password != confirm_password:
                self.add_error('confirm_password', 'Passwords do not match when entered twice')
            return self.cleaned_data  # Remember to return
    
        # Local hook checks if the user name exists:
        def clean_username(self):
            username = self.cleaned_data.get('username')
            user_obj = models.UserInfo.objects.filter(username=username).first()
            if user_obj:
                self.add_error('username', 'User name already exists')
            return username   # Remember to return
  3. Create orm mapping table relational model data for Django in model.py file of project app01:
    models.py, create tables (if you need to create a database first (bbs01))
    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    # Create your models here.
    class UserInfo(AbstractUser):
        phone = models.BigIntegerField(null=True)
        create_time = models.DateField(auto_now_add=True)
        blog = models.OneToOneField(to='Blog', null=True)
        avatar = models.FileField(upload_to='avatar/', default='avatar/default_avatar.jpg')
    
    
    class Blog(models.Model):
        blog_name = models.CharField(max_length=32)
        blog_title = models.CharField(max_length=64)
        blog_theme = models.CharField(max_length=64)
    
    
    class Article(models.Model):
        title = models.CharField(max_length=64)
        content = models.TextField()
        desc = models.CharField(max_length=255)
        create_time = models.DateField(auto_now_add=True)
        blog = models.ForeignKey(to='Blog', null=True)
        category = models.ForeignKey(to='Category', null=True)
        tag = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag'))
        # Optimize Query
        comment_num = models.IntegerField()
        up_num = models.IntegerField()
        down_num = models.IntegerField()
    
    class Category(models.Model):
        name = models.CharField(max_length=32)
        blog = models.ForeignKey(to='Blog', null=True)
    
    class Article2Tag(models.Model):
        article = models.ForeignKey(to='Article')
        tag = models.ForeignKey(to='Tag')
    
    class Tag(models.Model):
        name = models.CharField(max_length=32)
        blog = models.ForeignKey(to='Blog', null=True)
    
    class UpAndDown(models.Model):
        is_up = models.BooleanField()
        user = models.ForeignKey(to='UserInfo')
        article = models.ForeignKey(to='Article')
    
    class Comment(models.Model):
        content = models.CharField(max_length=255)
        create_time = models.DateField(auto_now_add=True)
        user = models.ForeignKey(to='UserInfo')
        article = models.ForeignKey(to='Article')
        parent = models.ForeignKey(to='self', null=True)
    4. Configure routes, view functions, front-end register.html creation
    In ## urls.py:
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^register/', views.register)
    ]

    ## register.html file creation:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    {#    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>#}
        <script src="/static/jQuery-3.4.1.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <link rel="stylesheet" href="/static/reg.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h2 class="text-center">Registration Page</h2>
                <hr>
    {#          Note: Use here form The purpose of the form is that we need to pass form Batch processing of data objects entered in a form#}
                <form id="myform">
                    {% csrf_token %}
                    {% for form in form_obj %}
    {#                  By input Box jackets div,Set up div Of class Contain form-group,#}
    {#                  Can pass bootstrap Style to adjust input Spacing between boxes#}
                        <div class="form-group">
                            <label for="{{ form.auto_id }}">{{ form.label }}</label>
                            {{ form }}
                            <span class="has-error pull-right"></span>
                        </div>
                    {% endfor %}
                </form>
                    <div class="form-group">
                        <label for="id_myfile">
                            <img id="id_avatar" src="/static/avatar/default_avatar.jpg" width="70" class="img-thumbnail">
                        </label>
                        //Click on the picture to upload the Avatar
                        <input type="file" id="id_myfile" name="myfile" class="hide">
                    </div>
                    <button class="btn btn-primary pull-right" id="id_submit">Submit registration</button>
            </div>
        </div>
    </div>
    
    <script>
        // Render user-uploaded picture files to the page display instantly
        $('#id_myfile').on('change',function () {
            // Get Upload File Object
            let file_obj = this.files[0];
            // Generate a built-in object
            let fileReader = new FileReader();
            // Pass file objects to built-in objects
            fileReader.readAsDataURL(file_obj);
            // Replace the read file object with img Label
            // Because rendering pictures is much faster than reading files with a file reader
            // So, you need to use onload Method Wait for the file reader to finish reading before rendering the picture
            fileReader.onload = function () {
                $('#id_avatar').attr('src', fileReader.result)
            }
        })
        // adopt ajax Send Request,Submit data
        $('#id_submit').on('click',function () {
            // ajax Can't transfer file by itself, need help from built-in object FormData Transfer Files
            // Declare a formData Object, formData Objects can transfer both files and normal keys through append Way to add
            let formData = new FormData();
            // jQuery Object Method each Method:
            // Will pass $('#The json-formatted array of objects obtained by the myform').serializeArray() method traverses each of its key-value pairs
            // Each key-value pair traversed is treated as a function. function()In index Is a traversed index of key-value pairs,
            // obj Is the traversed key-value pair(Here it is form Inside Form input Box name And filled in value)
            $.each(
                // adopt serializeArray() Method serialization form Form value to create object array(Name and Value),This method returns a json object
                // Returned JSON An object is an array of objects, where each object contains a key-value pair name and value
                $('#myform').serializeArray(),
                function (index, obj) {formData.append(obj.name,obj.value);}
                // 1 {name: "username", value: "sgt"} Corresponding index and obj
                ); // function The function that will be traversed json Data Pass Point name And Point value Get the corresponding key value to add in formData in
    
            // Normal key value(input Key values filled in by boxes)Once added, add file data to formData in
            formData.append('myfile', $('#id_myfile')[0].files[0]);
            $.ajax({
                url: '', // Do not write default current page route submission
                type: 'post', // post Submission Method
                data: formData, // To transfer data and files, you have to use built-in objects formData Send Request
                processData: false, // Tell the browser not to do anything with the data
                contentType: false, // No encoding, formData data object Django Backend is recognizable
                // Next
                success:function (data) {
                    // Registration successful, jump to the specified page from the back end
                    if (data.code==100) {location.replace(data.url)}
                    // Registration failed, rendering the front end with hints from the back end that the check was unsuccessful
                    // One thing to note here is: Django Of form When the form is rendered on the front end, each input Box id Name follows law
                    // Define names, like this: id_username,id_password
                    else {
                        $.each(
                            data.msg,
                            function (index, obj) {
                                // Be careful: index obj Namely: username ["Minimum 3-digit user name"]
                                // Unlike the above method, this is to use a dictionary each Method, which uses the array above each Method
                                let targetId = '#id_'+index;  // Stitch out input Box id name
                                // Each field name traversed, matched by the stitching above input Box corresponding id Name, through this
                                // id The name will find it, underneath it (via next()Method) is what we need to do span Label
                                // Add it html text(Is the error message, note obj Is a list),Continue chain operation at the same time
                                // Make a mistake input Red box, warning prompt, pass parent()Method finds parent label div,Put it in
                                // class Join one has-error That's it.
                                $(targetId).next().html(obj[0]).parent().addClass('has-error')
                            }
                        )
                    }
                }
    
            })
        });
        // Pass above ajax Send out post The request for registration is almost complete, and finally the rendering of error information is implemented, which needs to be improved
        // If a user registers with an error prompt and continues to register, he or she will need to clear the error prompt again, so:
        $('input').on('focus',function () {
            $(this).next().html('').parent().removeClass('has-error')
            // The method is similar to adding an error message above and finds input Below the box span Label, put her html Empty, go and remove the red tips
            // Continue to find its parent tag at the same time div Remove class Inside has-error,Red box prompts cancel
        })
    </script>
    </body>
    </html>

    ## views.py view function

    from django.shortcuts import render,HttpResponse,redirect
    from app01.myform.myform import MyForm
    from app01 import models
    from django.http import JsonResponse
    
    # Create your views here.
    def register(request):
        form_obj = MyForm()
        # Define a response dictionary first, then register the request to use when returning
        back_dic = {'code': 100, 'msg': ''}
        if request.method == 'POST':
            # take register Common data for page submissions is retrieved and discarded to MyForm(),item base form_obj
            form_obj = MyForm(request.POST)
            # adopt form_obj obtain Django Automatically verify submission form processing results
            if form_obj.is_valid():
                # Verification Passed,Get all key value data dictionaries passed
                data = form_obj.cleaned_data
                # Note here that there is one in the dictionary confirm_password The key value, which is not required after the check passes
                # So it needs to be removed:
                data.pop('confirm_password')
                # Get the user's uploaded avatar file object
                file_obj = request.FILES.get('myfile')
                # You need to add a layer of judgment here to see if the user has uploaded a avatar file on the front end or is using the default Avatar
                # Add when passed data,Add data directly without passing
                if file_obj:
                    # User uploaded avatar file,to data Add key value of avatar file to
                    data['avatar'] = file_obj
                    # Be careful to use create_user Can create user data normally
                    # data Is a dictionary key-value pair that directly scatters incoming data. perfect!
                models.UserInfo.objects.create_user(**data)
                back_dic['msg'] = 'login was successful'
                # Add page routes that jump after successful registration to the corresponding data dictionary
                back_dic['urs'] = '/login/'
            # Verification failed, registration unsuccessful
            else:
                back_dic['code'] = 101  # Failed to register on behalf of 101
                # Pass in a dictionary of information that failed validation, wait for front-end rendering to prompt user registration failure
                back_dic['msg'] = form_obj.errors
            return JsonResponse(back_dic)
        return render(request, 'register.html', locals())

     



Posted by mpharo on Wed, 19 Jun 2019 09:59:31 -0700