Today I Learnd 2024-03-15T09:17:23+08:00 jiang.haiyun#gmail.com Wechat mini program basic structure 2024-03-13T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/wechat__Wechat_mini_program_basic_structure Project config file project.config.json

Put project settings such as appid.

App global config file app.json

Include all page pathes and navigation bar style:

{
	"pages": [
		"pages/index/index",
		"pages/logs/logs"
	],
	"window": {
		"navigationBarTitleText": "WeChat"
	}
}

App global style file app.wxss

Same as CSS file.

Define the app logic with App() in the app.js file

App({
	onLaunch: function(){},
	onShow: function(options){},
	onHide: function(){},
	globalData: {
		userInfo: null,
		myData: {}
	}
})

Page files

Every page constitutes of 3 files, js file, wxml file and wxss file, corresponds to js file, html file and css file.

Define page logic with Page() in pages’s js file

Define data and event handlers in js file:

// pages/index/index.js
Page({
    data: { msg: 'Hello' }, // Page initial data
	myData: '123',
	onLoad: function(options){},
	handleBtnTap: function() {},
	changeData: function(){
		this.setData({today: '2024-03-13'})
	}
})

wxml file

Page object’s data value is available in wxml file:

<view></view>

We can bind event handler to a component with bind<evnet>

<button bindtap="handleBtnTap">..</button>

Refresh with setData()

