Реализация m2m django после обучения - PullRequest
1 голос
/ 17 апреля 2019

Сценарий: у меня есть несколько ящиков (контейнеров). У меня есть несколько объектов (образцов), образец может быть разбит на несколько ящиков, в одном ящике может быть много образцов.

Я хочу иметь возможность назначить образец для коробки и удалить образец из коробки.

Я следовал этим учебникам 57-59 , назначая друзей пользователям, и заставлял его работать.

Итак, я сейчас пытаюсь адаптировать код, поэтому мне нужно изменить пользователей на ящики / контейнеры и друзей на образцы. Звучит достаточно просто. Но я неопытен в причудах Джанго и где request.user, я не могу получить правильный синтаксис. Итак, вот код, сначала код, работающий из учебника, а затем моя попытка его рефакторинга.

У меня есть 2 другие таблицы / модели Containers и Sample, в которые помещается модель ContainerContent.

# 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>
...

Ниже моя попытка:

# 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'),

Я подозреваю, что мне нужно передать идентификатор контейнера здесь, иначе не будет никакого различия между контейнерами.

# 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>
...       

--- Обновление ---

Я должен был включить представление, которое генерирует страницу, а не пользователи / друзья все еще содержатся в ней и будут удалены, как только я получу ее работу.

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,

    })

Ответы [ 2 ]

1 голос
/ 17 апреля 2019

Вы не ссылаетесь на поле 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')
1 голос
/ 17 апреля 2019

Это должно вызвать проблемы, потому что 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)

Поскольку образец является полем ManyToMany, устанавливающим соединение между CurrentContainer и Sample моделью.

Обновление 2

@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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...