Django: ID Null after Save - python

I Got this Models in models.py:
class Boats(models.Model):
id = models.BigIntegerField(primary_key=True)
created = models.DateTimeField(default=timezone.now, blank=True)
name = models.CharField(max_length=30)
class Meta:
managed = True
db_table = 'boats'
ordering = ['name']
class Clients(models.Model):
id = models.BigIntegerField(primary_key=True)
created = models.DateTimeField(default=timezone.now, blank=True)
code = models.CharField(max_length=100)
class Meta:
managed = True
db_table = 'clients'
ordering = ['name']
==========================
In the views.py; my function do it like that:
f = NewBoatForm(request.POST)
if f.is_valid():
nBoat = f.save()
print 'ID:'+str(nBoat.id)
cBoat = ClientsBoats()
cBoat.client = client
cBoat.boat = nBoat
cBoat.save()
But django fails with this error:
ValueError: save() prohibited to prevent data loss due to unsaved related object 'boat'.
I print the ID but it's Null. Can someOne help me.

You've overridden the primary key field, id, to be something other than an AutoField. Don't do that.
Normally you wouldn't define it at all, and let Django do it automatically. If you are really really sure that a standard integer field is not big enough, you can use BigAutoField. But I doubt you will have more than 2147483647 boats in your database.

Related

Django Multi Combination Model Joins