Just like React’s setData or setState, setData() will update the Page’s data and then will trigger a page refresh. See changeData().

]]>
Wechat mini-program statistic tools 2024-03-13T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/tools__Wechat_mini-program_statistic_tools TalkingData, 友盟, App Annie GrowingIO

]]>
Event.target vs Event.currentTarget in Javascript 2024-03-13T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/javascript__Event.target_vs_Event.currentTarget_in_Javascript
  • target: refers to the element that triggered the event
  • currentTarget: refers to the element that the event handler/listener is attached to.
  • Example one, target and currentTarget are not the same

    <div id="target">
        <span>click me</span>
    </div>
    
    const elem = document.getElementById('target'); // div
    
    elem.addEventListener('click', function (event) {
        console.log(event.target); // span
        console.log(event.currentTarget); // div
    });
    

    Example two, target and currentTarget are the same

    <div>
        <span id="target">click me</span>
    </div>
    
    const elem = document.getElementById('target'); // span
    
    elem.addEventListener('click', function (event) {
        console.log(event.target); // span
        console.log(event.currentTarget); // span
    });
    
    ]]>
    Install wechat min program development environment on Ubuntu 2024-03-11T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/wechat__Install_wechat_min_program_development_environment_on_Ubuntu Build with docker

    Install wine and wine-binfmt

    sudo apt-get update
    sudo apt-get install wine wine-binfmt
    

    Install docker and docker-compose

    sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose
    

    See https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-20-04

    Clone

    $ git clone --recurse-submodules https://github.com/msojocs/wechat-web-devtools-linux.git
    

    Build with docker-compse

    sudo docker-compose up
    

    Install icon

    ./tools/install-desktop-icon-node
    

    Usage

    Start with command bin/wechat-devtools. Or just click the icon

    See https://github.com/msojocs/wechat-web-devtools-linux

    ]]>
    default, auto_now, auto_now_add in Django DateTimeField 2024-03-07T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/django__default,_auto_now,_auto_now_add_in_Django_DateTimeField
  • published: default: Similar to auto_now_add, the current date and time will be saved as the default value when creating an object, and we can update the value in the future.
  • created: auto_now_add: the current date and time will be saved automatically when creating an object, this makes the field non-editable, we can’t change the value in the future.
  • updated: auto_now: the current date and time will be saved automatically when saving an object, this makes the field non-editable, we can’t change the value manually.
  • from django.db import models
    from django.utils import timezone
    
    class Post(models.Model):
        title = models.CharField(max_length=250)
        slug = models.SlugField(max_length=250)
        body = models.TextField()
        published = models.DateTimeField(default=timezone.now)
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
    
        class Meta:
            ordering = ['-publish']
    
        def __str__(self):
            return self.title
    
    ]]>
    Define model field choices with enumeration class such as TextChoices and IntegerChoices in Django 2024-03-07T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/django__Define_model_field_choices_with_enumeration_class_such_as_TextChoices_and_IntegerChoices_in_Django Django provides enumeration types that we can subclass to define choices simply. See https://docs.djangoproject.com/en/4.1/ref/models/fields/#enumeration-types.

    Subclass models.TextChoices to create choices that work with models.TextField, and subclass models.IntegerChoices to create choices that work with models.IntegerField.

    from django.db import models
    from django.utils import timezone
    
    class Post(models.Model):
    
        class Status(models.TextChoices):
            DRAFT = ('DF', 'Draft')
            PUBLISHED = ('PB', 'Published')
    
        title = models.CharField(max_length=250)
        slug = models.SlugField(max_length=250)
        body = models.TextField()
        publish = models.DateTimeField(default=timezone.now)
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
        status = models.CharField(max_length=2, choices=Status.choices, default=Status.DRAFT)
    
        class Meta:
            ordering = ['-publish']
            indexes = [
                models.Index(fields=['-publish'])
            ]
    
        def __str__(self):
            return self.title
    

    We can access Post.Status.choices to obtain the available choices, Post.Status.labels to obtain the hunam-readable names, and Post.Status.valus to obtain the actual values of the choices.

    (InteractiveConsole)
    >>> from blog.models import Post
    >>> Post.Status
    <enum 'Status'>
    >>> Post.Status.choices
    [('DF', 'Draft'), ('PB', 'Published')]
    >>> Post.Status.values
    ['DF', 'PB']
    >>> Post.Status.names
    ['DRAFT', 'PUBLISHED']
    >>> Post.Status.labels
    ['Draft', 'Published']
    >>> Post.Status.DRAFT
    Post.Status.DRAFT
    >>> str(Post.Status.DRAFT)
    'DF'
    
    ]]>
    Define default sort order and database index in Django 2024-03-07T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/django__Define_default_sort_order_and_database_index_in_Django Create a default sort order in Meta.ordering

    The default order will apply when no order is specified in the query.

    Add a database index

    Define a database index for the default sort field will improve performance for queries filtering or ordering results by this field.

    We add the index in Meta.indexes, a index could comprise one or multiple fields, in ascending or descending order.

    from django.db import models
    from django.utils import timezone
    
    class Post(models.Model):
        title = models.CharField(max_length=250)
        slug = models.SlugField(max_length=250)
        body = models.TextField()
        publish = models.DateTimeField(default=timezone.now)
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
    
        class Meta:
            ordering = ['-publish']
    		indexes = [
    			models.Index(fields=['-publish']),
    		]
        def __str__(self):
            return self.title
    
    ]]>
    One-to-one, one-to-many, many-to-many relationship in Database 2024-03-07T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/db__One-to-one,_one-to-many,_many-to-many_relationship_in_Database One-to-one relation

    One record of the first table will be linked to zero or one record of another table. For example, each employee in the Employee table will have a corresponding row in EmployeeDetails table.

    Employee          EmployeeDetails
      EmployeeID         EmployeeID
      Name,...           Detail,...
    

    Each employee has none or just one corresponding record in EmployeeDetails.

    One-to-many relation

    One-to-many is the most commonly used relationship among tables. A single record from one table can be linked to zero or more rows in another table.

    For example, each employee has zero or more records of address.

    The Employee and Address tables are linked by the key column EmployeeID. It is a foreign key in the Address table linking to the primary key EmployeeID in the Employee table. Thus, one record of the Employee table can point to multiple records in the Address table. This is a One-to-Many relationship.

    Employee          Address
      EmployeeID         ForeignKey(EmployeeID)
      Name,...           Detail,...
    

    Many-to-many relation

    Many-to-Many relationship lets us relate each row in one table to many rows in another table and vice versa.

    As an example, an employee in the Employee table can have many skills from the EmployeeSkill table and also, one skill can be associated with one or more employees.

    Employee          EmployeeSkill                Skill
      EmployeeID         ForeignKey(EmployeeID)        SkillID
      Name,...           ForeignKey(SkillID)           Description,...
    

    The many-to-many relation between Employee and Skill using the junction table EmploySkill.

    Individually, the Employee and EmployeeSkill have a one-to-many relation, and the Skill and EmployeeSkill tables have one-to-many relation. But, they form many-to-many relation by using a junction table EmployeeSkill.

    See https://www.tutorialsteacher.com/sqlserver/tables-relations

    ]]>
    Google PageSpeed Insights for measuring page load time 2024-03-06T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/tools__Google_PageSpeed_Insights_for_measuring_page_load_time Google’s PageSpeed Insights

    ]]>
    Useful third party packages for Django 2024-03-06T00:00:00+08:00 Haiiiiiyun haiiiiiyun.github.io/django__Useful_third_party_packages_for_Django
  • django-debug-toolbar: inspect the complete request/response cycle of any given page.
  • django-extensions: comes with a number of command extensions, including shell_plus, which automatically loads all app models in the shell.
  • django-compressor: minimize front-end assets.
  • easy-thumbnails: shrink down image size. A fantastic free e-book on the topic is Essential Image Optimization by Addy Osmani that goes into depth on image optimization and automations.
  • nplusone, django-zen-queries, django-auto-prefetch: identify SQL N+1 issues.
  • ]]>