How to set ManToManyField to None? - django

I have a Section model for storing different sections of laws.
A law has Part, Book, Chapter, Title, Section, SubSection, ... and Article
Instead of making models for each of the above parts, I created a section model to store the sections in the database.
The level field in the section model specifies the depth of levels. as you can see in the picture.
class Section(Timestamped):
parent = models.ManyToManyField(
to='self',
verbose_name=_("Parent Section"),
help_text=_("Specifies the links to another section."),
blank=True,
symmetrical=False
)
level = models.PositiveIntegerField(
verbose_name=_("Level of the section"),
)
...
My problem is that when I store the first section or level, the parent should be set to null(which means that the first section has no parent). But I get an error when I set the parent to None.
I have all the sections in a JSON file:
The script
for section in sections:
section_data = {
"text_id": section.get("id"),
"level": 1,
}
section_db, created = Section.objects.get_or_create(**section_data)
section_db.parent.add(None)
The error
django.db.utils.IntegrityError: null value in column "to_section_id" of relation "laws_section_parent" violates not-null constraint
DETAIL: Failing row contains (3, 22, null).
Is there any solution?
Are the models correctly designed?

Related

Creating New Model Form Fields in Django Admin

I have a product model that has a manytomany relationship to a locations model. I am creating an app for my clients business that has hundreds of products and services, but each product/service have different prices base on the delivery location and can deliver to multiple locations. Right now my client delivers to 4 locations.
Solution #1
Hard code all 4 locations into the product model - this works, but is not preferred since they want to expand and hard coding more locations is just gross..
Solution #2 (current solution - code listed below)
Create a manytomany relationship to locations - this works, but is getting way out of hand having location options of varying charges an rates for - multiplied by every product....
Solution #3 - This is the help I need, if a solution exists.
I would like to build a hybrid of sort of the above two options. Id like to keep the manytomany with the location model so its easy to add locations as they grow, but once added, I would like to have an empty 'price' object that they can fill-in when adding or updating a product, yet remain assigned to that product only.
Not sure if this makes sense, so after my current code below (solution 2 above) I included a sample image to help illustrate my question. Thank you for your help.
Product Model
class Product(models.Model):
...
locations = models.ManyToManyField('Location', related_name='deliver_to')
...
Location Model
LOCATIONS = (
('Los Angeles', 'Los Angeles'),
('Orange County', 'Orange County'),
('Riverside', 'Riverside'),
('San Diego', 'San Diego')
)
class Location(models.Model):
l_title = models.CharField(
max_length=255,
choices=LOCATIONS,
verbose_name='Service Location'
)
...
Using https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany will allow for extra fields.

Newbie Creating Django models

I'm new to django and trying to understand how I might create my models. I'm building an app that can be used to create documents from a template. These documents can be of a number of different types, and contain generic sections as well as sections specific to each document type. I'm intending for the specific sections that the user can choose from (to include in their document), to change according to the document type they have chosen to create. Yet the generic sections will be used no matter what the document type.
I'm having a hard time getting my head round how I might build my models to achieve this. I've considered giving the document model and sections model a document type that can be set and referenced in html, matching the sections to each document:
class Document(models.Model):
document_type = models.CharField(max_length=50)
class Sections(models.Model):
document_type = models.CharField(max_length=50)
or adding in a document type model:
class Document(models.Model):
document_type = models.ForeignKey(DocumentType)
class Sections(models.Model):
document_type = models.ForeignKey(DocumentType)
class DocumentType(models.Model):
name = models.CharField(max_length=50)
But I'm worried that this will cause problems due to many documents sharing some generic sections. And so I wondered if I separate the generic and specific sections:
class GenericSection():
document_type = models.ManyToManyField(DocumentType)
class SpecificSection():
document_type = models.ForeignKey(DocumentType)
or even separate each document type into it's own app. I think I've got myself into a twist with this and would appreciate any feedback on whether there's a more appropriate way to approach this.
If a document can be of only one type, I would personally have that in it's own table. That way they are not duplicated everywhere.
Then your document table's document type should be a foreign key to the document type table (assuming a document can only have one type or a many to many relation to the document type table if a document can be more than one type)
foreign key's are a great way to make sure your table doesn't turn into a nightmare of pointing to the wrong values or dead values etc...

Should optional Foreign Key be NULL or should it point to an empty string

