Alternate model, which PK is used as default value for OneToOneRelation - python

I've run into a problem with Django migrations.
I have following models:
class ModelA(models.Model):
field_x = models.OneToOneField(
'app_label.ModelB',
default=ModelB.get_fresh,
)
class ModelB(model.Model):
field_y = models.TextField()
#classmethod
def get_fresh():
return cls.objects.create().id
What I want to do is to add another field to ModelB.
So I've added the field and then runned makemigrations command.
class ModelB(model.Model):
field_y = models.TextField()
field_z = models.BooleanField(default=False)
#classmethod
def get_fresh():
return cls.objects.create().id
Unfortunately, while running the tests, when django makes full migration for my project it says that there is no such column for default object.
django.db.utils.ProgrammingError: column "field_z" of relation "model_a_modelb" does not exist
Which is technically true, because default was added on previous migration and it don't know yet it new schema.
What I can do, to solve this problem and be able to extend ModelB in this case?

Related

How to correctly migrate custom UserModel in Django

I have custom user model from AbstractUser. And in the user model i have 1 field as foreignKey to other model. So i can't make migrations because i recieve error:
no such table: app_userrate
I tired to comment this foreignKey field but it is not soulution cause i want to auto deploy app.
class UserRate(models.Model):
name = models.CharField(max_length=30, blank=False)
max_active_events_cnt = models.PositiveIntegerField(default = 5)
max_people_contacts_cnt = models.PositiveIntegerField(default = 30)
def __str__(self):
return self.name
def default_rate():
obj, created = UserRate.objects.get_or_create(name="Basic")
return obj.id
class User(AbstractUser):
rate = models.ForeignKey(UserRate, on_delete=models.PROTECT, default=default_rate)
rate_until = models.DateField(null=True, blank=True)
I want to understand what should i change to make migrations correctly
This isn't really about the user model specifically, nor about foreign keys. It's about the default attribute, which you have set to call a function which itself does a database lookup. Obviously, at the time the migrations are run, the db item does not exist.
There is a solution, but it will take a few steps. You would need to remove the default attribute at first and create the migrations without it (you may need to set null=True). Then, add a second migration to define the "Basic" UserRate object. Finally, add the default back in and create a third migration.

django.db.utils.IntegrityError: update or delete on table when deleting a record

