Scenario: I have some boxes (containers) I have some objects (samples) a sample can be split over many boxes, a box can contain many samples.
I want to be able to assign a sample to a box and remove a sample from a box.
I followed these tutorials 57-59, assigning friends to users, and got it working.
So I now try to adapt the code, so I need to change users to boxes/containers and friends to samples. Sounds simple enough. But I'm inexperienced with the quirks of Django and where the request.user
is I can't seem to get the correct syntax. So here comes the code, first the code working from the tutorial, then my attempt at refactoring it.
I have 2 other tables/models Containers and Sample which the ContainerContent model fits inbetween.
# models.py (tutorial)
class Friend(models.Model):
users = models.ManyToManyField(User)
current_user = models.ForeignKey(User, related_name='owner', null=True, on_delete = models.PROTECT)
# container_id = models.ForeignKey(Container, null=True, on_delete = models.PROTECT)
@classmethod
def make_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user=current_user
)
friend.users.add(new_friend)
@classmethod
def lose_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user=current_user
)
friend.users.remove(new_friend)
# views.py
def change_friends(request, operation, pk):
friend = User.objects.get(pk=pk)
if operation == 'add':
Friend.make_friend(request.user, friend)
elif operation == 'remove':
Friend.lose_friend(request.user, friend)
return redirect('depot:allcontainer')
#urls.py
url(r'^container/(?P<operation>.*)/(?P<pk>\d+)/$', views.change_friends, name='change_friends'),
#html
...
<tbody>
{% for user in users %}
<tr>
{% if user not in friends %}
<!-- we will want to add an if stmt list if not in unassigned - need to think how to do this -->
<td>{{ container.container_id }}</td>
<td>{{ user.username }}</td>
<td> <a href="{% url 'depot:change_friends' operation='add' pk=user.pk %}" class="badge badge-primary" role="button">
<!-- container=container.container_id -->
<!-- container=container.container_id -->
<!-- <button type="button" class="btn btn-success">add</button> -->
>>
</a></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
...
...
<tbody>
<tr>
{% for friend in friends %}
<td><a href="{% url 'depot:change_friends' operation='remove' pk=friend.pk %}" class="badge badge-primary" role="button">
<<
</a></td>
<td>{{ friend.username }}</td>
</tr>
{% endfor %}
</tbody>
...
Below is my Attempt:
# models.py
class ContainerContents(models.Model):
sample = models.ManyToManyField('Sample')
current_container = models.ForeignKey(Container, null=True, on_delete = models.PROTECT)
@classmethod
def add_to_container(cls, current_container, new_sample):
sample, created = cls.objects.get_or_create(
current_container=current_container
)
sample.add(new_sample)
@classmethod
def remove_from_container(cls, current_container, new_sample):
sample, created = cls.objects.get_or_create(
current_container=current_container
)
sample.remove(new_sample)
# views.py - this one is causing me issues, the request.____
def change_container(request, operation, pk, fk='', sample_id=''):
container = Container.objects.get(pk=pk)
sample = Sample.objects.get(pk=fk)
# sample = Container.objects.get(container.sample_id=sample_id)
if operation == 'add':
ContainerContents.add_to_container(request.container, container)
elif operation == 'remove':
ContainerContents.remove_from_container(request.container, container)
return redirect('depot:allcontainer')
# urls.py
url(r'^change_container/(?P<operation>.*)/(?P<pk>\d+)/sample/(?P<fk>\d+)$', views.change_container, name='change_container'),
I suspect I need to pass the container id here otherwise there will not be any distinction between the containers.
# html
<tbody>
{% for unassigned in container_contents %}
<tr>
<!-- { if user not in friends } -->
<!-- we will want to add an if stmt list if not in unassigned - need to think how to do this -->
<td>{{ unassigned.area_easting }}.
{{ unassigned.area_northing }}.
{{ unassigned.context_number }}.
{{ unassigned.sample_number }}</td>
<td>{{ unassigned.sample_id }}</td>
<td></td>
<td> <a href="{ url 'depot:change_friends' operation='add' pk=user.pk }" class="badge badge-primary" role="button">
<!-- container=container.container_id -->
<!-- container=container.container_id -->
<!-- <button type="button" class="btn btn-success">add</button> -->
>>
</a></td>
<!-- { endif } -->
</tr>
{% endfor %}
</tbody>
...
...
<tbody>
<tr>
{% for contents in container_contents %}
<td><a href="{% url 'depot:change_container' operation='remove' pk=container.container_id fk=contents.sample_id %}" class="badge badge-primary" role="button">
<!-- <button type="button" class="btn btn-default">remove</button> -->
<<
</a></td>
<td>{{ contents.sample_id }}</td>
<td>{{ contents.area_easting }}.
{{ contents.area_northing }}.
{{ contents.context_number }}.
{{ contents.sample_number }}</td>
</tr>
{% endfor %}
</tbody>
...
--- Update ---
I should have included the view that generates the page, not the users/friends is still contained in it and will be removed once I get it working.
def detailcontainer(request, container_id):
container = get_object_or_404(Container, pk=container_id)
samples = container.samples.all()
# allsamples = container.samples.exclude(sample_id=samples)
allsamples = container.samples.all()
users = User.objects.exclude(id=request.user.id).order_by('-id')
friend = Friend.objects.get(current_user=request.user)
friends = friend.users.all().order_by('-id')
container_contents = container.samples.all()
# container_contents = Container.objects.get(current_container=samples)
return render(request, 'container/detailcontainer.html',
{'container':container,
'samples':samples,
'allsamples': allsamples,
'users': users,
'friends': friends,
'container_contents': container_contents,
})
答案 0 :(得分:1)
这应该引起问题,因为request
没有任何名为container的属性。在您的教程示例中,它使用request.user
来已登录的用户,因为django(通过中间件)将登录的用户实例分配给了request
。
由于sample
视图方法中已经有container
和change_container
个对象,因此您可以尝试以下操作:
if operation == 'add':
ContainerContents.add_to_container(container, sample)
elif operation == 'remove':
ContainerContents.remove_from_container(container, sample)
缺少一件事,您还需要在add_to_container
和remove_from_container
方法内部进行更改:
@classmethod
def add_to_container(cls, current_container, new_sample):
container, created = cls.objects.get_or_create(
current_container=current_container
)
container.sample.add(new_sample)
@classmethod
def remove_from_container(cls, current_container, new_sample):
container, created = cls.objects.get_or_create(
current_container=current_container
)
container.sample.remove(new_sample)
因为示例是CurrentContainer
和Sample
模型之间的ManyToMany Field连接。
@classmethod
def remove_from_container(cls, current_container, new_sample):
from app_name.models import ContainerSample
c_sample = ContainerSample.objects.get(container=current_container, sample=new_sample)
c_sample.delete()
答案 1 :(得分:1)
您没有在获取的对象中引用您的m2m字段。您需要按如下所示处理sample
字段:
models.py:
@classmethod
def add_to_container(cls, current_container, new_sample):
containerContents, created = cls.objects.get_or_create(
current_container=current_container
)
containerContents.sample.add(new_sample)
@classmethod
def remove_from_container(cls, current_container, new_sample):
containerContents, created = cls.objects.get_or_create(
current_container=current_container
)
containerContents.sample.remove(new_sample)
并为模型方法设置适当的变量:
views.py
def change_container(request, operation, pk, fk='', sample_id=''):
container = Container.objects.get(pk=pk)
sample = Sample.objects.get(pk=fk)
# sample = Container.objects.get(container.sample_id=sample_id)
if operation == 'add':
ContainerContents.add_to_container(container, sample)
elif operation == 'remove':
ContainerContents.remove_from_container(container, sample)
return redirect('depot:allcontainer')