product.outerframe.top.cost
这使得我必须进行复杂的计算,组织得更好.
但是,这种模式安排使得使用django admin很棘手.我基本上有一个直通表,即外框表只是一堆外键到其他表(每个表都有唯一约束).我最终了解了Modeladmin的add_vIEw()和change_vIEw()方法,这非常困难.
使用django管理员时,是否有更简单的方法来处理多对多/通过表格?
表格的排列方式如下:
产品>外框,内框,玻璃,其他
外框>顶部,底部,侧面等
内框架>顶部,侧面等
玻璃> glass_type等
其他>配件等
这是我的模特:
class Product(mixins.Productvariables): name = models.CharFIEld(max_length=255) sku = models.CharFIEld(max_length=100,unique=True,db_index=True) image = thumbnail.ImageFIEld(upload_to='product_images',blank=True) description = models.TextFIEld(blank=True) group = models.ForeignKey('ProductGroup',related_name='products',null=True) hIDden = models.BooleanFIEld(default=False) product_specific_mark_up = models.DecimalFIEld(default=1.0,max_digits=5,decimal_places=2) # Methods for totals def total_material_cost(self,wIDth,height,options): return sum([ self.outerframe.cost(wIDth,options),self.innerframe.cost(wIDth,self.glass.cost(wIDth,self.other.cost(wIDth,]) def total_labour_time(self,options): return sum([ self.outerframe.labour_time(wIDth,self.innerframe.labour_time(wIDth,self.glass.labour_time(wIDth,self.other.labour_time(wIDth,]) def total_co2_output(self,options): return sum([ self.outerframe.co2_output(wIDth,self.innerframe.co2_output(wIDth,self.glass.co2_output(wIDth,self.other.co2_output(wIDth,]) @property def max_overall_wIDth(self): return 1000 @property def max_overall_height(self): return 1000 def __unicode__(self): return self.nameclass OuterFrame(models.Model,mixins.GetFIEldsMixin,mixins.GetRelatedClassesMixin): top = models.OnetoOneFIEld(mixins.topFrame) bottom = models.OnetoOneFIEld(mixins.BottomFrame) sIDe = models.OnetoOneFIEld(mixins.SIDeFrame) accessorIEs = models.OnetoOneFIEld(mixins.AccessorIEs) flashing = models.OnetoOneFIEld(mixins.Flashing) silicone = models.OnetoOneFIEld(mixins.Silicone) product = models.OnetoOneFIEld(Product) def cost(self,options): #accessorIEs_cost = (self.accessorIEs.cost if options['accessorIEs'] else 0) #flashing_cost = (self.flashing.cost if options['flashing'] else 0) #silicone_cost = (self.silicone.cost if options['silicone'] else 0) return sum([ self.top.cost * (wIDth / 1000),self.bottom.cost * (wIDth / 1000),self.sIDe.cost * (wIDth*2 / 1000),#accessorIEs_cost,#flashing_cost,#silicone_cost,]) def labour_time(self,options): return datetime.timedelta(minutes=100) def CO2_output(self,options): return 100 # some kg measurement @classmethod def get_fIElds(cls): options = cls._Meta fIElds = {} for fIEld in options.fIElds: if fIEld.name == 'product': continue if isinstance(fIEld,models.OnetoOneFIEld): related_cls = fIEld.rel.to related_fIElds = fIElds_for_model(related_cls,fIElds=related_cls.get_fIElds()) fIElds.update( { related_cls.__name__ + '_' + name:fIEld for name,fIEld in related_fIElds.iteritems() }) return fIEldsclass InnerFrame(models.Model,mixins.GetRelatedClassesMixin): top = models.OnetoOneFIEld(mixins.topFrame) bottom = models.OnetoOneFIEld(mixins.BottomFrame) sIDe = models.OnetoOneFIEld(mixins.SIDeFrame) accessorIEs = models.OnetoOneFIEld(mixins.AccessorIEs) product = models.OnetoOneFIEld(Product) def cost(self,options): #accessorIEs_cost = (self.accessorIEs.cost if options['accessorIEs'] else 0) print self.top.cost return sum([ self.top.cost * (wIDth / 1000),# accessorIEs_cost,options): return 100 # some kg measurementclass Glass(models.Model,mixins.GetRelatedClassesMixin): glass_type_a = models.OnetoOneFIEld(mixins.GlasstypeA) glass_type_b = models.OnetoOneFIEld(mixins.GlasstypeB) enhanced = models.OnetoOneFIEld(mixins.Enhanced) laminate = models.OnetoOneFIEld(mixins.Laminate) low_iron = models.OnetoOneFIEld(mixins.LowIron) privacy = models.OnetoOneFIEld(mixins.Privacy) anti_slip = models.OnetoOneFIEld(mixins.AntiSlip) heat_film_mirror = models.OnetoOneFIEld(mixins.HeatMirrorFIEld) posished_edges = models.OnetoOneFIEld(mixins.PolishedEdges) product = models.OnetoOneFIEld(Product) def cost(self,options): return sum([ ]) def labour_time(self,options): return 100 # some kg measurementclass Other(models.Model,mixins.GetRelatedClassesMixin): num_packages = models.OnetoOneFIEld(mixins.NumberPackages) product = models.OnetoOneFIEld(Product) def cost(self,options): return 100 def labour_time(self,options): return 100 # some kg measurement
混入:
class TimeCostMixin(models.Model,GetFIEldsMixin): cost = models.DecimalFIEld(default=0.0,max_digits=10,decimal_places=2) time = models.TimeFIEld(default=datetime.timedelta(0)) class Meta: abstract = True##### Frame #####class FrameComponentMixin(TimeCostMixin): external_wIDth = models.IntegerFIEld(default=0) material_weight = models.DecimalFIEld(default=0.0,decimal_places=2) u_value = models.DecimalFIEld(default=0.0,decimal_places=2) class Meta: abstract = Trueclass topFrame(FrameComponentMixin): passclass BottomFrame(FrameComponentMixin): passclass SIDeFrame(FrameComponentMixin): passclass AccessorIEs(TimeCostMixin): material_weight = models.DecimalFIEld(default=0.0,decimal_places=2)class Flashing(TimeCostMixin): passclass Silicone(TimeCostMixin): labour_time = models.DecimalFIEld(default=0.0,decimal_places=2)###################### Glass #####class GlasstypeA(TimeCostMixin): material_weight = models.DecimalFIEld(default=0.0,decimal_places=2)class GlasstypeB(TimeCostMixin): material_weight = models.DecimalFIEld(default=0.0,decimal_places=2)class Enhanced(TimeCostMixin): material_weight = models.DecimalFIEld(default=0.0,decimal_places=2)class Laminate(TimeCostMixin): material_weight = models.DecimalFIEld(default=0.0,decimal_places=2)class LowIron(TimeCostMixin): passclass Privacy(TimeCostMixin): passclass AntiSlip(TimeCostMixin): passclass HeatMirrorFIEld(TimeCostMixin): u_value = models.DecimalFIEld(default=0.0,decimal_places=2)class PolishedEdges(models.Model): cost = models.DecimalFIEld(default=0.0,decimal_places=2)####################### other #####class NumberPackages(models.Model): number_of_packages = models.IntegerFIEld(default=0)##################
还有一个拉头管理员!
class Productadmin(adminImageMixin,admin.Modeladmin): inlines = [ProductDownloadInline,ProductConfigurationInline] add_form_template = 'admin/products/add_form.HTML' change_form_template = 'admin/products/add_form.HTML' @csrf_protect_m @transaction.atomic def add_vIEw(self,request,form_url='',extra_context=None): extra_context = extra_context or {} "The 'add' admin vIEw for this model." model = self.model opts = model._Meta if not self.has_add_permission(request): raise PermissionDenIEd ModelForm = self.get_form(request) formsets = [] inline_instances = self.get_inline_instances(request,None) if request.method == 'POST': form = ModelForm(request.POST,request.fileS) if form.is_valID(): new_object = self.save_form(request,form,change=False) form_valIDated = True else: form_valIDated = False new_object = self.model() prefixes = {} for FormSet,inline in zip(self.get_formsets(request),inline_instances): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix,0) + 1 if prefixes[prefix] != 1 or not prefix: prefix = "%s-%s" % (prefix,prefixes[prefix]) formset = FormSet(data=request.POST,files=request.fileS,instance=new_object,save_as_new="_saveasnew" in request.POST,prefix=prefix,queryset=inline.get_queryset(request)) formsets.append(formset) ##### outer_frame_forms = [ modelform_factory(cls)(request.POST,prefix='OuterFrame_'+cls.__name__) for cls in models.OuterFrame.get_related_classes(exclude=['product']) ] inner_frame_forms = [ modelform_factory(cls)(request.POST,prefix='InnerFrame'+cls.__name__) for cls in models.InnerFrame.get_related_classes(exclude=['product']) ] glass_forms = [ modelform_factory(cls)(request.POST,prefix='InnerFrame'+cls.__name__) for cls in models.Glass.get_related_classes(exclude=['product']) ] other_forms = [ modelform_factory(cls)(request.POST,prefix='InnerFrame'+cls.__name__) for cls in models.Other.get_related_classes(exclude=['product']) ] ##### if all_valID(formsets +outer_frame_forms +inner_frame_forms +glass_forms +other_forms ) and form_valIDated: self.save_model(request,new_object,False) self.save_related(request,formsets,False) self.log_addition(request,new_object) ##### save object hIErichy ##### # inner frame inner_frame = models.InnerFrame() inner_frame.product = new_object mapPing = {f.rel.to:f.name for f in models.InnerFrame._Meta.fIElds if f.name not in ['ID','product']} for f in inner_frame_forms: obj = f.save() setattr(inner_frame,mapPing[obj.__class__],obj) inner_frame.save() # outer frame outer_frame = models.OuterFrame() outer_frame.product = new_object mapPing = {f.rel.to:f.name for f in models.OuterFrame._Meta.fIElds if f.name not in ['ID','product']} for f in outer_frame_forms: obj = f.save() setattr(outer_frame,obj) outer_frame.save() # glass glass = models.Glass() glass.product = new_object mapPing = {f.rel.to:f.name for f in models.Glass._Meta.fIElds if f.name not in ['ID','product']} for f in glass_forms: obj = f.save() setattr(glass,obj) glass.save() # other other = models.Other() other.product = new_object mapPing = {f.rel.to:f.name for f in models.Other._Meta.fIElds if f.name not in ['ID','product']} for f in other_forms: obj = f.save() setattr(other,obj) other.save() ################################# return self.response_add(request,new_object) else: forms = SortedDict({}) forms['Outer Frame Variables'] = { cls.__name__: modelform_factory(cls)(prefix='OuterFrame_'+cls.__name__) for cls in models.OuterFrame.get_related_classes(exclude=['product']) } forms['Inner Frame Variables'] = { cls.__name__: modelform_factory(cls)(prefix='InnerFrame'+cls.__name__) for cls in models.InnerFrame.get_related_classes(exclude=['product']) } forms['Glass Variables'] = { cls.__name__: modelform_factory(cls)(prefix='InnerFrame'+cls.__name__) for cls in models.Glass.get_related_classes(exclude=['product']) } forms['Other Variables'] = { cls.__name__: modelform_factory(cls)(prefix='InnerFrame'+cls.__name__) for cls in models.Other.get_related_classes(exclude=['product']) } extra_context['forms'] = forms # Prepare the dict of initial data from the request. # We have to special-case M2Ms as a List of comma-separated PKs. initial = dict(request.GET.items()) for k in initial: try: f = opts.get_fIEld(k) except models.FIEldDoesNotExist: continue if isinstance(f,models.ManyToManyFIEld): initial[k] = initial[k].split(",") form = ModelForm(initial=initial) prefixes = {} for FormSet,prefixes[prefix]) formset = FormSet(instance=self.model(),queryset=inline.get_queryset(request)) formsets.append(formset) adminForm = helpers.adminForm(form,List(self.get_fIEldsets(request)),self.get_prepopulated_fIElds(request),self.get_Readonly_fIElds(request),model_admin=self) media = self.media + adminForm.media inline_admin_formsets = [] for inline,formset in zip(inline_instances,formsets): fIEldsets = List(inline.get_fIEldsets(request)) Readonly = List(inline.get_Readonly_fIElds(request)) prepopulated = dict(inline.get_prepopulated_fIElds(request)) inline_admin_formset = helpers.InlineadminFormSet(inline,formset,fIEldsets,prepopulated,Readonly,model_admin=self) inline_admin_formsets.append(inline_admin_formset) media = media + inline_admin_formset.media context = { 'Title': _('Add %s') % force_text(opts.verbose_name),'adminform': adminForm,'is_popup': IS_POPUP_VAR in request.REQUEST,'media': media,'inline_admin_formsets': inline_admin_formsets,'errors': helpers.adminerrorList(form,formsets),'app_label': opts.app_label,'preserved_filters': self.get_preserved_filters(request),} context.update(extra_context or {}) return self.render_change_form(request,context,form_url=form_url,add=True)解决方法 我没有完全处理你冗长的add_vIEw方法,但你的一般问题的答案只是“不”.管理员没有提供任何处理多层异构层次结构的好方法.通过内联很好地处理两层层次结构,因此您可以轻松地进行处理,以便通过编辑任何一层中的对象,您可以方便地管理下一层中的相关对象;但除此之外没什么.
多年来一直有a ticket开放为管理员添加嵌套内联支持,这将有助于处理这种情况.但是有许多棘手的边缘情况,并且很难使UI易于理解,因此补丁从未达到提交就绪状态.
在某些时候,您的数据模型的复杂性超出了通用管理界面可以处理的良好可用性,并且您最好只编写自己的自定义管理界面.主要是管理员只是建立在ModelForms和InlineModelFormsets之上,所以它并不像你想象的那样难以构建你自己的工作方式;与尝试大量定制管理员相比,它通常更容易(并且具有更好的结果).
我还应该提一下,通过表可以使用admin inlines多对多(即使through表是隐式的,而不是它自己的模型类),因为如何访问隐式创建的直通模型并不是很明显:
class MyM2MInline(admin.TabularInline): model = SomeModel.m2m_fIEld.through
@H_404_0@ 总结以上是内存溢出为你收集整理的python – Django很多很多和管理员全部内容,希望文章能够帮你解决python – Django很多很多和管理员所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)