我想找到一种创建子对象的简单而可靠的方法。我认为这是一个简单的问题,可能使用Django RelationshipManager或Related Objects引用解决了。
过去我已经开始使用它了(通过付钱给fiver的人来帮助我解决这个问题),但是我觉得有一种更简单的方法可以使我逃脱。
这适用于我的 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-ey方法可以使工作更简单,更可靠。我认为应该在Django RelationshipManager中找到我的解决方案,但找不到有效的解决方案。我在Fiver上付了一个钱,我认为他没有把这个变得尽可能简单。
答案 0 :(得分:2)
检查django InlineFormset:https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#inline-formsets
如果您需要负担添加一个删除表单集的动态检出(基于Jquery): https://github.com/elo80ka/django-dynamic-formset
如果您使用的是基于类的视图,则必须在get_context_data()
和form_valid()
内添加inlineformset,检查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 :(得分:1)
因此,您可以清除其中的许多内容。
instance.middelname = form.cleaned_data['middlename']
永远不会起作用,因为实例名上的中间名不正确。
您可以使用Main.objects.create(firstname=form.validated_data['firstname'], lastname= .... etc)
创建模型实例
您应该应该通过Main而不是Visit来将User与模型之间的关系。这将使您可以更轻松地添加“拜访”记录,例如,员工记录拜访记录而不是客户。
您应该查找CreateView来帮助您创建实例。
重命名主模型。到底是什么对我来说,它看起来像个人资料,但称其为Main并不是很好的描述。
年龄应为整数字段。没有人是“戴夫”岁。