Django model's table doesnt contain given field - python

I have the following model in Django:
class Priority(models.Model):
task = models.ForeignKey(Task, on_delete=models.CASCADE)
priority = models.PositiveSmallIntegerField
However, when I run makemigrations and migrate, the field priority ( models.PositiveSmallIntegerField) doesn't appear in mysql table and I cannot create object of this model. Why?

Because you did not construct a field, you only passed a reference to that class, you need to add brackets (()) to make the call:
class Priority(models.Model):
task = models.ForeignKey(Task, on_delete=models.CASCADE)
priority = models.PositiveSmallIntegerField()
# call the constructor ^^
If you do not call the constructor, you have set priority as a reference to the PositiveSmallIntegerField class, not as a PositiveSmallIntegerField object.

Related

How to set custom text for django on_delete function?

I have a model named 'Clients' and another model named 'Information'.
class Information(models.Model):
client_name = models.ForeignKey(Clients, on_delete=models.SET(get_deleted_client_intance))
I want to set a custom text when a name is deleted from 'Clients' model.
The below function creates a new name 'deleted' as a new entry and is saved in 'Clients' model. I don't want that. I want if I delete a name it says 'deleted' or 'removed' on it's place.
def get_deleted_client_intance():
return Clients.objects.get_or_create(name='deleted')[0]
How can I do this?
I think you have a little misunderstanding about on_delete keyword argument. According to the docs:
When an object referenced by a ForeignKey is deleted, Django will emulate the behavior of the SQL constraint specified by the on_delete argument. For example, if you have a nullable ForeignKey and you want it to be set null when the referenced object is deleted:
user = models.ForeignKey(
User,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
I.e. it handles some logic when a referenced object is deleted - sets the field as null (SET_NULL), restricts from removing if the referenced object has children (PROTECT), deletes the child objects as well (CASCADE), or sets your preferred value (SET), etc.
In your case, if you want to change the state of the Clients object you don't need to do it in the callable passed to models.SET, you'd better do it on the object level, e.g. override the delete method:
class Clients(models.Model):
...
def delete(self, using, *args, **kwargs):
self.name = 'deleted'
self.save(using=using)

TypeError in models

I'm getting this error:
user = models.OneToOneField(User)
TypeError: init() missing 1 required positional argument: 'on_delete'
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfileInfo(models.Model):
# creating relationship
user = models.OneToOneField(User)
# additional attributes
portfolio = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_pics', blank=True)
def __str__(self):
return self.user.username
As the error indicates, you need to specify what should happen, given the object to which you refer is removed, by the on_delete= parameter [Django-doc]. For example:
class UserProfileInfo(models.Model):
# creating relationship
user = models.OneToOneField(User, on_delete=models.CASCADE)
# additional attributes
portfolio = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_pics', blank=True)
def __str__(self):
return self.user.username
The options here are:
CASCADE
Cascade deletes. Django emulates the behavior of the SQL constraint
ON DELETE CASCADE and also deletes the object containing the
ForeignKey.
Model.delete() isn't called on related models, but the pre_delete
and post_delete signals are sent for all deleted objects.
PROTECT
Prevent deletion of the referenced object by raising ProtectedError,
a subclass of django.db.IntegrityError.
SET_NULL
Set the ForeignKey null; this is only possible if null is True.
SET_DEFAULT
Set the ForeignKey to its default value; a default for the
ForeignKey must be set.
SET()
Set the ForeignKey to the value passed to SET(), or if a callable
is passed in, the result of calling it. In most cases, passing a
callable will be necessary to avoid executing queries at the time your
models.py is imported (...)
DO_NOTHING
Take no action. If your database backend enforces referential
integrity, this will cause an IntegrityError unless you manually add
an SQL ON DELETE constraint to the database field.
A similar question is answered here Getting TypeError: __init__() missing 1 required positional argument: 'on_delete' when trying to add parent table after child table with entries
Basically following should fix url problem
From Django 2.0 on_delete is required:
user = models.OneToOneField(User, on_delete=models.CASCADE)
put 'on_delete = models.CASCADE' in the constructor
what it does: when you will delete the user object as you have referenced it in the user field of your model. it will also delete the model object of UserProfileInfo for taht particular user.

Cannot define 'through' relationship on two models which share a base class in Django

I've got a 'set' model, which has a many to many relationship to the 'Item' model. The issue is that 'set' is a subclass of Item (everything is an Item on the project).
It works fine, until I try to create a 'through' relationship to an intermediary model called 'order', which I'm defining so I can order the 'Items' inside the 'Set'.
When I try to define the relationship, I get this error:
ERRORS:
curate.Set.items_: (fields.E001) Field names must not end with an underscore.
curate.order.set: (fields.E304) Reverse accessor for 'order.set' clashes with reverse accessor for 'order.item'.
HINT: Add or change a related_name argument to the definition for 'order.set' or 'order.item'.
I've tried adding a related_name to Order.set, and also Order.item, but it doesn't seem to work. I can get migrations to be happy, but then when I try to migrate I get an error saying:
ValueError: Cannot alter field curate.Set.items into curate.Set.items - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)
models.py
class Item(models.Model, AdminVideoMixin):
title = models.TextField(max_length=5000)
slug = models.SlugField(max_length=5000, default='')
...
class Video(Item):
video_embed = EmbedVideoField(max_length=500)
...
class Article(Item):
authors = models.CharField(max_length=10000)
...
class Podcast(Item):
categories = models.CharField(max_length=5000, null=True, blank=True,)
...
class Episode(Item):
author = models.CharField(max_length=10000, null=True,blank=True,)
...
class Set(Item):
items = models.ManyToManyField(Item, related_name='setItems', max_length=5000, through='Order')
front_page = models.BooleanField(max_length=300, blank=False, default=False, null=False)
class order(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE,)
set = models.ForeignKey(Set, on_delete=models.CASCADE,)
order = models.CharField(max_length=64, default=0)
You can't change a ManyToMany field to use a through relationship once it has been created. This is because the through table will now contain extra fields that cannot be populated by the standard ManyToMany relationship (this is the same reason why you can't use add, clear, remove, delete when using a through table). You will need to create a new ManyToMany field on Set that uses the through relationship and then populate it with the data from Set.items before removing Set.items.
Docs on through tables
If you need to have the new field called items you can do the following:
Change items to items_old in the Set model, you will need to change the related_name as well if you would like that to be the same (make and run the migration)
Add the new items field with the through relationship (make and run the migration)
Populate the new items field with the data from items_old
set_items = Set.objects.filter(items__isnull=False)
Order.objects.bulk_create([
Order(item=item, set=s)
for s in set_items
for item in s.items.all()
])
Remove items_old from Set
NB - Like katoozi mentioned in his comment, you probably shouldn't have fields named set

