Problem z zapisywaniem modelu wykorzystującego multi table inheritance

17 views
Skip to first unread message

Kokos

unread,
May 21, 2012, 3:11:55 AM5/21/12
to djan...@googlegroups.com
Hej!

Postaram się krótko i zwięźle, mam taką hierarchię klas

class Common(models.Model):
    commonFieldA = ....
    commonFieldB = ...

    class Meta:
           abstract = True

class Entity(Common):
    efieldA = ...
    efieldB = ...
    efieldC = ...

class TypeZ(Entity):
   zfieldA = ...
   zfieldB = ...


czyli mamy abstract Common do Entity oraz multitable z Entity do TypeZ

teraz w widoku robię:
     tz = TypeZ()
     #from abstract common
     tz.commonFieldA = ...
     tz.commonFieldB = ...
     tz.commonFieldC = ...
     # from base Entity
     tz.efieldA = ...
     tz.efieldB = ..
     tz.efieldC = ...
     # typeZ fields
     tz.zfieldA = ..
     tz.zfieldB = ..

     tz.save()

I tu jest problem, gdyż po wywołaniu tz.save zapisują mi się dane do tabeli TypeZ, natomiast do tabeli Entity nie dodaje się żaden rekord. Może jestem ślepy, ale nie zauważyłem w dokumentacji żeby było napisane iż trzeba wykonać jakiś inny magiczny zestaw poleceń, także nie wiem o co chodzi... Czy ktoś wie jak rozwiązać ten problem?

 Dziwi mnie to że w ogóle można zapisać tabelę pochodną z kluczę null do Entity... (nie deklarowałem wlasnych kluczy, pozostawiłem to w całości django) ... gdyż jak dla mnie Django powinien w jakiś sposób wymusić zapisanie tabeli Entity, gdyż samo TypeZ nie powinno mieć rekordów nie powiązanych z Entity....

Rafał Stożek

unread,
May 21, 2012, 6:03:27 AM5/21/12
to djan...@googlegroups.com
Django zapisuje dane do Entity. Gdyby tego nie robiło, to dostałbyś IntegrityError (jeżeli używasz normalnego DBMS). Wniosek - coś spieprzyłeś, ale na podstawie podanych przez Ciebie danych ciężko będzie cokolwiek określić.


2012/5/21 Kokos <kosowsk...@gmail.com>

--
Otrzymujesz tę wiadomość, ponieważ subskrybujesz grupę dyskusyjną Google o nazwie „django-pl - grupa polskiej społeczności Django”.
Aby wyświetlić tę dyskusję w internecie, odwiedź stronę https://groups.google.com/d/msg/django-pl/-/0RQiPw0tDNsJ.
Aby zamieszczać posty w tej grupie, wyślij e-mail na adres djan...@googlegroups.com.
Aby anulować subskrypcję tej grupy, wyślij e-mail na adres django-pl+...@googlegroups.com.
Aby uzyskać więcej informacji, odwiedź tę grupę pod adresem http://groups.google.com/group/django-pl?hl=pl.

Kokos

unread,
May 21, 2012, 7:04:09 AM5/21/12
to djan...@googlegroups.com
Sprawdzałem w bazie (mysql) i są rekordy w tabeli Place a nie ma w Entity. Poniżej bardziej szczegółowy kod - jak jeszcze czegoś potrzeba to pisz a dokleję. części Ajaxowej do końca jeszcze nie łapię więc może się wydać śmieszna ale to temat na osobny wątek...

