一 使用环境
开发系统: windows
IDE: pycharm
数据库: msyql,navicat
编程语言: python3.7 (Windows x86-64 executable installer)
虚拟环境: virtualenvwrapper
开发框架: Django 2.2
Django 2.2通病===>访问admin出现问题:
报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: illegal multibyte sequence
解决方法:https://www.cnblogs.com/djtang/p/10194811.html
二 Django Admin 实现三级联动的示例代码(省市区)===>小白级
1. 在 model.py 中
from django.db import models # 人员 class Member(models.Model): name = models.CharField(max_length=100, verbose_name='姓名') province = models.ForeignKey('Province', on_delete=models.PROTECT, null=True, blank=True, verbose_name='省份') city = models.ForeignKey('City', on_delete=models.PROTECT, null=True, blank=True, verbose_name='城市') district = models.ForeignKey('District', on_delete=models.PROTECT, null=True, blank=True, verbose_name='区/县') class Meta: verbose_name_plural = verbose_name = '00-人员' def __str__(self): return self.name # 省份 class Province(models.Model): 省份 = models.CharField(max_length=100, null=True, blank=True, verbose_name='省份') class Meta: verbose_name_plural = verbose_name = '01-省份' def __str__(self): return self.省份 # 城市 class City(models.Model): 城市 = models.CharField(max_length=100, null=True, blank=True, verbose_name='城市') 省份 = models.ForeignKey('Province', on_delete=models.PROTECT, null=True, blank=True, related_name='城市_省份', verbose_name='省份') class Meta: verbose_name_plural = verbose_name = '02-城市' def __str__(self): return self.城市 # 区/县 class District(models.Model): 区县 = models.CharField(max_length=100, null=True, blank=True, verbose_name='区/县') 城市 = models.ForeignKey('City', on_delete=models.PROTECT, null=True, blank=True, related_name='区县_城市', verbose_name='城市') class Meta: verbose_name_plural = verbose_name = '03-区/县' def __str__(self): return self.区县
2. 在 view.py 中
from django.http import JsonResponse from sjld.models import Province, City, District # Create your views here. # 省份 def choose_province(request): 省份 = Province.objects.all() result = [] for i in 省份: result.append(i.省份) # 取公司的简称 province = result # 传递一个列表 return JsonResponse(province, safe=False) def choose_city(request): 省份 = request.GET.get('p') # 取上面选中省份的名称 城市 = City.objects.all() result = [] for i in 城市: if str(省份) == str(i.省份): result.append(i.城市) cities = result # 传递一个列表 return JsonResponse(cities, safe=False) def choose_district(request): 城市 = request.GET.get('c') # 取上面选中城市的名称 区县 = District.objects.all() result = [] for i in 区县: if str(城市) == str(i.城市): result.append(i.区县) cities = result # 传递一个列表 districts = cities return JsonResponse(districts, safe=False)
3. 在 urls.py 中
from django.contrib import admin from django.urls import path from sjld.views import choose_province, choose_city, choose_district urlpatterns = [ path('admin/', admin.site.urls), path('province/', choose_province), path('city/', choose_city), path('district/', choose_district), ]
4. 在 admin.py 中
from django import forms from django.contrib import admin from shanjld.models import Member, Province, City, District class MemberForm(forms.ModelForm): class Meta: widgets = { 'province': forms.Select(), 'city': forms.Select(), 'district': forms.Select() } # 人员 @admin.register(Member) class MemberAdmin(admin.ModelAdmin): form = MemberForm change_form_template = 'area.html' # raw_id_fields = ('province', 'city', 'district',) # 这个在这里就无效了,希望哪位大老指点一下,怎么重写这个方法. fields = ('name', 'province', 'city', 'district') list_display = ('name', 'province', 'city', 'district') # 省份 @admin.register(Province) class ProvinceAdmin(admin.ModelAdmin): pass # 城市 @admin.register(City) class CityAdmin(admin.ModelAdmin): raw_id_fields = ('省份',) # 区/县 @admin.register(District) class DistrictAdmin(admin.ModelAdmin): raw_id_fields = ('城市',)
5. 在项目 templates 文件下新建一个 area.html 文件
6. 找到django源码中的 change_form.html 文件,打开复制里面全部的html内容到 area.html 中. (文件在 External Libraries => python3.7(我用的这个版本) => site-packages => django/contrib/admin/templates/admin/).
7. 在 area.html 文件中找到 {% block admin_change_form_document_ready %} (在66行) , 用下面代码覆盖全部 {% block admin_change_form_document_ready %} .
7.1 area.html 中所有增加替换代码
{% block admin_change_form_document_ready %} <script type="text/javascript" id="django-admin-form-add-constants" src="{% static 'admin/js/change_form.js' %}" {% if adminform and add %} data-model-name="{{ opts.model_name }}" {% endif %}> </script> <script type="text/javascript"> (function($) { $('#id_city').change(function() { let p_id = $('#id_province').val(); let c_id = $('#id_city').val(); $.get('/district/', {"p": p_id, "c": c_id }, function(a_info) { var area_info = $('#id_district').empty().append('<option value>' + '---------' + '</option>'); $.each(a_info, function(i, area) { area_info.append('<option value="' + area + '">' + area + '</option>') }); {% if change %} $("#id_district").find("option:contains({{ original.district }})").attr('selected', true); {% endif %} }); }); $('#id_province').change(function() { let p_id = $('#id_province').val(); $.get('/city/', { 'p': p_id }, function(c_info) { var city_info = $('#id_city').empty().append('<option value>' + '---------' + '</option>'); $.each(c_info, function(i, city) { city_info.append('<option value="' + city + '">' + city + '</option>') }); {% if change %} $("#id_city").find("option:contains({{ original.city }})").attr('selected', true); $("#id_city").trigger("change"); {% endif %} }); }); $.get('/province/', function(p_info) { var province_info = $('#id_province').empty().append('<option value>' + '---------' + '</option>'); $.each(p_info, function(i, province) { province_info.append('<option value="' + province + '">' + province + '</option>') }); {% if change %} $("#id_province").find("option:contains({{ original.province }})").attr('selected', true); $("#id_province").trigger("change"); {% endif %} }); })(django.jQuery); </script> {% endblock %}
7.2 area.html 中所有代码
{% extends "admin/base_site.html" %} {% load i18n admin_urls static admin_modify %} {% block extrahead %}{{ block.super }} <script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script> {{ media }} {% endblock %} {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}">{% endblock %} {% block coltype %}colM{% endblock %} {% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %} {% if not is_popup %} {% block breadcrumbs %} <div class="breadcrumbs"> <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> › <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a> › {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › {% if add %}{% blocktrans with name=opts.verbose_name %}Add {{ name }}{% endblocktrans %}{% else %}{{ original|truncatewords:"18" }}{% endif %} </div> {% endblock %} {% endif %} {% block content %}<div id="content-main"> {% block object-tools %} {% if change %}{% if not is_popup %} <ul class="object-tools"> {% block object-tools-items %} {% change_form_object_tools %} {% endblock %} </ul> {% endif %}{% endif %} {% endblock %} <form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.model_name }}_form" novalidate>{% csrf_token %}{% block form_top %}{% endblock %} <div> {% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %} {% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %} {% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %} {% if errors %} <p class="errornote"> {% if errors|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %} </p> {{ adminform.form.non_field_errors }} {% endif %} {% block field_sets %} {% for fieldset in adminform %} {% include "admin/includes/fieldset.html" %} {% endfor %} {% endblock %} {% block after_field_sets %}{% endblock %} {% block inline_field_sets %} {% for inline_admin_formset in inline_admin_formsets %} {% include inline_admin_formset.opts.template %} {% endfor %} {% endblock %} {% block after_related_objects %}{% endblock %} {% block submit_buttons_bottom %}{% submit_row %}{% endblock %} {% block admin_change_form_document_ready %} <script type="text/javascript" id="django-admin-form-add-constants" src="{% static 'admin/js/change_form.js' %}" {% if adminform and add %} data-model-name="{{ opts.model_name }}" {% endif %}> </script> {% endblock %} {# JavaScript for prepopulated fields #} {% prepopulated_fields_js %} </div> </form></div> {% endblock %}
8.效果
9.访问admin出现问题:
报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: illegal multibyte sequence
解决方法:https://www.cnblogs.com/djtang/p/10194811.html