When the related value in foreign table is missing for an optional Foreign Key, I can either:
Set it to null
Point it to an empty string '' in the foreign table
It appears to me that if you follow Django design practices, you end up with option 2 (see code below). Is there any obvious advantage or downside with either approach?
Django favors 2 somewhat by design/convention. The docs say that null and '' are 2 possible values of "no-data". Hence if you omit the optional field, the forms will validate correctly and supply an empty string to which your Foreign Key can point to.
However logically, it seems like a missing value should imply a null or missing Foreign Key (instead of a valid Foreign Key that points to an empty value).
Moreover, storing blank would be a gotcha if I simply list all albums or do a count. Each time I've to remember to avoid the empty string. On the contrary, a null foreign key would never have an entry in the album table.
Reference:
Can a foreign key be NULL...
Can foreign key be NULL
Django docs on null vs blank
Optional detail with code:
#models.py
class Album(Model):
name = CharField(max_length=50, unique=True)
class Song(Model):
name = CharField(max_length=50)
album = ForeignKey(Album, null=True, blank=True)
#forms.py
class SongForm(Form):
name = CharField(max_length=50)
album = CharField(max_length=50, required=False)
If you have a song with no album name, the form returns {'name':'foo', 'album':''}. This creates an entry in Album table with a blank name. I can circumvent that in the view (see code below). But this seems like a hack since data validation should be done in forms.
if album:
Song.objects.create(name=form.cleaned_data['name'], album=form.cleaned_data['album'])
else:
Song.objects.create(name=form.cleaned_data['name'], album_id=None)
After thinking more, approach 2 (the one in which a missing foreign relation implies an FK to an empty string) has one advantage compared to approach 1.
Using approach 2would make it easier to have a unique_together index on (song.name, song.album). This is better explained with an example. When empty strings are used for Album, two similar values of Song (d below) would be caught by unique constraint. However, null are treated as different values in DB and they won't be caught in case 1 (have to rely on conditional indexes to make this work).
I'm not sure this was by design or an accidental advantage of Django's convention.
Missing album => FK is null Missing Album => FK points to blank name
Song | Album Song | Album
---------------- ----------------
'a' | 'x' 'a' | 'x'
'b' | 'y' 'b' | 'y'
'c' | 'y' 'c' | 'y'
'd' | null 'd' | ''
'd' | null <- Dup. not caught by DB 'd' | '' <- Duplicate caught by DB
Django's convention is to use '' to represent the lack of data in text-based fields. When it comes to ForeignKeys, however, the convention in Django and elsewhere is to represent the lack of data by NULL (i.e. option 1).
Your option 2 confuses the distinction between an album with no name and a song with no album. Django's convention has to do with different ways to represent the lack of data in a field where that is allowed. But in your case, it is not valid to have an album with no name, so option 2 would require inventing a invalid album just to give other models something to point to.
You write: "Point it to an empty string '' in the foreign table". Note, though, that foreign keys don't point to fields in a foreign table, they point to entire rows. Imagine you had other fields in the Album model (a BooleanField is_international, for example, or a DateField release_date). Now you have to make up arbitrary, fake values for these fields in your magical row that doesn't represent an actual album.
So I suggest sticking with the conventional option 1.
Handling this in forms is built-in and straightforward. In ModelForms, for example, a ForeignKey is represented by a ModelChoiceField. If the ForeignKey has blank=True and null=True then one of the choices in the dropdown will be blank, and saving the form with that choice selected will make the corresponding database field NULL.
In your case it looks like you're having the user enter the album name directly on the Song form. That's perfectly fine, but of course you're going to have to have special logic to interpret that value and create the appropriate models. Your sample code above is not a hack and is not data validation. Validation is allowing empty values or not, and that is controlled by blank=True (in the model) or required=False (in the form).

multiple Django annotate Count over reverse relation of a foreign key with an exclude returns a strange result (18)

The strangest thing, either I'm missing something basic, or maybe a django bug
for example:
class Author(Model):
name = CharField()
class Parent(Model):
name = CharField(
class Subscription(Model):
parent = ForeignKey(Parent, related_name='subscriptions')
class Book(Model):
name = CharField()
good_book = BooleanField()
author = ForeignKey(Author, related_name='books')
class AggregatePerson(Model):
author = OneToOneField(Author, related_name='+')
parent = OneToOneField(Parent, related_name='+')
when I try:
AggregatePerson.objects.annotate(counter=Count('author__books')).order_by('counter')
everything work correctly. both ordering and fields counter and existing_subs show the correct number BUT if I add the following:
AggregatePerson.objects.annotate(existing_subs=Count('parent__subscriptions')).exclude(existing_subs=0).annotate(counter=Count('author__books')).order_by('counter')
Then counter and existing_subs fields become 18
Why 18? and what am I doing wrong?
Thanks for the help!
EDIT clarification after further research:
is the number of parent__subscriptions, the code breaks even without the exclude, **for some reason counter also gets the value of existing_subs
I found the answer to this issue.
Tl;dr:
You need to add distinct=True inside the Count like this:
AggregatePerson.objects.annotate(counter=Count('author__books', distinct=True))
Longer version:
Adding a Count annotation is adding a LEFT OUTER JOIN behind the scene. Since we add two annotations, both referring to the same table, the number of selected and grouped_by rows is increased since some rows may appear twice (once for the first annotation and another for the second annotation) because LEFT OUTER JOIN allows empty cells (rows) on select from the right table.
(repeating essentials of my reply in another forum)
This looks like a Django bug. Possible workarounds:
1) Add the two annotations in one annotate() call:
...annotate(existing_subs=Count('parent__subscriptions'),counter=Count('author__books'))...
2) Replace the annotation for existing_subs and exclude(existing_subs=0) with an exclude (parent__subscriptions=None).

Left Join with a OneToOne field in Django

I have 2 tables, simpleDB_all and simpleDB_some. The "all" table has an entry for every item I want, while the "some" table has entries only for some items that need additional information. The Django models for these are:
class all(models.Model):
name = models.CharField(max_length=40)
important_info = models.CharField(max_length=40)
class some(models.Model):
all_key = models.OneToOneField(all)
extra_info = models.CharField(max_length=40)
I'd like to create a view that shows every item in "all" with the extra info if it exists in "some". Since I'm using a 1-1 field I can do this with almost complete success:
allitems = all.objects.all()
for item in allitems:
print item.name, item.important_info, item.some.extra_info
but when I get to the item that doesn't have a corresponding entry in the "some" table I get a DoesNotExist exception.
Ideally I'd be doing this loop inside a template, so it's impossible to wrap it around a "try" clause. Any thoughts?
I can get the desired effect directly in SQL using a query like this:
SELECT all.name, all.important_info, some.extra_info
FROM all LEFT JOIN some ON all.id = some.all_key_id;
But I'd rather not use raw SQL.
You won't get a DoesNotExist exception in the template - they are hidden, by design, by the template system.
The SQL you give is what is generated, more or less, when you use select_related on your query (if you're using Django 1.2 or a checkout more recent than r12307, from February):
allitems = all.objects.select_related('some')