I use django and postgress and have a very odd exception.
I have a model object called ProductModel (with upc as a unique_id).
This is how the model looks like:
class ProductModel(models.Model):
def __str__(self):
return self.clean_name + " " + str(self.product_upc)
product_name = models.CharField(max_length=300, blank=True)
product_upc = models.CharField(max_length=300, primary_key=True)
official_price = models.DecimalField(default=0, decimal_places=5, max_digits=10)
mrsp = models.DecimalField(default=0, decimal_places=5, max_digits=10)
last_seen = models.DateTimeField(default=now)
clean_name = models.CharField(max_length=200, default='')
unfortunately (as I understand now) at the begining of times I made a mistake and created a class called product that inherits the ProductModel - this class has some regular methods nothing fancy.
class Product(ProductModel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.create_clean_name()
self.img_list = []
self.scraped_content = ""
self.specs = {}
Now, I was sure that this class has nothing to do with the db and the db doesnt aware of its existence - but now When I try to delete some product records using this command:
p = ProductModel.objects.all().filter(last_seen__month__lt=4,product_name__contains='a')
p.delete()
I get the following error -
django.db.utils.IntegrityError: update or delete on table "my_app_productmodel" violates foreign key constraint "f64b7bfb6c6019a35bf6b81e4125240f" on table "my_app_product"
DETAIL: Key (product_upc)=(852896336240) is still referenced from table "my_app_product"
And in this point I got totally lost and confused what the h*** is table "my_app_product" - why it exists??
I went to my PostgreSQL and found out that this table is really exists.
I'd like to understand how does it work and how I delete records in this situation.
ohh and one more detail - as I try to delete my records via django admin I manage to do it without any problems.
Thanks to the kind helper.
Here is what you actually did: https://docs.djangoproject.com/en/1.11/topics/db/models/#multi-table-inheritance
Subclassing a model (that is not defined as abstract) will create a new table called Product that has a OneToOneField to ProductModel pk which is product_upc. You are trying to delete a ProductModel which has a reference to Product table, this is why you get the error.
Depending on how you use that Product class I suggest to just change its superclass to object and run makemigrations to remove the table, since you don't actually need it.

How to get ForeignKey model field

In Django 1.8
class OtherModel(models.Model):
somefield = models.CharField(max_length=20)
class Orderform(models.Model):
sell_item_id = models.CharField(max_length=20)
class Selled(models.Model):
orderform = models.ForeignKey("Orderform")
sell_count = models.IntegerField()
something = OtherModel.objects.get(id=sell_item_id)
I need to use something like OtherModel.objects.get(id=sell_item_id).
How to get sell_item_id in class Selled(models.Model):?
You schema couldn't be presented in SQL.
Option #1:
class Orderform(models.Model):
sell_item_id = models.CharField(max_length=20)
othermodel = models.OneToOneField("OtherModel")
and get it
Selled.objects.get(pk=1).orderform.othermodel
Option #2:
class Selled(models.Model):
orderform = models.ForeignKey("Orderform")
sell_count = models.IntegerField()
def something(self):
return OtherModel.objects.get(id=self.sell_item_id)
and get
Selled.objects.get(pk=1).something()
But I think you should better think about you DB schema.
It looks like you have a couple of questions, for the first, to get the related
Selled.objects.filter(order_form__sell_item_id =id_to_get).select_related('order_form')
Notice the __ (double underscore) before sell_item_id. This is important because it says, selected Selleed by the sell_item_id of the OrderForm. and select_related makes sure that order form is brought back in the results with a single call to the db.
Now, if you want to do that for OtherModel, you will need to create a similar ForeignKey field in the OtherNodel and this will allow you to make the same query as above. Currently, you have no such relation.
class OtherModel(models.Model):
somefield = models.CharField(max_length=20)
orderform = models.ForeignKey("Orderform")
OtherModel.objects.filter(order_form__sell_item_id =id_to_get).select_related('order_form')
Don't forget to run:
python manage.py makemigration
python manage.py migrate
This should solve the issue.

django model with unique combination of two fields

I have a django model as below
class MySubject(models.Model):
name=models.CharField(unique=True,max_length=50)
description=models.TextField(blank=True)
slug=models.SlugField(editable=False)
class Meta:
verbose_name_plural="MySubjects"
def __unicode__(self):
return self.name
def save(self,*args,**kwargs):
self.name=self.name.strip()
self.slug=slugify(self.name)
super(MySubject,self).save(*args,**kwargs)
#models.permalink
def get_absolute_url(self):
return ('subject_detail',(),{'slug':self.slug})
I need to make the creator+ name unique ,sothat I can call
subject,status=MySubject.objects.get_or_create(name__iexact=name.strip(),creator= request.user,defaults={'name':name,'description':name,'creator':request.user})
Is the following ,the right way to do this?
class MySubject(models.Model):
name=models.CharField(max_length=50)
creator = models.ForeignKey(User,null=True)
description=models.TextField(blank=True)
slug=models.SlugField(editable=False)
class Meta:
verbose_name_plural="MySubjects"
unique_together = ('name', 'creator',)
...
I guess I have to do a migration using south after making the change..Do I have to do schemamigration alone or do I have to do a datamigration?
Adding a unique constraint is a schema migration. However, if you have existing data that would cause an integrity error, you would need a data migration, as well.
If you really want case-insensitive unique constraint, it's a little more complicated:
Case insensitive unique model fields in Django?
see also: https://code.djangoproject.com/ticket/14564
If you always use get_or_create with iexact, you may be ok. But, you should not manually create two with name as "foo" and "fOo", because, this would be allowed and then your call to get_or_create would cause a MultipleObjectsReturned .. if I'm thinking correctly.

Django admin List Display + ForeignKey = Empty Change List

I've got a weird problem in django admin list_display. Whenever I add a foreign key to a list_display the whole change list view goes blank showing only the total no of entries.
models.py:
class Organization(models.Model):
org_id = models.AutoField(primary_key=True)
org_name = models.CharField(max_length=288)
def __unicode__(self):
return self.org_name
class Meta:
db_table = u'organization'
class Server(models.Model):
server_id = models.AutoField(primary_key=True)
server_name = models.CharField(max_length=135,verbose_name="Server Name")
org = models.ForeignKey(Organization,verbose_name="Organization")
def __unicode__(self):
return self.server_name
class Meta:
db_table = u'server'
admin.py:
class ServerAdmin(admin.ModelAdmin):
list_display = ('server_name','org')
admin.site.register(Server,ServerAdmin)
Now I'd expect this code to show me the organization name in the ChangeList View, But instead I get this:
If I remove the org in the list_display of ServerAdmin class, I get this:
I didn't modify the template or override any ModelAdmin methods. I'm using Mysql(5.1.58) as my database that comes with ubuntu 11.10 repository.
I'll be really glad if I could a get a sloution for this problem guys. Thanks in advance.
I second Stefano on the fact that null=True, blank=True is to be added. But, I think you only need to add it to the org_name field of the Organization model. That should make your way through. It has to be done because you have run inspectdb to create models from your legacy DB. And probably the organization table in the DB has an empty string stored. So, adding the above would allow the Admin to have a blank field/column displayed.
Moreover, you can also try using callbacks in situations where you don't want to make changes to your model definition like the above.
Try adding null=True, blank=True to all your model fields.
Usually django admin will silenty fail (thus show no records in the list) if the row does not validate the model constraints.
See: https://stackoverflow.com/a/163968/1104941
Does the following work for you?
admin.py:
class ServerAdmin(admin.ModelAdmin):
list_display = ('server_name','org__org_name')
admin.site.register(Server,ServerAdmin)
I had a similar problem and solved it like this (using your example):
class ServerAdmin(admin.ModelAdmin):
list_display = ('server_name', 'get_org')
def get_org(self, obj):
return obj.org.org_name
get_org.short_description = 'Org'
admin.site.register(Server,ServerAdmin)

Categories

Resources