Django OneToOne reverse relationship does not allow null values - database

I have this architecture (very simplified)
from django.db import Models
class MainClass(models.Model):
a = models.IntegerField()
b = models.CharField()
class OtherClass(models.Model):
c = models.IntegerField()
main = models.OneToOneField(MainClass, primary_key=True)
Which means my MainClass object has an attribute named otherclass, because of the existence of the reverse relationship between these models.
My problem is if I specify valid values for MainClass.a and MainClass.b, but None for MainClass.otherclass. I get the error
ValueError: Cannot assign None: "MainClass.otherclass" does not allow null values.
I understand there cannot be OtherClass without MainClass (it doesn't make sense), but why the opposite situation is also causing an error? Other way: Why cannot be MainClass without OtherClass?

Looks like this is a normal behaviour in Django 1.8, although the restriction has been removed in Django 1.10
So, This isn't an error.

Related

Django 1.11.23 - calling superclass methods in a script

I'm exporting data from a legacy Django application and have written a script that imports the old models.py, which are something like this:
class GeneralType(models.Model):
...
publications = models.ManyToManyField(Publication, blank=True)
class Publication(models.Model):
...
authors = models.TextField()
url = models.URLField(blank=True)
class Record(GeneralType):
...
name = models.CharField(max_length=128)
So, this should work:
for r in Record.objects.all():
for p in r.publications.all(): # Exception thrown here
print(p.url)
But instead it gives:
django.core.exceptions.FieldError: Cannot resolve keyword 'generaltype' into field. Choices are: authors, url
So, there's some issue with calling GeneralType methods on a Record instance, presumably related to having abstracted this out to a script, as everything is fine if similar code is run in the Django app.
There's probably something obvious I've missed here - would happen to know what it is?

Datastore query without model class

I recently encountered a situation where one might want to run a datastore query which includes a kind, but the class of the corresponding model is not available (e.g. if it's defined in a module that hasn't been imported yet).
I couldn't find any out-of-the-box way to do this using the google.appengine.ext.db package, so I ended up using the google.appengine.api.datastore.Query class from the low-level datastore API.
This worked fine for my needs (my query only needed to count the number of results, without returning any model instances), but I was wondering if anyone knows of a better solution.
Another approach I've tried (which also worked) was subclassing db.GqlQuery to bypass its constructor. This might not be the cleanest solution, but if anyone is interested, here is the code:
import logging
from google.appengine.ext import db, gql
class ClasslessGqlQuery(db.GqlQuery):
"""
This subclass of :class:`db.GqlQuery` uses a modified version of ``db.GqlQuery``'s constructor to suppress any
:class:`db.KindError` that might be raised by ``db.class_for_kind(kindName)``.
This allows using the functionality :class:`db.GqlQuery` without requiring that a Model class for the query's kind
be available in the local environment, which could happen if a module defining that class hasn't been imported yet.
In that case, no validation of the Model's properties will be performed (will not check whether they're not indexed),
but otherwise, this class should work the same as :class:`db.GqlQuery`.
"""
def __init__(self, query_string, *args, **kwds):
"""
**NOTE**: this is a modified version of :class:`db.GqlQuery`'s constructor, suppressing any :class:`db.KindError`s
that might be raised by ``db.class_for_kind(kindName)``.
In that case, no validation of the Model's properties will be performed (will not check whether they're not indexed),
but otherwise, this class should work the same as :class:`db.GqlQuery`.
Args:
query_string: Properly formatted GQL query string.
*args: Positional arguments used to bind numeric references in the query.
**kwds: Dictionary-based arguments for named references.
Raises:
PropertyError if the query filters or sorts on a property that's not indexed.
"""
from google.appengine.ext import gql
app = kwds.pop('_app', None)
namespace = None
if isinstance(app, tuple):
if len(app) != 2:
raise db.BadArgumentError('_app must have 2 values if type is tuple.')
app, namespace = app
self._proto_query = gql.GQL(query_string, _app=app, namespace=namespace)
kind = self._proto_query._kind
model_class = None
try:
if kind is not None:
model_class = db.class_for_kind(kind)
except db.KindError, e:
logging.warning("%s on %s without a model class", self.__class__.__name__, kind, exc_info=True)
super(db.GqlQuery, self).__init__(model_class)
if model_class is not None:
for property, unused in (self._proto_query.filters().keys() +
self._proto_query.orderings()):
if property in model_class._unindexed_properties:
raise db.PropertyError('Property \'%s\' is not indexed' % property)
self.bind(*args, **kwds)
(also available as a gist)
You could create a temporary class just to do the query. If you use an Expando model, the properties of the class don't need to match what is actually in the datastore.
class KindName(ndb.Expando):
pass
You could then do:
KindName.query()
If you need to filter on specific properties, then I suspect you'll have to add them to the temporary class.

Problems with StructuredProperty and StringProperty

i am doing the finally degree work in Google App Engine, but i am having problems when i try this:
class Predicate(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.JsonProperty()
class State(ndb.Model):
predicates = ndb.StructuredProperty(Predicate, repeated=True)
class Action(ndb.Model):
name = ndb.StringProperty()
parameters = ndb.StringProperty(repeated=True)
preconditions = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToAdd = ndb.StructuredProperty(Predicate, repeated=True)
predicatesToDel = ndb.StructuredProperty(Predicate, repeated=True)
class Plan(ndb.Model):
plan = ndb.StructuredProperty(Predicate, repeated=True)
class Problem(ndb.Model):
initialState = ndb.StructuredProperty(Predicate)
goalState = ndb.StructuredProperty(Predicate)
actions = ndb.StructuredProperty(Action, repeated=True)
i get this error:
TypeError: This StructuredProperty cannot use repeated=True because its model class (Predicate) contains repeated properties (directly or indirectly).
StructuredProperty, if it contains repetitions, can not be replicated another StructuredProperty. But I need this structure models. How can i solve this?
And sorry for my bad english :(
I solved this problem using LocalStructuredProperty, but I think it will not work at all
The problem with your design is that ndb does not allow nested repeated properties. In other words, you cannot have a repeated structured property, which in turn has its own repeated property. If you remove the repeated=True from the parameters property, it will work.
You will need to re-think your design to work around this. One possible solution may be to use a JsonProperty for parameters, and store the list of strings as a JSON string. You won't be able to query them then of course, but it may work out depending on your requirements.

Using a Model with "general purpose" fields to model inheritance

I am currently kidding around on how to model something using Django. The basic situation is that I have an object that should serve as a chassis and provide some sockets. Then there are loads of different modules that are placed on the sockets of a chassis. I would like to model these different modules as distinct classes in Django, but use a common class on the database layer, possibly involving some generic fields.
So the database model might look something like this:
class Module(models.model):
name = models.CharField(max_length=128)
# Or is there a better way to annotate a type?
type = models.CharField(max_length=128)
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
# Some kind of engine class that derives from Module
# but does nothing else then "mapping" the generic
# fields to something sensible
class Socket(models.Model):
is_on = models.ForeignKey(Chassis)
name = models.CharField(max_length=128)
type = models.CharField(max_length=128)
class Connection(models.Model):
chassis = models.ForeignKey(Chassis)
module = models.ForeignKey(Module)
via = models.ForeignKey(Socket)
class Chassis(models.Model):
name = models.CharField(max_length=128)
modules= models.ManyToManyField(Module, through='Connection')
class Group(models.Model):
name = models.CharField(max_length=128)
Of course I wouldn't want to spoil my logic with this denormalization. Thats why I hinted for some kind of engine class that should use the Module table, but provide "logical" getters and setters, effectively mapping data like "Horsepower" to "int1".
So my questions are basicly:
Is what I am doing reasonable with Django? Or is there a better (possibly built in) way to deal with this?
Would it be possible to construct the correct type, the one providing the wrapper methods for the denormalized model, depending on the Module.type field automatically?
Is what I am doing reasonable with Django?
The general idea is okay, but the denormalization may make your queries less than optimal. The standard solution would be to subclass Module for each type of module; this would create a module table plus a table per module type with the type-specific stuff. This, of course, assumes you won't be creating or deleting module types at runtime.
That said, there are some issues with your models:
class Module(models.model):
name = models.CharField(max_length=128)
# Or is there a better way to annotate a type?
type = models.CharField(max_length=128)
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
Normally, type would get normalized to save space:
class ModuleType(models.model):
name = models.CharField(max_length=128)
# Any other type-specific parameters.
class Module(models.model):
name = models.CharField(max_length=128)
type = models.ForeignKey(ModuleType, related_name="modules")
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
class Socket(models.Model):
is_on = models.ForeignKey(Chassis)
name = models.CharField(max_length=128)
type = models.CharField(max_length=128)
class Connection(models.Model):
chassis = models.ForeignKey(Chassis)
module = models.ForeignKey(Module)
via = models.ForeignKey(Socket)
class Chassis(models.Model):
name = models.CharField(max_length=128)
sockets = m
modules= models.ManyToManyField(Model, through='Socket')
Chassis is a mess. You didn't define sockets, wrote Model where you probably want module, and through should probably refer to Connection (a through model has to have ForeignKeys to both ends of the link). But from your description, I get the far simpler:
class Socket(models.Model):
chassis = models.ForeignKey(Chassis, related_name="sockets")
name = models.CharField(max_length=128)
# Is `type` a ModuleType? If so, use a ForeignKey.
# If not, create a SocketType model.
type = models.___
module = models.ForeignKey(Module, related_name="sockets")
class Chassis(models.Model):
name = models.CharField(max_length=128)
sockets = models.IntegerField()
modules = models.ManyToManyField(Socket)
With a better description of what you're modeling, this can be refined further. For example, I'm not sure a ManyToMany is what you want. You may need to split the design of a chassis (i.e. things common to all instances of a given kind of chassis, including its sockets) from the instances of that chassis (which would reference the design, and have another table mapping sockets to modules).
Would it be possible to construct the correct type depending on the Module.type field automatically?
That's the Factory design pattern. In Python, you'd implement it as a dictionary of constructors:
class Module(models.model):
# ...
CONSTRUCTORS = {}
#staticmethod
def register_constructor(type_name, constructor):
Module.CONSTRUCTORS[type_name] = constructor
def construct(self):
return Module.CONSTRUCTORS[self.type.name](self)
I don't think you need a specific engine class; the various module classes will suffice.
In order to define an abstract base class you can do the following:
class Module(models.model):
name = models.CharField(max_length=128)
type = models.CharField(max_length=128)
string1 = models.CharField(max_length=128)
string2 = models.CharField(max_length=128)
...
int1 = models.IntegerField()
class Meta:
abstract = True
class SpecificModule(Module):
subClassField = models.CharField(max_length=128)
I would recommend to read this part of the documentation as it is a perfectly good starting point for dealing with inheritance and abstract classes.
You could also define the parent Module class without class Meta: abstract = True . The only difference is that with abstract = True all fields of the class SpecificModule and all the fields of the abstract Module parent class will be created in the subclass table for the class SpecificModule, whereas with no abstract = True definition a table for the class Module will be created, having all "generic" fields available in the Module table, and all sub-class specific fields in the table for the class SpecificModule.
Edit: In reply to the question regarding relationship between parent and child.
As an implicit one-to-one field is created in the subclass table (docs), you can get the child object using this query.
#get the parent
parent = Module.objects.get(name="my first module")
#this is possible
print parent.name
>>> "my first module"
#this is not possible
print parent.subClassField
>>> Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Module' object has no attribute 'subClassField'
#get the corresponding child
child = SpecificModule.objects.get(module_ptr_id=parent.pk)
#finally we can print the value
print child.subClassField
I think there should be also a default related_name be created by Django, but not sure which one it is.
Please note that an implicit one-to-one relationship from parent to child is only created in the abstract=False case. Nevertheless if abstract = True you will not have the abstract parent available as an object, since it is abstract..

Getting unmanaged models

I seem to have a problem after creating an unmanaged model (syncdb):
class Client_jobs(models.Model):
job_id = models.IntegerField(primary_key=True)
status = models.IntegerField()
class Meta:
db_table = 'client_jobs'
managed=False
in one of my def views, it calls the database view(Client_jobs)
def listjobs(request):
# if user is authenticated
if request.user.is_authenticated():
jobsArr = Client_jobs.objects.get.all()
The page returned me an error of
(1146, "Table 'table1.client_jobs' doesn't exist")
I know I'm missing something but I can't figure out. How does django detect this unmanaged model? Thank you.
as I know the db_table option will get precedence over the existing convention of app name_model name. If you set it explicitly you will have to prefix the application name yourself.
try client_jobs.client_jobs

Resources