Как я могу просто и эффективно создать связанный объект в Django 2.0+? - PullRequest
0 голосов
/ 24 апреля 2019

Я хотел бы найти простой и надежный способ создания дочернего объекта. Я думаю, что это простая проблема, вероятно, решаемая с помощью Django RelationshipManager или ссылки на связанные объекты.

Я заставил его работать в прошлом (заплатив кому-то по пятерке, чтобы он помог мне решить эту проблему), но я чувствую, что есть гораздо более простой метод, который избегает меня.

Это сработало на моем 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 новое посещение, связанное с этим человеком. Позже я покажу список посещений этого пациента (но не предмет этого вопроса).

Models.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})

forms.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-эй способ сделать вещи намного проще и надежнее. Я думаю, что мое решение должно быть найдено в Django RelationshipManager, но я не могу найти решение, которое работает. Я заплатил парню на Fiver, и я думаю, что он не понял это настолько просто, насколько это возможно.

Ответы [ 2 ]

2 голосов
/ 24 апреля 2019

Проверьте django InlineFormset: https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#inline-formsets

Если вы хотите иметь возможность динамически извлекать извлечение набора форм (на основе Jquery): https://github.com/elo80ka/django-dynamic-formset

Если вы используете представление на основе классов, вам нужно будет добавить inlineformset в get_context_data() и внутри form_valid() проверить, если formset.is_valid(), а затем сохранить его в базе данных.

РЕДАКТИРОВАТЬ: Вот код, основанный на вашем комментарии

forms.py

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

views.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)

models.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})
1 голос
/ 24 апреля 2019

Итак, ряд вещей, которые вы могли бы прояснить.

  1. instance.middelname = form.cleaned_data['middlename'] Никогда не будет работать, так как midllename неверно на стороне экземпляра.

  2. Вы можете использовать Main.objects.create(firstname=form.validated_data['firstname'], lastname= .... etc) для создания экземпляров вашей модели

  3. Вероятно, вы должны иметь отношение пользователя к вашим моделям через Main, а не Visit. Это позволит вам легче добавлять записи для посещения, например, регистрация посещений сотрудника вместо клиента.

  4. Вы должны искать CreateView, чтобы помочь вам с образцом создания экземпляра.

  5. Переименуйте основную модель. Что это на самом деле? Для меня это выглядит как Профиль, но называть его Главным не очень наглядно.

  6. Поле возраста должно быть целочисленным. Никто не "Дейв" лет.

...