Poniżej kod (lub ---> http://pastebin.com/y0Jqa0t7 )
#====== model ====
class CommonInfo(models.Model):
    pluses = models.IntegerField()
    minuses = models.IntegerField()
    abuseCount = models.IntegerField()
    isArchive = models.BooleanField()

   
    class Meta:
        abstract = True

class Entity(CommonInfo):   
    PLACE = 0
    ROUTE = 1
    ENTITY_TYPES = (
                    (PLACE, 'Place'),
                    (ROUTE, 'Route'),
                    )
   
    entityType = models.IntegerField(choices = ENTITY_TYPES)
    userCreatedBy = models.ForeignKey(User, related_name='user_createdby', editable=False)
    dateCreated = models.DateField(editable=False)
    lastModified = models.DateField()
    lastModifiedBy = models.ForeignKey(User, related_name='user_lastModifiedBy')
    tags = models.ManyToManyField('Tag', blank=True, null=True)
   
    def __unicode__(self):
        return self.entityType

class Place(Entity):
    name = models.CharField(max_length=155)
    description = models.TextField()
    pType = models.ForeignKey(PlaceType)
    location = models.ForeignKey(Point)
   
#======================== form:
class AddPlaceForm(forms.Form):
    #POINT
    pointLat = forms.FloatField(label="Sz:", max_value=Decimal(90), min_value=Decimal(-90), error_messages={'required': 'Musisz podać szerokość geograficzną',
                                                                                                                                            'max_value':'Szerokość nie może być większa niż 90 stopni',
                                                                                                                                            'min_value':'Szerokość nie może być mniejsza niż -90 stioni',
                                                                                                                                            })
    pointLng = forms.FloatField(label="Dł:", max_value=Decimal(180), min_value=Decimal(-180))
    #PLACE
    placeName = forms.CharField(label="Nazwa:", min_length=1, max_length=255)
    placeDesc = forms.CharField(label="Opis:", widget=forms.Textarea())
    #TYPE
    placeType = forms.ModelChoiceField(label="Typ:", queryset=PlaceType.objects.all(), empty_label="(wybierz typ)")
    #TAGS
    placeTags = forms.ModelMultipleChoiceField(label="Tagi:", required=False, queryset=Tag.objects.all(), widget=forms.CheckboxSelectMultiple)
 
#====================== view:
def new_place_save_view(request):
    ajax = request.is_ajax()
    if request.method == 'POST':
        form = AddPlaceForm(request.POST)
        if form.is_valid():
            place = _new_place_save(form, request)
            return HttpResponseRedirect('/user/places/%d' % place.id )
    else:
        form = AddPlaceForm()
   
    variables = RequestContext(request, {'form': form })
    if ajax:
        return render_to_response('places/place_save.html', variables)
    else:
        return render_to_response('places/add_edit_place.html', variables)
           
def _new_place_save(p_form, request):
    p_point = Point(lat=p_form.cleaned_data['pointLat'], lng=p_form.cleaned_data['pointLng'])
    p_type = p_form.cleaned_data['placeType']
    tags = p_form.cleaned_data['placeTags']
   
    place = Place()
    place.name = p_form.cleaned_data['placeName']
    place.description = p_form.cleaned_data['placeDesc']
    place.pType = p_type
    #place.tags = tags
    place.entityType = Entity.PLACE
    place.abuseCount = 0
    place.pluses = place.minuses = 0
    place.dateCreated = datetime.datetime.now()
    place.lastModified = datetime.datetime.now()
   
    user = User.objects.get(username = request.user.username)
    place.userCreatedBy = user
    place.lastModifiedBy = user
   
    p_point.save()
    place.location = p_point
    place.save()
    place.tags = tags
    place.save()
    return place


2012/5/21 Kokos <kosowsk...@gmail.com>
Aby anulować subskrypcję tej grupy, wyślij e-mail na adres django-pl+unsubscribe@googlegroups.com.

Rafał Stożek

unread,
May 21, 2012, 7:14:30 AM5/21/12
to djan...@googlegroups.com
Wydaje mi się, że wszystko jest w porządku - i oczywiście nie używasz porządnego DBMS stąd brak wyjątku - jaka to wersja django?

2012/5/21 Kokos <kosowsk...@gmail.com>
Aby wyświetlić tę dyskusję w internecie, odwiedź stronę https://groups.google.com/d/msg/django-pl/-/CnsD-Bk4CtkJ.

Aby zamieszczać posty w tej grupie, wyślij e-mail na adres djan...@googlegroups.com.
Aby anulować subskrypcję tej grupy, wyślij e-mail na adres django-pl+...@googlegroups.com.

Kokos

unread,
May 21, 2012, 7:25:01 AM5/21/12
to djan...@googlegroups.com
MySQL był narzucony z góry że tak powiem ;) Django 1.3

Rafał Stożek

unread,
May 21, 2012, 7:47:49 AM5/21/12
to djan...@googlegroups.com
Możesz dla testu przerzucić pola z CommonInfo do Entity i zrobić tak, żeby Entity dziedziczyło bezpośrednio z models.Model?

2012/5/21 Kokos <kosowsk...@gmail.com>
Aby wyświetlić tę dyskusję w internecie, odwiedź stronę https://groups.google.com/d/msg/django-pl/-/5rJfM_ZOTggJ.

Aby zamieszczać posty w tej grupie, wyślij e-mail na adres djan...@googlegroups.com.
Aby anulować subskrypcję tej grupy, wyślij e-mail na adres django-pl+...@googlegroups.com.

Rafał Stożek

unread,
May 21, 2012, 7:49:34 AM5/21/12
to djan...@googlegroups.com
Także fajnie jakbyś podał zawartość django.db.connection.queries zaraz po zapisie do bazy.

2012/5/21 Rafał Stożek <say...@gmail.com>

Kokos

unread,
May 21, 2012, 7:53:39 AM5/21/12
to djan...@googlegroups.com
hmm a jak to wyciągnąć - którędy można się do tego dobrać? (to jest moje pierwsze podejście do Django więc nie wiem ;) )