Currently experiencing a problem where my models aren't joining on the foreign key properly,
Doctors can only have one toolset, essentially I need to return [DoctorName, Category, Type, Subtype, Syringe, Bandage]
ToolSetCategoryID, ToolSetTypeID, ToolSetSubTypeID all join on each other's respective tables and all join back to ToolSets
an example of the models would be:
class Doctor(models.Model):
DoctorID = models.AutoField(db_column='DoctorID', primary_key=True)
ToolSetID = models.ForeignKey("ToolSets", db_column='ToolSetID', on_delete=models.CASCADE)
DoctorName = models.CharField(db_column='DoctorName', max_length=100)
class Meta:
managed = False
db_table = 'tblDoctors'
default_permissions = ['add','edit','delete']
class ToolSetCategories(models.Model):
ToolSetCategoryID = models.AutoField(db_column='ToolSetCategoryID', primary_key=True)
Category = models.CharField(db_column='Category', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSetCategories'
default_permissions = ['add','edit','delete']
class ToolSetTypes(models.Model):
ToolSetTypeID = models.AutoField(db_column='ToolSetTypeID', primary_key=True)
ToolSetCategoryID = models.ForeignKey("ToolSetCategories",db_column='ToolSetCategoryID',on_delete=models.CASCADE)
Type = models.CharField(db_column='Type', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSetTypes'
default_permissions = ['add','edit','delete']
class ToolSetSubTypes(models.Model):
ToolSetSubTypeID = models.AutoField(db_column='ToolSetSubTypeID', primary_key=True)
ToolSetTypeID = models.ForeignKey("ToolSetTypes",db_column='ToolSetTypeID',on_delete=models.CASCADE)
ToolSetCategoryID = models.ForeignKey("ToolSetCategories",db_column='ToolSetCategoryID',on_delete=models.CASCADE)
SubType = models.CharField(db_column='SubType', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSetSubTypes'
default_permissions = ['add','edit','delete']
class ToolSets(models.Model):
ToolSetID = models.AutoField(db_column='ToolSetID', primary_key=True)
ToolSetCategoryID = models.ForeignKey("ToolSetCategories",db_column='ToolSetCategoryID',on_delete=models.CASCADE)
ToolSetTypeID = models.ForeignKey("ToolSetTypes",db_column='ToolSetTypeID',on_delete=models.CASCADE)
ToolSetSubTypeID = models.ForeignKey("ToolSetSubTypes",db_column='ToolSetSubTypeID',on_delete=models.CASCADE)
Syringe = models.CharField(db_column='Syringe', max_length=100)
Bandage = models.CharField(db_column='Bandage', max_length=100)
class Meta:
managed = False
db_table = 'tblToolSets'
default_permissions = ['add','edit','delete']
I've found either the fix or a workaround.
I had to filter the conditions I would've used in a join instead of using a join.
You can use Django's built in function F in order to reference a fields dynamic data to filter against (such as filtering field data against another field's data).
Not the best looking solution but is working for now, if anyone can find a more efficient way of doing this please post an answer below.
from django.db.models import F
Doctor.objects.using("test").filter(DoctorID=DoctorID).filter(
ToolSetID__ToolSetTypeID__ToolSetCategoryID=F("ToolSetID__ToolSetCategoryID"),
ToolSetID__ToolSetSubTypeID__ToolSetTypeID=F("ToolSetID__ToolSetTypeID"),
ToolSetID__ToolSetSubTypeID__ToolSetCategoryID=F("ToolSetID__ToolSetCategoryID"),
)

Django inner join methods return unexpected results

I am new to Django's ORM and am confused by inner join conventions despite having consulted the documentation and other answers on SO. I have two tables - MyPoints and MyBuffers that are one-to-one related by projectid (no duplicates in either table). My goal is to fetch the radius field using inner join on projectid. Even though I have defined a foreign key, my first attempt at fetching all of the fields from MyBuffers returns nothing from the joined table, and my second attempt at fetching one field from MyBuffers errors. What is wrong with the syntax or methodology here? Should key columns be named differently? Any advice would be greatly appreciated!
models.py
from django.contrib.gis.db import models
class MyBuffers(models.Model):
id = models.BigAutoField(primary_key=True)
projectid = models.CharField(max_length=25, unique=True)
radius = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'my_buffers'
class MyPoints(models.Model):
id = models.BigAutoField(primary_key=True)
projectid = models.ForeignKey('MyBuffers', max_length=25, on_delete=models.DO_NOTHING, to_field='projectid', db_column='projectid')
geog = models.PointField(geography=True, srid=4326)
class Meta:
managed = False
db_table = 'my_points'
views.py
from .models import MyPoints
from .models import MyBuffers
1.Does not return any fields in from the joined MyBuffers table
test = MyPoints.objects.select_related('projectid')
test.first().__dict__
{'_state': <django.db.models.base.ModelState object at 0x7f3e21786520>, 'id': 5808, 'projectid_id': 'foobar1', 'geog': <Point object at 0x7f3e21738910>}
2.Throws an errors
test= MyPoints.objects.select_related('projectid__radius')
test.first().__dict__
django.core.exceptions.FieldError: Non-relational field given in select_related: 'radius'. Choices are: (none)
I think select related only works in foreign keys. So if you are trying to get fields other than foreign keys it will throw an error. Your queryset must be
test= MyPoints.objects.select_related('projectid')
# To get radius
test.first().projectid.radius
from django.contrib.gis.db import models
class MyBuffers(models.Model):
id = models.BigAutoField(primary_key=True)
projectid = models.CharField(max_length=25, unique=True)
radius = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'my_buffers'
class MyPoints(models.Model):
id = models.BigAutoField(primary_key=True)
projectid = models.ForeignKey('MyBuffers',
max_length=25,on_delete=models.CASCADE)
geog = models.PointField(geography=True, srid=4326)
class Meta:
managed = False
db_table = 'my_points'
Try the following code

Creating new object returns field with None value

I'm trying to create a new object of my model, but keep on getting a value of none for one field.
My models look like this:
class KeyCategory(models.Model):
program = models.ForeignKey('Program', verbose_name='Programm', on_delete=models.CASCADE)
name = models.CharField('Name', max_length=100)
events = models.ManyToManyField('Event', through='EventQuota')
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
ordering = ['name']
unique_together = ("program", "name")
permissions = (
('view_key_category', 'Have access to categories'),
)
class EventQuota(models.Model):
key_category = models.ForeignKey(KeyCategory, on_delete=models.CASCADE, related_name='key_quota')
event = models.ForeignKey('Event', on_delete=models.CASCADE, related_name='key_quota')
quota = models.PositiveIntegerField('Quota', default=0)
class Meta:
verbose_name = 'Quota'
verbose_name_plural = 'Quotas'
unique_together = ('key_category', 'event')
When I try now to create a KeyCategory and my EventQuota, the field "events" for KeyCategory always returns core.Event.None
if program.pk == 1:
for _ in range(0, 2):
key_category = KeyCategory(
program=program,
name=random.choice(self.eventList)
)
key_category.save()
event_quota = EventQuota(
key_category=key_category,
event = random.choice(eventList),
quota = random.randint(0,100)
)
event_quota.save()
Note: the eventList in the random.choice is a queryset list of objects.
I tried to follow Djangos Extra fields on Many-to-Many relationships example, but somehow it seems that I'm missing something here or doing something not the right way? Would appreciate any help! Thanks in regard.
Logging:
import logging
logger = logging.getLogger(__name__)
logger.debug(key_category.events)
When you access key_category.events you are asking for the value of a field (or a single object for foreign key fields). However with a ManyToMany relationship you are asking for multiple objects (a queryset).
Using key_category.events.all() returns the objects related to the key_category, not just a single value.
core.events.all()

Serialize m2mfield('self')

I have this model in models.py:
class Foo(models.Model):
bar = models.ManyToManyField('self')
How can I serialize it?
I was using one of solutions from this topic: Django rest framework nested self-referential objects But none of them working with M2M, either causes in infinity cycle of serialization. Solution where I'm using a row of serializers works good except it's limited by copy&paste (sounds really sad :) )
Generic model mostly looks like a comment's tree. I hope such a problem was already solved before but haven't found how yet.
I don't think you will get a straight solution to this, so try this
class FooBaseSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = Foo
class FooSerializer(FooBaseSerializer):
bar = FooBaseSerializer(many=True)
NOTE: As a Software Engineer, I love to use Architectures and I have deeply worked on Layered Approach for Development so I am gonna be Answering it with Respect to Tiers.
I would suggest the use of a Bridge Table for M2M relationships to Normalize Stuff. Anyhow serializing many of the Items would require to
serializer = SerializerNameGoesHere(AllFilteredObjectsfromModel, many=True)
would serializer m2m.
Here's an Example in Layered Approach!
As i understood the Issue, Here's the Solution
models.py
class Member(models.Model):
member_id = models.AutoField(primary_key=True)
member_name = models.CharField(max_length =
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length = 20)
fk_member_id = models.ForeignKey('Member', models.DO_NOTHING,
db_column='fk_member_id', blank=True, null=True)
class Membership(models.Model):
membershipid = models.AutoField(primary_key=True)
fk_group_id = models.ForeignKey('Group', models.DO_NOTHING,
db_column='fk_member_id', blank=True, null=True)
join_date = models.DateTimeField()
serializers.py
import serializer
class AllSerializer(serializer.Serializer):
group_id = serializer.IntegerField()
group_name = serializer.CharField(max_length = 20)
join_date = serializer.DateTimeField()
CustomModels.py
imports...
class AllDataModel():
group_id = ""
group_name = ""
join_date = ""
BusinessLogic.py
imports ....
class getdata(memberid):
alldataDict = {}
dto = []
Member = models.Members.objects.get(member_id=memberid) #or use filter for Name
alldataDict["MemberId"] = Member.member_id
alldataDict["MemberName"] = Member.member_name
Groups = models.Group.objects.filter(fk_member_id=Member)
for item in Groups:
Custommodel = CustomModels.AllDataModel()
Custommodel.group_id = item.group_id
Custommodel.group_name = item.group_name
Membership = models.Membership.objects.get(fk_group_id=item.group_id)
Custommodel.join_date = Membership.join_date
dto.append(Custommodel)
serializer = AllSerializer(dto,many=True)
alldataDict.update(serializer.data)
return alldataDict

How to serialize using django rest_framework a ManyToManyFields with a Through Model

I have a Recipe model that holds an M2M field of an IngredientType object. This field, aka ingredient_list, uses the notorious 'through' model via an Ingredient object that adds extra data to my IngredientType.
these are my classes:
class Recipe(models.Model):
user_profile = models.ForeignKey(UserProfile, null=True, blank = True)
name = models.CharField(max_length=200)
photo1 = models.ImageField( upload_to = 'images/recipies', help_text="This photo will show by default")
ingredient_list = models.ManyToManyField(IngredientType,through='Ingredient')
class Ingredient(models.Model):
ingredient_type = models.ForeignKey(IngredientType)
recipe = models.ForeignKey(Recipe)
amount = models.IntegerField()
units = models.CharField(max_length=4,choices=UNIT,
default=None, null=True, blank = True)
class IngredientType(models.Model):
name = models.CharField(max_length=200)
plural_name = models.CharField(max_length=200)
photo = models.ImageField( upload_to = 'images/ingredients')
is_main = models.BooleanField()
i've tried serializing them using the rest_framework:
class IngredientTypeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = IngredientType
fields=('name', 'plural_name', 'photo', 'is_main')
class IngredientSerializer(serializers.HyperlinkedModelSerializer):
ingredient_type = IngredientTypeSerializer(source = 'ingredient_type')
amount = serializers.Field(source='ingredient_type.amount')
units = serializers.Field(source='ingredient_type.units')
recipe = serializers.Field(source='Recipe.name')
class Meta:
model = Ingredient
fields=('amount', 'units')
class RecipeSerializer(serializers.ModelSerializer):
ingredient_list = IngredientSerializer(source='ingredient_list', many=True, read_only = True)
class Meta:
model = Recipe
fields = ('user_profile', 'name','photo1','ingredient_list')
but when trying to run this, I get an AttributeError :
'IngredientType' object has no attribute 'ingredient_type'
clearly, when I change the line:
ingredient_list = IngredientSerializer(source='ingredient_list', many=True, read_only = True)
to:
ingredient_list = IngredientTypeSerializer(source='ingredient_list', many=True, read_only = True)
that is, change the Serializer, it works, but without fetching me the Ingredient data.
i've used this link:
Include intermediary (through model) in responses in Django Rest Framework
as reference, but obviously it hasn't solved my problems.
Any help would be appreciated.
tnx,
Nitzan
On your Recipe model, for the ingredient_list field you have a ManyToManyField pointing to IngredientType.
On your RecipeSerializer the ingredient_list field is not using the IngredientTypeSerializer but rather the IngredientSerializer.
This is the error. (And it explains the error message — the actual model at the source doesn't have the attribute being looked for by the serializer.)
Beyond this, your naming scheme is massively confusing. "Recipe" is fine, but what you're calling "IngredientType" should probably just be "Ingredient" and then you should find a distinct name for the through table. (Maybe "RecipeIngredientDetails")
I hope that helps.

Categories

Resources