首页 > 解决方案 > Django 更新/创建架构

问题描述

我已经为自己找到了一种方法来创建和更新我的 Django 模型。但我想知道这是否是正确的方法。假设我们有两个模型 A 和 B,其中一个 A 可以有多个 B。

这里 B 有两个用户输入 b1、b2 和“b3”定义为:b3 = b1 + b2

这里 A 也有两个用户输入字段 a1、a2 和“a3”定义为:a3 = a1 + a2 + b[0].b3 + b[1].b3 + ... + b[N].b3

这里A取决于零个或多个B。如果 B 的其中一项发生更改,则 A 将需要重新计算它的 a3 字段。

因此,A 和 B 模型定义为:

class A(models.Model):
    a1      = models.FloatField(default=0)
    a2      = models.FloatField(default=0)
    a3      = models.FloatField(default=0)

    @classmethod
    def create( cls, a1, a2):
        a   = cls(a1  = a1, a2  = a2)
        return a

    def set_a(self, a):
        a.a3 = a.a1 + a.a2

        bs = B.objects.filter(a=a)
        for b in bs:
            a.a3 += b.b3
        a.save()
        return a

class B(models.Model):
    a       = models.ForeignKey('a.A', related_name='bs', on_delete=models.CASCADE)
    b1      = models.FloatField(default=0)
    b2      = models.FloatField(default=0)
    b3      = models.FloatField(default=0)

    @classmethod
    def create( cls, a, b1, b2):
        b   = cls(  a = a, b1  = b1, b2  = b2)
        return b

    def set_b(self, b):
        b.b3 = b.b1 + b.b2
        b.save()
        b.a.set_a(b.a)
        return b

“a”应用程序的创建和更新视图是:

class ACreateView(LoginRequiredMixin, CreateView):
    model = A
    template_name = 'a/create.html'
    form_class = AForm

    def form_valid(self, form):
        a = A.create(   a1      = form.cleaned_data['a1'],
                        a2      = form.cleaned_data['a2'])
        a = a.set_a(a)
        return HttpResponseRedirect(reverse('a:detail', args=(a.id,)))


class AUpdateView(LoginRequiredMixin, UpdateView):
    model = A
    template_name = 'a/detail-update.html'
    form_class = AForm

    def get_object(self):
        return get_object_or_404(A, pk=self.kwargs['pk_a'])

    def form_valid(self, form):
        a = self.get_object()
        a.a1        = form.cleaned_data['a1']
        a.a2        = form.cleaned_data['a2']
        a = a.set_a(a)
        return HttpResponseRedirect(reverse('a:detail', args=(a.id,)))    

现在的问题是这是正确的方法吗?在 set_a(a) 函数中使用 save() 命令是否正确?它似乎适用于这个非常简单的例子,但如果模型增加,那么复杂性就会增加,这种方法可能不再可行......

标签: djangoarchitecture

解决方案


另一种可能更优雅的方法是将 a3 和 b3 定义为属性,而不是将它们存储在数据库中。这样 a3 和 b3 会在需要时立即计算出来。B 模型的 b1 和 b2 字段的更新将立即导致 a3 属性的新更新值。

当然,缺点是我们不能(轻松)在数据库中查询 a3 和 b3,因为它们没有存储在数据库中。

A 模型被定义为:

from django.db import models
from b.models import B

class A(models.Model):
    a_name  = models.CharField(max_length=200)
    a1      = models.FloatField(default=0)
    a2      = models.FloatField(default=0)

    @classmethod
    def create( cls, a_name, a1, a2):
        a   = cls(  a_name = a_name, a1  = a1, a2  = a2)
        b1 = B.create(a = a, b_name = "auto_created_b1", b1 = 999, b2=0)
        return a

    @property
    def a3(self):
        a3 = self.a1 + self.a2
        bs = B.objects.filter(a=self)
        for b in bs:
            a3 += b.b3
        return a3

    def get_absolute_url(self):
        return reverse('a:detail', kwargs={'pk_a':self.id })

A 模型的更新和创建视图是:

class ACreateView(LoginRequiredMixin, CreateView):
    model = A
    template_name = 'a/create.html'
    form_class = AForm

    def form_valid(self, form):
        a = A.create(   a_name  = form.cleaned_data['a_name'],
                        a1      = form.cleaned_data['a1'],
                        a2      = form.cleaned_data['a2'])
        a.save()
        return HttpResponseRedirect(reverse('a:detail', args=(a.id,)))

class AUpdateView(LoginRequiredMixin, UpdateView):
    model = A
    template_name = 'a/detail-update.html'
    form_class = AForm

    def get_object(self):
        return get_object_or_404(A, pk=self.kwargs['pk_a'])

    def form_valid(self, form):
        a = self.get_object()
        a.a_name    = form.cleaned_data['a_name']
        a.a1        = form.cleaned_data['a1']
        a.a2        = form.cleaned_data['a2']
        a.save()
        return HttpResponseRedirect(reverse('a:detail', args=(a.id,)))    

推荐阅读