Mam dość tajemniczy multiObjectsReturned borl, który właśnie pojawił się po tygodniach nie posiadania problemu. Mam nadzieję, że brakuje mi czegoś prostego.

Mam model Order, model OrderLine, który ma klucz obcy Item. Każda Item ma klucz obcy do Product. Oto ukryte modele:

class OrderLine(models.Model):
    order = models.ForeignKey(Order, related_name="lines", on_delete=models.CASCADE)
    item = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True)


class Product(TimeStampedModel):
   ...


class Item(TimeStampedModel):
   product = models.ForeignKey(Product, related_name='items', on_delete=models.CASCADE)

Zamówienie i zamówienie Przeznaczenie w celach informacyjnych:

class OrderLineForm(forms.ModelForm):
    class Meta:
        model = OrderLine
        ...

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['category'].queryset = ItemType.objects.all()
        self.fields['product'].queryset = Product.objects.none()
        self.fields['item'].queryset = Item.objects.none()

        if self.instance.pk:
            try: # When changing an existing OrderLine
                ...
                current_item = Item.objects.filter(pk=self.instance.item.pk)
                available_items = current_item.union(
                    get_available_items(...)
                )
                self.fields['item'].queryset = available_items
                self.fields['category'].initial = item_type_id
            except:
                self.fields['item'].queryset = Item.objects.all()
        ...


@admin.register(OrderLine)
class OrderLineAdmin(admin.ModelAdmin):
    form = OrderLineForm

Teraz, gdy używam admin Django, aby edytować OrderLine, który ma więcej niż jeden Item w ModelChoicefield QuerySet: Wpisz opis obrazu tutaj

Otrzymuję następujący błąd podczas czystego formularza: get() returned more than one Item -- it returned 2!

Po bliższej kontroli logów pojawia się ModelChoiceField jest przekazywany poprawnie Item id / pk, ale {x2}} jest jakoś powracając 2 elementy z pojedynczego ID / PK, chociaż Elementy mają różne ID / PKS (49 i 50): Wprowadź opis obrazu tutaj

Ponownie, to dzieje się tylko wtedy, gdy pole OrderLine {{x x}} ma więcej niż jeden obiekt w zapytaniu. Jeśli to tylko pojedynczy Item, oszczędza dobrze. Jakieś pomysły, dlaczego teraz otrzymuję ten błąd? Dzięki!

Jedyną rzeczą, jaką mogę wymyślić, zmieniło się pod względem relacji z bazą danych, jest to, że dodałem formset.save_m2m() do administratora modelu, jednak pozycja nie jest relacją M2M, więc być może mogłoby doprowadzić do niektórych błędów indeksowania bazy danych?

Str.s. Znalazłem to https://code.djangoproject.com/ticket/23354 z lat temu to Wydaje się odnieść się do błędu w tym kontekście, ale bilet powiedział, że został naprawiony.

0
Peter 14 kwiecień 2021, 20:18

1 odpowiedź

Najlepsza odpowiedź

Z tych dwóch linii widzimy, że wykonujesz związek i ustawiasz to jako pól QuerySet:

current_item = Item.objects.filter(pk=self.instance.item.pk)
available_items = current_item.union(
    get_available_items(...)
)

Z Dokumentacja na union:

Ponadto, tylko limit , , , liczyć (*) , zamówienie przez , oraz określenie kolumn (I.e. Krajanie, Count () , istnieje () , Zamów_by () , i wartości () / wartości_listów () <) ) są dozwolone na wynikowym queryset . Ponadto bazy danych umieszczają ograniczenia na temat tego, co Operacje są dozwolone w połączonych zapytaniach. Na przykład najbardziej Bazy danych nie zezwalają na offset lub lub w połączonych zapytaniach.

Biorąc pod uwagę, że pole zadzwoni do get na tym zapytaniu w celu zatwierdzenia wybranego wyboru Unia nie jest dla niego możliwa. Biorąc pod uwagę przypadek użytkowania w rzeczywistości istnieje lepsza opcja dla nas, używając operatora SQL lub . Istnieje głównie 2 sposoby na to:

  1. Użyj {x0}} Ogólnorator:

     available_items = current_item | get_available_items(...)
    

    Jest to odpowiednik mówienia SELECT ... WHERE (condition for current item) OR (conditions for available items).

  2. Użyj {x0}} Obiekty:

    Poprzednia metoda nie była bardzo duża, biorąc pod uwagę, że możemy prosić o zapytań mający dość złożone warunki. Doprowadziłoby to do nas pisząc kilka queryset, a następnie przy użyciu | i & na nich. Zamiast tego mamy świetną opcję przy użyciu obiektów Q, które mogą przyjmować jako argumenty słowowości

     from django.db.models import Q
    
    
     available_items = Item.objects.filter(Q(pk=self.instance.item.pk) | Q(some_condition_for_available=True))
    
0
Abdul Aziz Barkat 15 kwiecień 2021, 03:51