首页 > 解决方案 > 如何在 Django 2.0+ 中简单有效地创建相关对象?

问题描述

我想找到一种简单而可靠的方法来创建子对象。我认为这是一个简单的问题,可能使用 Django 关系管理器或相关对象引用来解决。

我过去已经让它工作了(通过支付某人的费用来帮助我解决这个问题),但我觉得有一种更简单的方法可以让我逃脱。

这对我的views.py有效

class MainVisitForm(SingleObjectMixin, FormView):
    template_name = "clincher/visit_form.html"
    form_class = VisitForm
    model = Main

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        self.object = self.get_object()



        form=self.get_form()
        form.fk_visit_user = self.request.user
        form.fk_visit_main = Main.objects.get(id=self.kwargs['pk'])
        #added this to save form as we are mixxing the two forms and Models
        # as the approch of singleObjectMixin is we should get object from DB as per request url as a primary key
        #and we have defined  model as a Main but taking the form view of VistForm as the probem occures
        # as i think


        if form.is_valid():
            instance = Main()
            instance.firstname = form.cleaned_data['firstname']
            instance.middelname = form.cleaned_data['middlename']
            instance.lastname = form.cleaned_data['lastname']
            instance.date_of_birth = form.cleaned_data['date_of_birth']
            instance.sex = form.cleaned_data['sex']

            instance.address = form.cleaned_data['address']
            instance.save()

        return super().post(request, *args, **kwargs)


    def get_success_url(self):
        return reverse('clincher:main_detail', kwargs={'pk': self.object.pk})

基本上,当用户在“主”对象的详细信息页面中时,我希望他们能够创建一个子对象(访问对象)。最终 1 名患者将进行多次就诊(1:m 关系)。每次患者访问该文档时,将添加 1 次与该人相关的新访问。稍后,我将显示该患者的就诊列表(但不是此问题的主题)。

模型.py

class Main(models.Model):
    firstname = models.CharField(max_length = 256, verbose_name=('First Name'))
    middlename = models.CharField(max_length=256, verbose_name=('Middle Name'))
    lastname = models.CharField(max_length=256, verbose_name=('Last Name'))
    date_of_birth = models.DateField()
    age = models.CharField(max_length=4)
    sex_list = (
        (str(1), 'Female'),
        (str(2), 'Male'),
        (str(3), 'Other'),
        (str(4), 'Unknown'),)
    sex = models.CharField(max_length = 24, choices=sex_list, verbose_name='Sex')
    address = models.TextField(max_length = 256)

    @property
    def full_name(self):
        #"Returns the person's full name."
        return '%s %s' % (self.firstname, self.lastname)

    #Redirects after form is submitted using primary key
    def get_absolute_url(self):
        return reverse('clincher:main_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return self.firstname + ' ' + self.lastname +' - ' + str(self.date_of_birth)




class Visit(models.Model):
    fk_visit_main = models.ForeignKey(Main, on_delete=models.CASCADE, verbose_name=('Patient Name'))
    visit_date = models.DateField(auto_now = True, editable=True)
    fk_visit_user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name=('Practitioner'), max_length=500)
    visit_label = models.CharField(max_length=256, blank=True, null=True)
    visit_type = models.CharField(
        max_length=256,
        default=1, verbose_name='Type of Visit')
    visit_progress_notes = models.TextField(max_length=10000,
                                   blank=True, verbose_name='Progress Notes')
    outcomes = models.BooleanField(default=False)

    def __str__(self):
        return '%s %s' % (self.visit_date, self.visit_label)

    def get_absolute_url(self):
        return reverse('clincher:main_detail', kwargs={'pk': self.pk})

表格.py

class VisitForm(forms.Form):
    visit_types_list = (
        (str(1), 'Consultation'),
        (str(2), 'Procedure'),
        (str(3), 'Administrative'),)
    visit_type = forms.ChoiceField(choices=visit_types_list)
    visit_label = forms.CharField(label='Visit Label', max_length=100)
    progress_note = forms.CharField(widget=forms.Textarea)

    def form_valid(self, form):
        form.instance.fk_visit_user = self.request.user
        form.instance.fk_visit_main = Main.objects.get(id=self.kwargs['pk'])
        return super().form_valid(form)

