saving data from both a model and a derived model

74 vistas
Ir al primer mensaje no leído

jjander...@gmail.com

no leída,
23 may 2017, 6:44:01 p.m.23/5/2017
para Django users
I have a model class, 'A_base', and a 2nd model class, 'A_derived'. When I save an object of A_derived, I want the data from both my base and derived class to be saved.

Example code looks like this:

    class A_base(models.model):
        name = models.CharField(max_length=50)

    class A_derived(A_base):
        role = models.CharField(max_length=50)


So when I call save(), I want to save an instance of the derived object, including the data in the base class into my sqlite3 database. I would like my code to look like this:

    ...
    derived_obj = A_derived.objects.get(name="john")
    derived_obj.role = "parent"
    derived_obj.save()
    ...

My question is whether the save method will save 'role' to the A_derived table and save 'name' to the A_base table? Or do I have to override the save method so that it saves 'role' and then calls the base class save method to save 'name'?

I tried doing this using the default save method and it created a stack trace, so I'm guessing that I am expecting too much from the default save method.

Jim A.

James Schneider

no leída,
24 may 2017, 3:36:53 a.m.24/5/2017
para django...@googlegroups.com
On Tue, May 23, 2017 at 3:44 PM, <jjander...@gmail.com> wrote:
I have a model class, 'A_base', and a 2nd model class, 'A_derived'. When I save an object of A_derived, I want the data from both my base and derived class to be saved.

Example code looks like this:

    class A_base(models.model):
        name = models.CharField(max_length=50)

    class A_derived(A_base):
        role = models.CharField(max_length=50)


So when I call save(), I want to save an instance of the derived object, including the data in the base class into my sqlite3 database. I would like my code to look like this:

    ...
    derived_obj = A_derived.objects.get(name="john")
    derived_obj.role = "parent"
    derived_obj.save()
    ...

My question is whether the save method will save 'role' to the A_derived table and save 'name' to the A_base table? Or do I have to override the save method so that it saves 'role' and then calls the base class save method to save 'name'?


No, you have created two separate (but related) models. A_base has a model field of 'name', and A_derived has model fields 'name' and 'role'. Since you are inheriting from a non-abstract parent model, there is an implied OneToOne relationship between the two models, see the following: https://docs.djangoproject.com/en/1.11/topics/db/models/#multi-table-inheritance

I'm not a big fan of this implied behavior, but it hasn't been problematic for me because I make heavy use of abstract model classes.

If you do not want the implied relationship between the two models, create an abstract base class matching A_base and have both of your models inherit from it (A_base would be an empty model in this case, most likely).

From a Django perspective, these two are completely independent models/entities (aside from the OneToOne relationship). A_derivied will have its own name and role. A_base also has it's own name, but will not be able to contain a role.

To achieve the behavior you want, when A_derived is saved, you'll need to either create a new A_base object and set the 'name' field to the same value, or query for an existing A_base object and change/save the 'name' field. Keep in mind that the two values are not connected to each other. Changing the 'name' field on the same A_derived class later will NOT change the 'name' field on an A_base object automatically, you would need to provide such logic on one or both models, depending on the direction of the dependency you wish to create.
 
I tried doing this using the default save method and it created a stack trace, so I'm guessing that I am expecting too much from the default save method.


Post the entire stack trace and we may be able to better illuminate the issue.  

-James

Jim Anderson

no leída,
24 may 2017, 2:04:25 p.m.24/5/2017
para django...@googlegroups.com
Hi James,

I'm attaching the stacktrace as you requested.

The call to rs_template.save() is made from a django view.  rs_template is an instance of a class RSTemplate which is derived from STemplate. STemplate is derived from PriorityItemType. PriorityItemType is derived from ItemType. ItemType is derived from models.Model. PriorityItemType and ItemType are classes that are part of a library and which I have minimal control over, so figure them as constants that cannot be changed.

Jim


The relevant code is as follows:

From ItemType.py

[code]
class ItemType(models.Model):
    ...
    name = models.CharField('Name', max_length=100, unique=True, db_index=True)
[/code]

From PriorityItemType.py

[code]
class PriorityItemType(ItemType):
   ...
   priority = models.IntegerField('Priority', default=1)
[/code]

From STemplate.py

[code]
class STemplate(PriorityItemType):
    ...
    backend = models.ForeignKey('siggy.SBackend', null=True, blank=True)
[/code]

From RSTemplate.py

[code]
class RSTemplate(STemplate):
   ...
   role = models.CharField(max_length=50)
[code]

From RSPrepView.py

[code]
class RSPrewView(View):
   ...
  
   for t in templates.templates:
            try:
                rs_template = RSTemplate.objects.get(name=t.filename)
            except RSTemplate.DoesNotExist:
                rs_template = RSTemplate()
            rs_template.name = t.filename
            rs_template.role = "RS Template"
            rs_template.save()
[/code]



--
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/QPo8MFXNdAc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CA%2Be%2BciXDpbGmmpqbcDC_iipvRVowJhuw3VcdeJsVLMAVJ5g-WQ%40mail.gmail.com.

For more options, visit https://groups.google.com/d/optout.

stackTrace.txt

James Schneider

no leída,
25 may 2017, 2:04:03 p.m.25/5/2017
para django...@googlegroups.com
On Wed, May 24, 2017 at 11:03 AM, Jim Anderson <jjander...@gmail.com> wrote:
Hi James,

I'm attaching the stacktrace as you requested.


Thanks. It is quite telling:

  File "/home/jja/testenv3.5/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 337, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: UNIQUE constraint failed: siggy_stemplate.name

The object you are working with is having a 'name' clash with another object of the same type. You've set the 'name' field to be unique, so you'll need to ensure that each object has a unique value for the 'name' field. Either check for uniqueness before assigning it, or attempt to save, catch this exception, and generate a more unique value as needed, rinse and repeat as necessary.

-James

jjander...@gmail.com

no leída,
26 may 2017, 9:13:21 a.m.26/5/2017
para Django users

James,

As always, thank you for looking at this.

Can you clarify for me?

I though that setting UNIQUE meant that the database objects, i.e objects already in the database had to be unique. From your response, my understanding that uniqueness applies to any object of the model type in memory. Is my understanding correct?

Jim

jjander...@gmail.com

no leída,
26 may 2017, 9:16:23 a.m.26/5/2017
para Django users

James,

I'm thinking about my last question more. If each object of the given type must be unique, there must be a manager in Django which keeps track of uniqueness. I will start searching for how I check for unique objects, but if you have a quick response, that will help.


Jim

On Tuesday, May 23, 2017 at 6:44:01 PM UTC-4, jjander...@gmail.com wrote:

jjander...@gmail.com

no leída,
26 may 2017, 9:21:30 a.m.26/5/2017
para Django users

James,

I just found what I was looking for. It looks like Model.validate_unique() is the test that I am looking for.


Jim

On Tuesday, May 23, 2017 at 6:44:01 PM UTC-4, jjander...@gmail.com wrote:

James Schneider

no leída,
29 may 2017, 3:21:57 a.m.29/5/2017
para django...@googlegroups.com
On Fri, May 26, 2017 at 6:13 AM, <jjander...@gmail.com> wrote:

James,

As always, thank you for looking at this.

Can you clarify for me?

I though that setting UNIQUE meant that the database objects, i.e objects already in the database had to be unique. From your response, my understanding that uniqueness applies to any object of the model type in memory. Is my understanding correct?


No, I was referring to objects that are saved to the database. Objects purely in memory likely will not complain. 

-James 
Responder a todos
Responder al autor
Reenviar
0 mensajes nuevos