Rafał Stożek

unread,
May 21, 2012, 7:59:14 AM5/21/12
to djan...@googlegroups.com
Gdzieś w widoku po save:

from django.db import connection
print "==========================================="
print connection.queries
print "==========================================="

Wypluje wszystko tam gdzie odpaliłeś runserver.

Skoro to twoje pierwsze podejście do django, to:
a) Używasz widoków-funkcji, podczas gdy w django 1.3 wprowadzono class based views
b) render_to_response i całe zamieszanie z context variables jest niepotrzebne. Sprawdź TemplateResponse.
c) Pola modelu zwyczajowo nazywa_sie_w_taki_sposob (nieWTaki)
d) Sprawdź ModelForm, nie będziesz musiał robić formularzy dla każdego modelu ręcznie.


2012/5/21 Kokos <kosowsk...@gmail.com>
Aby wyświetlić tę dyskusję w internecie, odwiedź stronę https://groups.google.com/d/msg/django-pl/-/MWus3xCSIsIJ.

Aby zamieszczać posty w tej grupie, wyślij e-mail na adres djan...@googlegroups.com.
Aby anulować subskrypcję tej grupy, wyślij e-mail na adres django-pl+...@googlegroups.com.

Kokos

unread,
May 21, 2012, 8:04:05 AM5/21/12
to djan...@googlegroups.com
Dzięki za porady! Aktualnie jestem w pracy, ale jak tylko będę miał chwilę przetestuję i wkleję wyniki.

co do nazewnictwa to moje przyzwyczajenie z C#, model Form znam, ale akurat w tym wypadku nie pasował mi do koncepcji / nie potrafiłem go odpowiednio użyć. Część kodu jest wzorowana na książce która dotyczy starszej wersji Django... btw. polecasz jakąś literaturę?

Rafał Stożek

unread,
May 21, 2012, 8:05:23 AM5/21/12
to djan...@googlegroups.com
Innej literatury niż dokumentacja nie znam.

2012/5/21 Kokos <kosowsk...@gmail.com>
Aby wyświetlić tę dyskusję w internecie, odwiedź stronę https://groups.google.com/d/msg/django-pl/-/MuFpxTqhIIwJ.

Aby zamieszczać posty w tej grupie, wyślij e-mail na adres djan...@googlegroups.com.
Aby anulować subskrypcję tej grupy, wyślij e-mail na adres django-pl+...@googlegroups.com.

Łukasz Rekucki

unread,
May 21, 2012, 8:19:17 AM5/21/12
to djan...@googlegroups.com
> Skoro to twoje pierwsze podejście do django, to:
> a) Używasz widoków-funkcji, podczas gdy w django 1.3 wprowadzono class based
> views

To że masz CBV, nie znaczy, że funkcje jako widoki są zabronione czy
gorsze. Funkcje są często bardziej czytelne.

> b) render_to_response i całe zamieszanie z context variables jest
> niepotrzebne. Sprawdź TemplateResponse.

A nie lepiej django.shortcuts.render() ? Po co się bawić w leniwe
renderowanie, które się ciężej debuguje i ma aktualnie kilka
"śmiesznych" błędów.

PS. Sprawdziłem na czystym projekcie i Django 1.3.0, że save() na
place zapisuję nowe Entity w SQLite3.

--
Łukasz Rekucki

Rafał Stożek

unread,
May 21, 2012, 8:30:18 AM5/21/12
to djan...@googlegroups.com


2012/5/21 Łukasz Rekucki <lrek...@gmail.com>

> Skoro to twoje pierwsze podejście do django, to:
> a) Używasz widoków-funkcji, podczas gdy w django 1.3 wprowadzono class based
> views

To że masz CBV, nie znaczy, że funkcje jako widoki są zabronione czy
gorsze. Funkcje są często bardziej czytelne.

W przypadku tego fragmentu dzięki CBV kod byłby bardziej czytelny. Nie mówię, że widoki-funkcje są gorsze (chociaż mogło tak to zabrzmieć).
 
> b) render_to_response i całe zamieszanie z context variables jest
> niepotrzebne. Sprawdź TemplateResponse.

A nie lepiej django.shortcuts.render() ? Po co się bawić w leniwe
renderowanie, które się ciężej debuguje i ma aktualnie kilka
"śmiesznych" błędów.

O, tego nie zauważyłem w release notes. Przyda się.
 
PS. Sprawdziłem na czystym projekcie i Django 1.3.0, że save() na
place zapisuję nowe Entity w SQLite3.

--
Łukasz Rekucki
--
Otrzymujesz tę wiadomość, ponieważ subskrybujesz grupę dyskusyjną Google o nazwie "django-pl - grupa polskiej społeczności Django".

Reply all
Reply to author
Forward
0 new messages