因此,我应该最终得到一个具有父对象主键的子记录/对象。

上面的代码有效,但我确信有一种简单的 Django-ey 方式可以更简单、更健壮地做事。我认为我的解决方案应该在 Django 关系管理器中找到,但我找不到有效的解决方案。我在 Fiver 上付钱给一个人,我认为他没有尽可能简单地做到这一点。

标签: djangodjango-modelsdjango-formsdjango-views

解决方案


检查 django InlineFormset:https ://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#inline-formsets

如果您希望能够添加删除表单集动态结帐(基于 Jquery): https ://github.com/elo80ka/django-dynamic-formset

如果您使用基于类的视图,则必须在其中添加 inlineformsetget_context_data()form_valid()检查是否存在formset.is_valid(),然后将其保存到数据库中。

编辑:这是基于您的评论的代码

表格.py

class VisitForm(forms.ModelForm);
    class Meta:
        model = Visit
        fields = [
            'visit_type',
            'visit_label',
            'visit_progress_notes'
        ]

视图.py

class CreateVisitView(CreateView):
    model = Visit
    form_class = VisitForm
    template_name =  "clincher/visit_form.html"

    #one of the first function called in class based view, best place to manage conditional access
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        return super(CreateVisitView,self).dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        visit = form.save(commit=False)
        visit.fk_visit_user = self.request.username
        visit.fk_visit_main = get_object_or_404(Main, pk=self.kwargs.get('pk'))
        visit.save()

        return super(CreateVisitView,self).form_valid(form)

模型.py

    class Main(models.Model):
        SEX_LIST_CHOICE = (
            (str(1), 'Female'),
            (str(2), 'Male'),
            (str(3), 'Other'),
            (str(4), 'Unknown'),
        )

        firstname = models.CharField(max_length = 256, verbose_name=('First Name'))
        middlename = models.CharField(max_length=256, verbose_name=('Middle Name'))
        lastname = models.CharField(max_length=256, verbose_name=('Last Name'))
        date_of_birth = models.DateField()

        age = models.PositiveSmallIntegerField()

        sex = models.CharField(max_length = 24, choices=SEX_LIST_CHOICE, verbose_name='Sex')
        address = models.TextField(max_length = 256)

        @property
        def full_name(self):
            #"Returns the person's full name."
            return '%s %s' % (self.firstname, self.lastname)

        #Redirects after form is submitted using primary key
        def get_absolute_url(self):
            return reverse('clincher:main_detail', kwargs={'pk': self.pk})

        def __str__(self):
            return self.firstname + ' ' + self.lastname +' - ' + str(self.date_of_birth)



class Visit(models.Model):
    VISIT_TYPE_CHOICE = (
        (str(1), 'Consultation'),
        (str(2), 'Procedure'),
        (str(3), 'Administrative'),)

    fk_visit_main = models.ForeignKey(Main, on_delete=models.CASCADE, verbose_name=('Patient Name'))
    visit_date = models.DateField(auto_now = True, editable=True)
    fk_visit_user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name=('Practitioner'), max_length=500)
    visit_label = models.CharField(max_length=256, blank=True, null=True)
    #you are storing the type of visit as an 
    visit_type = models.CharField(
        max_length=256,
        default=1,
        verbose_name='Type of Visit',
        choices=VISIT_TYPE_CHOICE
    )
    visit_progress_notes = models.TextField(max_length=10000,
                                   blank=True, verbose_name='Progress Notes')
    outcomes = models.BooleanField(default=False)

    def __str__(self):
        return '%s %s' % (self.visit_date, self.visit_label)

    def get_absolute_url(self):
        return reverse('clincher:main_detail', kwargs={'pk': self.pk})

推荐阅读