Django 1.11 One-to-Many relationship no related set

So I have two models:
class UserData(models.Model):
""" Holds basic user data. """
id = models.IntegerField(primary_key=True, editable=False) # id is taken from data.
class ConsumptionTimePoint(models.Model):
""" Individual consumption time points with a One-to-Many relationship with UserData """
user_data = models.ForeignKey(UserData, on_delete=models.CASCADE)
And when I try and test them by creating them both, and their relationship in a test:
def test_basic_model_creation(self):
user_data_object = UserData.objects.create(id=1)
user_data_object.save()
consumption_time_point_object = ConsumptionTimePoint.objects.create(user_data=user_data_object)
consumption_time_point_object.save()
self.assertIsNotNone(consumption_time_point_object.user_data)
self.assertEquals(1, len(user_data_object.consumption_time_point_set.all()))
I get the following error:
AttributeError: 'UserData' object has no attribute 'consumption_time_point_set'
But from my understanding that's the correct way to get the set. Have I misnamed something? Or is this a testing issue?
To get the related queryset the class name is lowercased and _set is appended. Try consumptiontimepoint_set
You can also set the reverse relation name manually by using the related_name parameter.

Django unique_together does not work: "refers to the non-existent field"

Creating a model in Django, I need to make unique the combination of two integer fields:
class example(models.Model):
lenght = models.PositiveSmallIntegerField
position = models.PositiveSmallIntegerField
otherfield = models.ForeignKey('onetable')
otherfield2 = models.ForeignKey('anothertable')
class Meta:
unique_together = (("lenght", "position"),)
So when I sync the database I receive the follow error message:
Executing manage.py syncdb
SystemCheckError: System check identified some issues:
ERRORS:
prj.CodeBlock: (models.E012) 'unique_together' refers to the non-existent field 'lenght'.
prj.CodeBlock: (models.E012) 'unique_together' refers to the non-existent field 'position'.
The Python REPL process has exited
>>>
I find out if I change the field type to "charfield" I do not receive any error message:
class example(models.Model):
lenght = models.CharField(max_length=8)
position = models.CharField(max_length=8)
otherfield = models.ForeignKey('onetable')
otherfield2 = models.ForeignKey('anothertable')
class Meta:
unique_together = (("lenght", "position"),)
Why I cannot make unique the combination of integer fields?
Because you did not declare (instantiate) the integer fields (you just referenced their classes):
class example(models.Model):
lenght = models.PositiveSmallIntegerField
position = models.PositiveSmallIntegerField
length and position are not field instances, but field classes. Try instantiating them to be actually existent fields in the table:
class example(models.Model):
lenght = models.PositiveSmallIntegerField()
position = models.PositiveSmallIntegerField()
In its metaclass, Django detects and enumerates field instances (i.e. by running isinstance(v, Field)) and create their columns. You can have any value declared in your class (methods are attributes; perhaps your class has custom exceptions or constant values for a choices= argument, ...), but only Field instances will be enumerated. This applies to field classes: Django does not treat them specially: perhaps you declare a custom Field class as an inner class in your model (intended to be used only in your model), and you would not expect it become just a field... so that's the reason why Django does not convert references to field classes to references to field instances.
You must be explicit. Perhaps you forgot the parenthesis.

Categories