1

I'm having a problem hope you could help me please.

I got these models:

MODELS = (
('A', 'A'),
('B', 'B'),
)


class person(models.Model):
    nombre = models.CharField(max_length=128)
    model = models.CharField(max_length=128,choices=MODELS, default=True)

    def __str__(self):
        return self.nombre


class person_A(models.Model):
    person = models.ForeignKey(person, on_delete=models.PROTECT, null=True)
    hobbies = models.CharField(max_length=40, default='')

    def __str__(self):
        return self.person.nombre

class person_B(models.Model):
    person = models.ForeignKey(person, on_delete=models.PROTECT, null=True)
    age = models.IntegerField(default=10)

    def __str__(self):
        return self.person.nombre

As you can see I have person_A, person_B which will be saved in my database.

Here's my view:

def get_person(request):
    titulo = 'Person'
    qs_a = person_A.objects.all()
    qs_b = person_B.objects.all()
    qs = chain(qs_b,qs_a)
    form = person_aForm(request.POST or None)
    form2 = personForm(request.POST or None)
    form4 = person_bForm(request.POST or None)
    context = {
        "qs_a": qs_a,
        "qs_b": qs_b,
        "qs": qs,
        "form2": form2,
        "form": form,
        "form4": form4,
        "titulo": titulo,
    }
    form2_valid = form2.is_valid()
    form_valid = form.is_valid()
    form4_valid = form4.is_valid()
    if form2_valid:
        person = form2.save()
        if form_valid:
            person_a = form.save(commit=False)
            person_a.person = person
            person_a.save()
            messages.success(request, 'Se ha guardado satisfactoriamente')
            return redirect("get_person")
        if form4_valid:
            person_b = form4.save(commit=False)
            person_b.person = person
            person_b.save()
            messages.success(request, 'Se ha guardado satisfactoriamente')
            return redirect("get_person")
    return render(request, "person.html", context)

Here as you can see is being saved my form for person_A or person_B.

Here's my delete function:

def delete_person(request,id):
    try:
        qs = person_B.objects.all()
        instance = get_object_or_404(qs, id=id)
        instance.delete()
        messages.success(request, 'B')
    except:
        try: 
            qs = person_A.objects.all()
            instance = get_object_or_404(qs, id=id)
            instance.delete()
            messages.success(request, 'A')
        except:
            pass
    return redirect('get_person')

My url:

url(r'^delete_person/(?P<id>\d+)/$',views.delete_person, name='delete_person'),

Template:

<table class="table table-hover">
    <thead>
      <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Last Name</th>
        <th>Delete</th>
      </tr>
    </thead>
    <tbody>
    {% for item in qs  %}
      <tr>
        <td>{{ item.id }}</td>
        <td>{{ item.person.model }}</td>
        <td>{{ item.person.nombre }}</td>
        <td><a href="{% url 'delete_person' item.id %}">Delete</a></td>
      </tr>
    {% endfor %}
    </tbody>
</table>

Basically, I'm having two different models which everyone is being saved in the database and being shown in a table. To do that I used chain() from itertools. I joined Person A and Person B to show them both in one table. This is working fine, now here's my problem:

If person_A has the same id as person_B and I want to delete person_A, it will delete person_B instead. I know this is because of the chain() but i'd like to know if there's a possible way to solve this?

Thank you!

cegas
  • 2,823
  • 3
  • 16
  • 16
User100696
  • 687
  • 4
  • 12
  • 26

1 Answers1

1

Your problem lies in the fact that delete_function() always tries to delete person_B first. Unless an exception is thrown, person_A will never be deleted. If an exception is thrown, you will still delete person_B first, since it is inside try: block, hence an attempt to delete it always precedes an attempt to delete person_A. By the way, the way your code is written now, any exception will result in an attempt to delete person_A. I would suggest using a more specific exception, or otherwise you might run into really confusing bugs later on.

As for the solution, I'm sure there are more clever ways out, but couple of quick-and-dirty solutions I can think of right now:

  1. Defining a custom filter, which would check what type of class the person is and act accordingly (e.g., call different delete methods for different classes; pass a flag as query parameter and use it in the delete_person() method to determine which person_ to delete).
  2. What I would probably do: instead of chaining instances of models, iterate over them separately and call delete methods suited for a specific model:

     <table>
     <thead>...</thead>
     <tbody>
       ...
       {% for item in qs_a %}
         <tr>
           <td>... delete_person_A() ...</td>
         </tr>
       {% endfor %}
       {% for item in qs_b %}
         <tr>
           <td>... delete_person_B() ...</td>
         </tr>
       {% endfor %}
     </tbody>
     </table>
    

    If I recall correctly, chain() iterates over first iterable until it is exhausted, and only then does it iterate over the second one. Hence, iterating over the qs_a and qs_b separately should not make a huge difference in the output. While this way you will have to write slightly more code, it will also be a bit more simple and explicit - hence, easier to understand and refactor later, if there is a need.

Community
  • 1
  • 1
cegas
  • 2,823
  • 3
  • 16
  • 16