我试图弄清楚Django如何理解m2m关系,在SQL中,您只需在中间表中添加一些联接即可。
我有一个包含各种样品的容器。样本可以散布在各种容器中。
因此,在我的容器中,我添加了一个别名样本m2m字段(本质上是另一个表的书签)。
我能做的是获得一个容器并显示表单信息,我想将Sample列添加到表单中,如果我对samples m2m字段执行此操作,它将返回一个多字段,但是我如何访问通过m2m的其他相关字段sample_id> = 在我的示例表中,我添加了容器别名,以充当另一个表的书签 在这种情况下,我要管理通过表: 所以现在我想通过表单显示单个容器的内容。我已经设置了网址以传递container_id。 表格 样本似乎列出了所有内容,而与容器无关。 然后是HTML 传递给:class Container(models.Model):
container_id = models.AutoField(primary_key=True)
samples = models.ManyToManyField(Sample, through='JoinSampleContainer', through_fields=('container_id', 'sample_id'), related_name='container')
location_id = models.ForeignKey(Location, db_column='location_id', on_delete = models.PROTECT)
icon_desc = models.ForeignKey(Icon, db_column='icon_desc', null=True, blank=True, default='Box',on_delete = models.PROTECT)
container_name = models.CharField(max_length=50, blank=True, null=True)
container_type = models.CharField(max_length=50, blank=True, null=True)
class Sample(models.Model):
sample_id = models.AutoField(primary_key=True)
containers = models.ManyToManyField(Container, through='JoinSampleContainer', through_fields=('sample_id', 'container_id'), related_name='sample')
sample_number = models.IntegerField()
material_type = models.CharField(max_length=200, default='', blank=True, null=True, choices = MATERIALS)
weight = models.DecimalField(max_digits=6, decimal_places=2)
description = models.CharField(max_length=500, default='', blank=True, null=True)
recovery_method = models.CharField(max_length=200, default='', blank=True, null=True, choices = RECOVERY_METHODS)
comments = models.CharField(max_length=1000, default='', blank=True, null=True)
class JoinSampleContainer(models.Model):
id = models.AutoField(primary_key=True)
container_id = models.ForeignKey(Container, db_column='container_id', on_delete = models.PROTECT)
sample_id = models.ForeignKey(Sample, db_column='sample_id', on_delete = models.PROTECT)
# views.py
def containercontents(request, pk):
post = get_object_or_404(Container, pk=pk)
# objects = Container.samples.all()
if request.method == "POST":
form = ContainerContentsForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
#post.user = request.user
#post.datetime = datetime.datetime.now()
post.save()
return redirect('allcontainer')
#, pk=post.pk)
else:
form = ContainerContentsForm(instance=post)
return render(request, 'container/containercontents.html', {'form': form})
# form.py
class ContainerContentsForm(forms.ModelForm):
class Meta:
model = Container
fields = (
'location_id',
'container_name',
'container_type',
'icon_desc',
'samples',
)
# html
<a href="{% url 'containercontents' pk=container.pk %}" class="btn btn-primary" role="button">contents</a>
# html
<div class="">
{{ form }}
</div>
答案 0 :(得分:0)
您的模型定义错误:您不应在两个模型上都定义ManyToManyField
,而只能在其中一个模型上定义。因此,请删除containers
上的Sample
字段,仅将其保留在Container
上。将related_name
设置为“容器”(复数)。这样,关系Container
-> Sample
为container.samples.all()
,相反的关系为sample.containers.all()
。
现在,表单的用途是允许您选择要与Sample
关联的Container
。因此,默认情况下,该字段将由ModelMultipleChoiceField
表示。使用Sample
实例初始化表单时,应预先选择已经关联的Container
。
您可以通过为字段指定queryset
并覆盖以下格式的默认字段来缩小样本范围:
class ContainerContentsForm(forms.ModelForm):
class Meta:
# same code here
samples = forms.ModelMultipleChoiceField(
queryset = Sample.objects.filter(...)
)
您说要“通过表单显示Container
的内容”,如果只想显示,为什么要使用表单?要仅显示内容,请循环浏览相关样本并显示它们:
{% for sample in form.instance.samples.all %}
{{ sample.sample_id }}
{% endfor %}
注意:您应该将ID重命名为id
。 sample.sample_id
是不好的编程风格。但是我已经告诉过你了。