2013-08-29 16 views
7

Jak podano here obiekty są tworzone automatycznie dla modeli z relacją OneToOne z innymi modelami. Więc jeśli mam Model1 z O2O do Modelu2 i utworzę obiekt Model2 z pk = 1, to obiekt Model1 z modelem2_id = 1 zostanie utworzony automa- tycznie. Następnie, jeśli Ill zrzuci dane z DB do json, będę miał dwa rekordy dla tych obiektów. A jeśli spróbuję załadować te dane do DB z loaddata - to się nie powiedzie, ponieważ obiekt dla Modelu 2 zostanie utworzony dwukrotnie i spowoduje to unikalne naruszenie indeksu i IntegrityError.
Czy ktoś znalazł na to rozsądne rozwiązanie?Oprawy Django i OneToOneField

p.s.
Używam Django 1.3.7

+0

znalazłeś rozwiązanie dla tego? –

+0

Zalecam aktualizację django, jeśli masz taką możliwość. – Alp

+4

Nie myśl, że będzie wiele obiektów w zrzutach danych lub utworzonych wiele razy. Czy możesz nam pokazać, jakie dane dump Ci daje? A także błąd danych loaddata? – Rohan

Odpowiedz

0

może skończyć się za pomocą Południe, co sprawia, migracje danych zarówno łatwe i wydajne:

http://south.readthedocs.org/en/latest/about.html

przychodzi z Django 1.6, nowa migrations module zastąpi starą bazę komendy i sprawiają, że Południe staje się przestarzałe.

+0

nadchodzi migracja z 1.7 ... Ale nie sądzę, że pomagają w tym przypadku (ani nie będzie na południe) – OBu

+0

czy możesz pokazać mi źródło, że migracje przychodzą z 1.7? – Alp

+1

Mieliśmy kilka dyskusji na ten temat na stronie https://code.djangoproject.com/ticket/21142, a tam jest projekt typu kickstarter stwierdzający to samo od południowego autora na stronie http://www.kickstarter.com/projects/andrewgodwin/schema -migrations-for-django. Przetestowałem to w wersji 1.7 alpha, ale ponieważ błąd wspomniany w pierwszym linku nie został w pełni rozwiązany, nie zadziałało to dla mnie. – OBu

4

Zrobiłem coś podobnego, nie tylko JSON, ale z xml, a moje django ma 1.7, więc może to nie działa dla ciebie.

  1. Możesz użyć natural keys, gdy odwołujesz się do serializowanych obiektów. Zapobiegnie to mieszaniu przedmiotów, jeśli indeks jest już używany przez inny obiekt.
  2. Możesz użyć numeru dependencies, aby określić kolejność serializacji (a więc deserializację).

Pomocne mogą być podobne wpisy, takie jak this one.

+0

W momencie, w którym to piszę, Django nie wypuściło jeszcze 1.6, więc myślę, że mogłeś błędnie wpisać numer wersji Django. –

+0

Nie, naprawdę używam najnowszego wydania alfa 1.7 – OBu

+1

BTW: 1.6 jest już gotowe! – OBu

0

Rzeczywiście, relacje O2O mogą być trudne, jeśli chcesz używać poleceń, takich jak dumpdata i loaddata, na przykład do tworzenia kopii zapasowych i przywracania wybranych obiektów w bazie danych.

Mamy podobny problem z naszym oprogramowaniem i odkryłem, że możliwym rozwiązaniem jest przesłonięcie metody save() pod numerem django.core.serializers.base.DeserializedObject, aby uzyskać uchwyt do momentu tuż przed zapisaniem "podwójnego" obiektu. W tym momencie możesz zdecydować się wyrzucić domyślną relację O2O stworzoną przez Django i pozwolić frameworkowi zapisać nowy lub zaktualizować go zapisanymi wartościami w pliku XML lub JSON.

Musiałbyś umieścić nadpisaną metodę gdzieś Django odbiera przed wykonaniem polecenia loaddata. Jedną z możliwości jest utworzenie własnego polecenia, które z kolei wywołuje loaddata. W module poleceń zainstalujesz zastąpienie. Podane są następujące szczegóły dotyczące tego rozwiązania:

  • Testowane z Django 1.8.x
  • Nasze O2O pole jest dołączony do Django User modelu
  • Dla uproszczenia w tym przykładzie, zadzwonię pole dołączony O2O Attached.

# Overrides deserialization to affect OneToOneFields for Users correctly 
import django.core.serializers.base 
from django.contrib.auth.models import User 
from your.attached.models import Attached #model with O2O field to User 

_original_save = django.core.serializers.base.DeserializedObject.save 

def save(self, *args, **kwargs): 

    if isinstance(self.object, Attached): 
    # if the user in question has an attached object, delete it 
    user = User.objects.get(pk=self.object.user_id) 
    if hasattr(user, 'attached'): user.attached.delete() 

    # use the built-in function for all other cases 
    _original_save(self, *args, **kwargs) 

django.core.serializers.base.DeserializedObject.save = save 

Możesz zmodyfikować kod powyżej, zamiast usuwania istniejącego obiektu, aktualizując go, jeśli, w klauzuli if hasattr(...), uniknąć usunięcia zaktualizować istniejący obiekt z wartości pochodzących z zserializowany obiekt i pomiń połączenie z numerem _original_save(). Sprawi to, że kod będzie nieco bardziej związany z modelem, ponieważ może być konieczne zdefiniowanie pól do aktualizacji na istniejącym obiekcie. Rozwiązanie przedstawione powyżej nie zakłada założenia co do zawartości modelu.