from django.shortcuts import render from django.forms import modelformset_factory, formset_factory from app01.models import Publisher from app01.forms import PublisherForm def publisher(request): # 查找到数据库中所有的出版社数据 data = Publisher.objects.all() FormSet = modelformset_factory(Publisher, PublisherForm, extra=0) formset_obj = FormSet(queryset=data) if request.method == 'POST': # form_obj = Form(request.POST, instance=edit_obj) formset_obj = FormSet(request.POST, queryset=data) if formset_obj.is_valid(): formset_obj.save() return render(request, 'publisher.html', {'formset_obj': formset_obj}) <form action="" method="post"> {% csrf_token %} {{ formset_obj.management_form }} {% for form_obj in formset_obj %} <tr> <td>{{ forloop.counter }}</td> {{ form_obj.id }} <td>{{ form_obj.name }}</td> <td>{{ form_obj.addr }}</td> </tr> {% endfor %}
""" 自定义分页组件 可以返回分页的数据和分页的HTML代码 """ from django.http import QueryDict class Pagination(object): def __init__(self, current_page, total_count, url_prefix, query_dict=QueryDict(mutable=True), per_page=10, show_page=9): """ 初始化分分页器 :param url_prefix: a标签的URL前缀 :param query_dict: 空的QueryDict()对象,并且是可修改的 :param current_page: 当前页码数 :param total_count: 数据总数 :param per_page: 每一页显示多少数据, 默认值是10 :param show_page: 页面显示的页码数, 默认值是9 """ # 0.分页的URL前缀 self.url_prefix = url_prefix self.query_dict = query_dict # 1. 每一页显示10条数据 assert per_page > 0 # 每页显示多少的数据必须是一个大于0的数 self.per_page = per_page # 2. 计算需要多少页 total_page, more = divmod(total_count, per_page) if more: total_page += 1 self.total_page = total_page # 3. 当前页码 try: current_page = int(current_page) except Exception as e: current_page = 1 current_page = total_page if current_page > total_page else current_page # 页码必须是大于0的数 if current_page < 1: current_page = 1 self.current_page = current_page # 4. 页面最多显示的页码数 self.show_page = show_page # 5. 最多显示页码的一半 self.half_show_page = self.show_page // 2 @property def start(self): # 数据切片的开始位置 return self.per_page * (self.current_page - 1) @property def end(self): # 数据切片的结束为止 return self.current_page * self.per_page # 定义一个返回HTML代码的方法 def page_html(self): if self.total_page == 0: return '' # 如果总页码数小于最大要显示的页码数 if self.total_page < self.show_page: show_page_start = 1 show_page_end = self.total_page # 左边越界 elif self.current_page - self.half_show_page < 1: show_page_start = 1 show_page_end = self.show_page # 右边越界 elif self.current_page + self.half_show_page > self.total_page: show_page_end = self.total_page show_page_start = self.total_page - self.show_page + 1 else: show_page_start = self.current_page - self.half_show_page # 页面显示页码的结束 show_page_end = self.current_page + self.half_show_page # 生成分页的HTML代码 page_list = [] # 添加分页代码的前缀 page_list.append('<nav aria-label="Page navigation"><ul class="pagination">') # 添加首页 self.query_dict['page'] = 1 page_list.append('<li><a href="{}?{}">首页</a></li>'.format(self.url_prefix, self.query_dict.urlencode())) # 添加上一 if self.current_page - 1 < 1: # 已经到头啦,不让点上一页啦 page_list.append( '<li class="disabled"><a href="" aria-label="Previous"><span aria-hidden="true">«</span></a></li>') else: self.query_dict['page'] = self.current_page - 1 page_list.append( '<li><a href="{}?{}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format( self.url_prefix, self.query_dict.urlencode()) ) for i in range(show_page_start, show_page_end + 1): self.query_dict['page'] = i if i == self.current_page: s = '<li class="active"><a href="{1}?{2}">{0}</a></li>'.format(i, self.url_prefix, self.query_dict.urlencode()) else: s = '<li><a href="{1}?{2}">{0}</a></li>'.format(i, self.url_prefix, self.query_dict.urlencode()) page_list.append(s) # 添加下一页 if self.current_page + 1 > self.total_page: page_list.append( '<li class="disabled"><a href="" aria-label="Next"><span aria-hidden="true">»</span></a></li>') else: self.query_dict['page'] = self.current_page + 1 page_list.append( '<li><a href="{}?{}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format( self.url_prefix, self.query_dict.urlencode()) ) # 添加尾页 self.query_dict['page'] = self.total_page page_list.append('<li><a href="{}?{}">尾页</a></li>'.format(self.url_prefix, self.query_dict.urlencode())) # 添加分页代码的后缀 page_list.append('</ul></nav>') page_html = ''.join(page_list) return page_html
mysql
# import pymysql
# pymysql.install_as_MySQLdb()
""" Django settings for knight project. Generated by 'django-admin startproject' using Django 1.11.16. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/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/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '(opcduuy#hnmr8cb&r*8$(%8l@&v2&8!c0gkw!yqc!ju6a&ej9' # 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', 'crm.apps.CrmConfig', ] 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 = 'knight.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 = 'knight.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3') # 'ENGINE': 'django.db.backends.mysql', # 'NAME': 'knight', # 'HOST': '127.0.0.1', # 'PORT': 3306, # 'USER': 'root', # 'PASSWORD': '123' } } # Password validation # https://docs.djangoproject.com/en/1.11/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/1.11/topics/i18n/ # LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'zh-hans' # TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True # 是否启动本地化 USE_L10N = False USE_TZ = True DATE_FORMAT = 'Y-m-d' DATETIME_FORMAT = 'Y-m-d H:i:s' # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] # 指定使用crm.UserProfile 表代替默认的auth_user表 AUTH_USER_MODEL = 'crm.UserProfile' # 配置登录页面的URL LOGIN_URL = '/login/' # 销售的私户限制数 CUSTOMER_NUM_LIMIT = 3
class BootstrapBaseForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 给实例对象的每一个字段添加class for field in self.fields.values(): field.widget.attrs.update({'class': 'form-control'}) class RegForm(BootstrapBaseForm): # email = forms.CharField( # validators=[RegexValidator(r"[1-9][0-9]{4,12}@qq\.com", "请输入正确的qq邮箱 heihiehie"), ] # ) re_password = forms.CharField( label='确认密码', widget=forms.widgets.PasswordInput(), ) class Meta: # 类的配置信息 model = UserProfile # ***** # fields = '__all__' # 所有字段都展示 fields = ['email', 'password', 're_password', 'name', 'mobile'] # 按照顺序展示列表中列出来的字段 # exclude = [''] # 把不需要展示的字段排除,展示剩下的字段 labels = { 'email': '邮箱', } error_messages = { 'password': { 'min-length': '密码最短多少位', } } widgets = { 'password': forms.widgets.PasswordInput(), } def clean_email(self): email_value = self.cleaned_data.get('email') is_exist = UserProfile.objects.filter(email=email_value) if is_exist: raise ValidationError('邮箱已被注册') else: return email_value def clean(self): pwd_value = self.cleaned_data.get('password') re_pwd_value = self.cleaned_data.get('re_password') if pwd_value == re_pwd_value: return self.cleaned_data else: self.add_error('re_password', '两次密码不一致') raise ValidationError('两次密码不一致') class CustomerForm(BootstrapBaseForm): class Meta: model = Customer fields = '__all__' widgets = { 'course': forms.widgets.SelectMultiple, 'birthday': forms.widgets.DateInput(attrs={'type': 'date'}), } class ConsultRecordForm(BootstrapBaseForm): class Meta: model = ConsultRecord exclude = ['delete_status', ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 把customer字段的choice设置成我的客户 print(self.instance, id(self.instance),'(((((((((((((') print('&' * 120) # 方法1:修改字段的chocies选项 # self.fields['customer'].choices = Customer.objects.filter(consultant=self.instance.consultant).values_list('id','name') # 方法2:将form表的字段直接修改字段 self.fields['customer'] = forms.models.ModelChoiceField(queryset=Customer.objects.filter(consultant=self.instance.consultant)) self.fields['customer'].widget.attrs.update({'class': 'form-control'}) # 修改跟进人只能是自己 self.fields['consultant'].choices = [(self.instance.consultant.id, self.instance.consultant.name), ]
from django.db import models from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager, User from django.utils.translation import ugettext_lazy as _ from multiselectfield import MultiSelectField from django.core.validators import RegexValidator from django.utils.safestring import mark_safe attendance_choices = (('checked', "已签到"), ('vacate', "请假"), ('late', "迟到"), ('absence', "缺勤"), ('leave_early', "早退"),) class Customer(models.Model): """ 客户表 """ qq = models.CharField(verbose_name='QQ', max_length=64, unique=True, help_text='QQ号必须唯一') qq_name = models.CharField('QQ昵称', max_length=64, blank=True, null=True) name = models.CharField('姓名', max_length=32, blank=True, null=True, help_text='学员报名后,请改为真实姓名') sex_type = (('male', '男'), ('female', '女')) sex = models.CharField("性别", choices=sex_type, max_length=16, default='male', blank=True, null=True) birthday = models.DateField('出生日期', default=None, help_text="格式yyyy-mm-dd", blank=True, null=True) phone = models.BigIntegerField('手机号', blank=True, null=True) source = models.CharField('客户来源', max_length=64, choices=source_type, default='qq') introduce_from = models.ForeignKey('self', verbose_name="转介绍自学员", blank=True, null=True) course = MultiSelectField("咨询课程", choices=course_choices) class_type = models.CharField("班级类型", max_length=64, choices=class_type_choices, default='fulltime') customer_note = models.TextField("客户备注", blank=True, null=True, ) status = models.CharField("状态", choices=enroll_status_choices, max_length=64, default="unregistered", help_text="选择客户此时的状态") network_consult_note = models.TextField(blank=True, null=True, verbose_name='网络咨询师咨询内容') date = models.DateTimeField("咨询日期", auto_now_add=True) last_consult_date = models.DateField("最后跟进日期", auto_now_add=True) next_date = models.DateField("预计再次跟进时间", blank=True, null=True) network_consultant = models.ForeignKey('UserProfile', blank=True, null=True, verbose_name='咨询师', related_name='network_consultant') consultant = models.ForeignKey('UserProfile', verbose_name="销售", related_name='customers', blank=True, null=True, ) class_list = models.ManyToManyField('ClassList', verbose_name="已报班级", null=True, blank=True) class Meta: verbose_name = '客户' verbose_name_plural = verbose_name def __str__(self): return '{}-{}'.format(self.qq, self.name) # 自定义类的方法 def show_class_list(self): return '|'.join([str(i) for i in self.class_list.all()]) # 展示状态 def show_status(self): _status_color = { 'signed': 'blue', 'unregistered': 'red', 'studying': 'orange', 'paid_in_full': 'green', } return mark_safe('<span style="background-color: {};color: white">{}</span>'.format( _status_color[self.status], self.get_status_display() )) class ClassList(models.Model): """ 班级表 """ course = models.CharField("课程名称", max_length=64, choices=course_choices) semester = models.IntegerField("学期") campuses = models.ForeignKey('Campuses', verbose_name="校区") price = models.IntegerField("学费", default=10000) memo = models.CharField('说明', blank=True, null=True, max_length=100) start_date = models.DateField("开班日期") graduate_date = models.DateField("结业日期", blank=True, null=True) contract = models.ForeignKey('ContractTemplate', verbose_name="选择合同模版", blank=True, null=True) teachers = models.ManyToManyField('UserProfile', verbose_name="老师") class_type = models.CharField(choices=class_type_choices, max_length=64, verbose_name='班级类型', blank=True, null=True) class Meta: unique_together = ("course", "semester", 'campuses') verbose_name = '已报班级' verbose_name_plural = verbose_name def __str__(self): return '{}-{}({})'.format(self.get_course_display(), self.semester, self.campuses) class UserManager(BaseUserManager): use_in_migrations = True def _create_user(self, email, password, **extra_fields): """ Creates and saves a User with the given email and password. """ if not email: raise ValueError('The given email must be set') email = self.normalize_email(email) user = self.model(email=email, **extra_fields) # 创建对象 UserProfile(email='', password='') user.set_password(password) # 把密码加密 user.save(using=self._db) # 保存到数据库 return user def create_user(self, email, password=None, **extra_fields): extra_fields.setdefault('is_staff', False) extra_fields.setdefault('is_superuser', False) return self._create_user(email, password, **extra_fields) def create_superuser(self, email, password, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) if extra_fields.get('is_staff') is not True: raise ValueError('Superuser must have is_staff=True.') if extra_fields.get('is_superuser') is not True: raise ValueError('Superuser must have is_superuser=True.') return self._create_user(email, password, **extra_fields) class UserProfile(AbstractBaseUser, PermissionsMixin): email = models.EmailField( max_length=255, unique=True, # validators=[RegexValidator(r"[1-9][0-9]{0,12}@qq\.com", "请输入正确的qq邮箱 heihiehie"), ] ) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.'), ) is_active = models.BooleanField( _('active'), default=True, help_text=_( 'Designates whether this user should be treated as active. ' 'Unselect this instead of deleting accounts.' ), ) name = models.CharField('名字', max_length=32) department = models.ForeignKey('Department', default=None, blank=True, null=True) mobile = models.CharField('手机', max_length=32, default=None, blank=True, null=True) memo = models.TextField('备注', blank=True, null=True, default=None) date_joined = models.DateTimeField(auto_now_add=True) EMAIL_FIELD = 'email' USERNAME_FIELD = 'email' # 用来唯一确定auth中的用户 REQUIRED_FIELDS = ['name'] # auth指定除了上面两个配置项的字段还有那些字段要必填 class Meta: verbose_name = '账户信息' verbose_name_plural = "账户信息" def clean(self): super(UserProfile, self).clean() # 对邮件字段做校验 self.email = self.__class__.objects.normalize_email(self.email) def get_full_name(self): # The user is identified by their email address return self.name def get_short_name(self): # The user is identified by their email address return self.email def __str__(self): # __unicode__ on Python 2 return self.name # 给ORM添加管理类 objects = UserManager()
class RegView(views.View): def get(self, request): form_obj = RegForm() return render(request, 'reg.html', {'form_obj': form_obj}) def post(self, request): form_obj = RegForm(request.POST) if form_obj.is_valid(): # 校验通过 # 方法一: # 1. 先把re_password字段去掉 # form_obj.cleaned_data.pop('re_password') # # 2. 去数据库创建新用户 # UserProfile.objects.create_user(**form_obj.cleaned_data) # 方法二:form_obj是一个ModelForm对象,它和数据库里面的Model类对应的 user_obj = form_obj.save() # --> UserProfile.objects.create(**form_obj.cleaned_data) user_obj.set_password(user_obj.password) user_obj.save() <select class="form-control" name="action"> <option value="">---------</option> <option value="to_public">变为公户</option> <option value="to_private">变为私户</option> <option value="delete">删除</option> </select> <div class="input-group-btn"> <button type="submit" class="btn btn-primary">提交</button> </div> </div> </div> <div class="col-md-10"> <div class="table-responsive"> <table class="table table-striped table-bordered"> <thead> <tr> <th style="width: 20px">选择</th> <th style="width: 20px">#</th> <th style="width: 80px">QQ</th> <th style="width: 80px">QQ昵称</th> <th style="width: 60px">姓名</th> <th style="width: 80px">电话</th> <th style="width: 90px">客户来源</th> <th style="width: 120px">咨询课程</th> <th style="width: 60px">招生老师</th> <th style="width: 60px">班级类型</th> <th style="width: 60px">状态</th> <th style="width: 100px">咨询日期</th> <th style="width: 120px!important;">已报班级</th> <th style="width: 120px!important;">沟通记录</th> <th style="width: 120px!important;">报名</th> <th style="width: 20px!important;">操作</th> </tr> </thead> <tbody> {% for customer in customer_list %} <tr> <td><input type="checkbox" name="cid" value="{{ customer.id }}"></td> <td>{{ forloop.counter }}</td> <td>{{ customer.qq }}</td> <td>{{ customer.qq_name }}</td> <td>{{ customer.name }}</td> <td>{{ customer.phone|default:'暂无' }}</td> <td>{{ customer.get_source_display }}</td> <td>{{ customer.course }}</td> <td>{{ customer.consultant }}</td> <td>{{ customer.get_class_type_display }}</td> <td>{{ customer.show_status }}</td> <td>{{ customer.date|date:'Y-m-d' }}</td> <td>{{ customer.show_class_list|default:'暂无' }}</td> <td><a href="{% url 'consult_record' cid=customer.id %}">查看</a></td> <td> <a href="{% url 'add_enrollment' customer.id %}">添加</a> | <a href="{% url 'enrollment_list' customer.id %}">查看</a> </td> <td><a href="{% url 'edit_customer' customer.id %}?{{ next_url }}"><i class="fa fa-edit" aria-hidden="true"></i></a></td> </tr> {% endfor %} </tbody> </table> <div> {{ page_html|safe }}
<div class="table-responsive"> <table class="table table-striped table-bordered"> <thead> <tr> <th style="width: 20px">选择</th> <th style="width: 20px">#</th> <th style="width: 80px">客户qq</th> <th style="width: 80px">客户姓名</th> <th style="width: 80px">跟进内容</th> <th style="width: 60px">跟进状态</th> <th style="width: 80px">跟进人</th> <th style="width: 90px">跟进日期</th> <th style="width: 20px!important;">操作</th> </tr> </thead> <tbody> {% for record in consult_record %} <tr> <td><input type="checkbox" name="cid" value="{{ record.id }}"></td> <td>{{ forloop.counter }}</td> <td>{{ record.customer.qq }}</td> <td>{{ record.customer.name }}</td> <td>{{ record.note }}</td> <td>{{ record.get_status_display }}</td> <td>{{ record.consultant.name }}</td> <td>{{ record.date }}</td> <td><a href="{% url 'edit_record' record.id %}"><i class="fa fa-edit" aria-hidden="true"></i></a></td> </tr> {% endfor %} </tbody> class EnrollmentListView(views.View): def get(self, request, customer_id=0): if int(customer_id) == 0: # 查询当前这个销售所有客户的报名表 query_set = Enrollment.objects.filter(customer__consultant=request.user) else: query_set = Enrollment.objects.filter(customer_id=customer_id) return render(request, 'enrollment_list.html', {'enrollment_list': query_set}) # 添加/编辑报名记录 def enrollment(request, customer_id=None, enrollment_id=None): # 先根据报名表id去查询 enrollment_obj = Enrollment.objects.filter(id=enrollment_id).first() # 查询不到报名表说明是新增报名表操作 # 又因为新增报名表必须指定客户 if not enrollment_obj: enrollment_obj = Enrollment(customer=Customer.objects.filter(id=customer_id).first()) form_obj = EnrollmentForm(instance=enrollment_obj) if request.method == 'POST': form_obj = EnrollmentForm(request.POST, instance=enrollment_obj) if form_obj.is_valid(): new_obj = form_obj.save() # 报名成功,更改客户当前的状态 new_obj.customer.status = 'signed' new_obj.customer.save() # 改的是哪张表的字段就保存哪个对象 return redirect(reverse('enrollment_list', kwargs={'customer_id': 0})) else: return HttpResponse('出错啦') return render(request, 'enrollment.html', {'form_obj': form_obj})
<form action="" method="post"> {% csrf_token %} {{ formset_obj.management_form }} <div class="col-md-3" style="margin: 5px 0"> </div> <div class="col-md-12"> <div class="table-responsive"> <table class="table table-striped table-bordered"> <thead> <tr> <th style="width: 20px">#</th> <th style="width: 80px">姓名</th> <th style="width: 80px">考勤</th> <th style="width: 80px">成绩</th> <th style="width: 80px">作业</th> </tr> </thead> <tbody> {% for form_obj in formset_obj %} <tr> {{ form_obj.id }} <td>{{ forloop.counter }}</td> <td style="display: none">{{ form_obj.student }}</td> <td>{{ form_obj.instance.student.name }}</td> <td>{{ form_obj.attendance }}</td> <td>{{ form_obj.score }}</td> <td>{{ form_obj.homework_note }}</td> </tr> {% endfor %} </tbody> </table> <div> {{ page_html|safe }} from django import views from django.shortcuts import render, redirect, HttpResponse from crm.models import ClassList, CourseRecord, StudyRecord from crm.forms import ClassListForm, CourseRecordForm, StudyRecordForm from django.urls import reverse from django.http import QueryDict class ClassListView(views.View): def get(self, request): query_set = ClassList.objects.all() return render(request, 'class_list.html', {'class_list': query_set}) # 新增和编辑班级 def op_class(request, edit_id=None): edit_obj = ClassList.objects.filter(id=edit_id).first() form_obj = ClassListForm(instance=edit_obj) if request.method == 'POST': form_obj = ClassListForm(request.POST, instance=edit_obj) if form_obj.is_valid(): form_obj.save() return redirect(reverse('class_list')) return render(request, 'op_class.html', {'form_obj': form_obj, 'edit_id': edit_id}) # 课程记录 class CourseListView(views.View): def get(self, request, class_id): print(class_id) print('*' * 120) # 根据班级id查询出所有的上课记录 query_set = CourseRecord.objects.filter(re_class_id=class_id) current_url = request.get_full_path() qd = QueryDict(mutable=True) qd['next'] = current_url return render(request, 'course_list.html', {'course_record_list': query_set, 'next_url': qd.urlencode(), 'class_id': class_id}) def post(self, request, class_id): # 1. 从POST提交过来的数据里找action 和 勾选的课程记录id cid = request.POST.getlist('cid') action = request.POST.get('action') # 2. 利用反射执行指定的动作 if hasattr(self, '_{}'.format(action)): ret = getattr(self, '_{}'.format(action))(cid) else: return HttpResponse('滚') if ret: return ret else: return redirect(reverse('course_record_list', kwargs={'class_id': class_id})) def _multi_init(self, cid): # 3. 根据cid找到要初始化学习记录的那些课程 courser_objs = CourseRecord.objects.filter(id__in=cid) print(courser_objs) print('*' * 120) # 4. 针对每个课程 挨个初始化学习记录 # 4.1 创建学习记录 课程记录对象在上面已经找到了, 找学生? --> 根据课程记录找 re_class --> 反向查找这个班级的所有学生 for course_record in courser_objs: all_student = course_record.re_class.customer_set.all() # 60个学生 print(all_student) print('-' * 120) # 创建学习记录 studentreord_objs = (StudyRecord(course_record=course_record, student=student) for student in all_student) StudyRecord.objects.bulk_create(studentreord_objs) return HttpResponse('初始化好了') def course_record(request, class_id=None, course_record_id=None): class_obj = ClassList.objects.filter(id=class_id).first() edit_obj = CourseRecord.objects.filter(id=course_record_id).first() form_obj = CourseRecordForm(instance=edit_obj, initial={'re_class': class_obj}) if request.method == 'POST': form_obj = CourseRecordForm(request.POST) if form_obj.is_valid(): form_obj.save() next_url = request.GET.get('next', '/crm/class_list/') return redirect(next_url) return render(request, 'course_record.html', {'form_obj': form_obj, 'edit_id': course_record_id}) from django.forms import modelformset_factory # 学习记录列表 def study_record_list(request, course_record_id): FormSet = modelformset_factory(StudyRecord, StudyRecordForm, extra=0) # 返回值是一个类 # 拿到这一个课程记录的所有同学的学习记录 query_set = StudyRecord.objects.filter(course_record_id=course_record_id) formset_obj = FormSet(queryset=query_set) if request.method == 'POST': formset_obj = FormSet(request.POST, queryset=query_set) if formset_obj.is_valid(): formset_obj.save() return render(request, 'study_record_list.html', {'formset_obj': formset_obj})
def customer_import(request): """ 批量导入 :param request: :return: """ if request.method == 'GET': return render(request, 'customer_import.html') context = {'status': True, 'msg': '导入成功'} try: customer_excel = request.FILES.get('customer_excel') """ 打开上传的Excel文件,并读取内容 注:打开本地文件时,可以使用:workbook = xlrd.open_workbook(filename='本地文件路径.xlsx') """ workbook = xlrd.open_workbook(file_contents=customer_excel.file.read()) # sheet = workbook.sheet_by_name('工作表1') sheet = workbook.sheet_by_index(0) row_map = { 0: {'text': '客户姓名', 'name': 'name'}, 1: {'text': '年龄', 'name': 'age'}, 2: {'text': '邮箱', 'name': 'email'}, 3: {'text': '公司', 'name': 'company'}, } object_list = [] for row_num in range(1, sheet.nrows): row = sheet.row(row_num) row_dict = {} for col_num, name_text in row_map.items(): row_dict[name_text['name']] = row[col_num].value object_list.append(models.Customer(**row_dict)) models.Customer.objects.bulk_create(object_list, batch_size=20) except Exception as e: context['status'] = False context['msg'] = '导入失败' return render(request, 'customer_import.html', context) def customer_tpl(request): """ 下载批量导入Excel列表 :param request: :return: """ tpl_path = os.path.join(settings.BASE_DIR, 'web', 'files', '批量导入客户模板.xlsx') content_type = mimetypes.guess_type(tpl_path)[0] print(content_type) response = FileResponse(open(tpl_path, mode='rb'), content_type=content_type) response['Content-Disposition'] = "attachment;filename=%s" % 'customer_excel_tpl.xlsx' return response
浙公网安备 33010602011771号