How to correctly migrate custom UserModel in Django - python

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.

Related

You are trying to add a non-nullable field 'post' to stream without a default; we can't do that

I have models.py
class Stream(models.Model):
following = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='stream_following')
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
date = models.DateTimeField()
and function
def add_post(sender, instance, *args, **kwargs):
post = instance
user = post.user
followers = Follow.objects.all().filter(following=user)
for follower in followers:
stream = Stream(post=post, user=follower.follower, date=post.posted, following=user)
stream.save()
when I'm trying command py manage.py makemigrations
I have an issue.
You are trying to add a non-nullable field 'post' to stream without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit, and let me add a default in models.py
Select an option:
How to solve that? I put on default smth. However in function add_post I have added date=post.posted
Thanks!
you probably changed your models while it already have data in it
you could choose either:
a. delete data from that model and re-do migrations,or
b. delete migrations and sqlite files and re-do migrations,or
c. choose "Provide a one-off default now " by typing 1 and just add a random existing id number(but it could mess with your data),or
d. add blank=True,null=True to all fields in your models and re-do migrations,

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

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?

One model object per user Django

I don't want to extend my userprofile.
I made a new model with name, contact and email.
The problem :
With createview the user is able to create multiple instances of the user_info model.
Is there any chance we can limit user to make only one user_info and update the same everytime.
models.py
class user_info(models.Model):
booked_by = models.CharField(max_length=100)
Name = models.CharField(max_length=40)
contact = models.IntegerField()
email = models.EmailField()
views.py
class user_info_create(LoginRequiredMixin,CreateView):
login_url = 'Mel:user_login'
form_class = user_infoform
template_name = 'Mel/user_info_form.html'
def form_valid(self, form):
form.instance.booked_by = self.request.user
return super(user_info_create, self).form_valid(form)
class user_info_detail(LoginRequiredMixin,DetailView):
login_url = 'Mel:user_login'
model = user_info
context_object_name = "book"
def get_queryset(self):
return user_info.objects.filter(booked_by=self.request.user)
As mentioned by #vorujack You need to create a OneToOne relationship between user_info and your user model. The R and RDBMS stands for Relations. So you need to build relationships between models. At the moment your system doesn't have any relation between user and the profile. However, the correct syntax is
booked_by = models.OneToOneField(User)
Then you need to do
python manage.py makemigrations
python manage.py migrate
if you already have duplicate entries in the table, the second step will fail. In that case you need to clear out the duplicates and run it again. If you have invalid entries in that table, the migration will still fail. So if you don't have any critical data, you might in fact want to clear out the whole table before you do this.
Another point worth noting.
https://legacy.python.org/dev/peps/pep-0008/#id39
Class Names
Class names should normally use the CapWords convention.
The naming convention for functions may be used instead in cases where the >interface is documented and used primarily as a callable.
Note that there is a separate convention for builtin names: most builtin names are single words (or two words run together), with the CapWords convention used only for exception names and builtin constants.
So your classes should really be UserInfo and UserInfoCreate
you can make a relation to your user model like this:
class user_info(models.Model):
booked_by = models.OneToOneField(User)
Name = models.CharField(max_length=40)
contact = models.IntegerField()
email = models.EmailField()
on create view set booked_by field with current user. with this change if user want to create multiple user_info it raised exception and no user_info inserted
Thank you vorujack and e4c5.
Just by doing OneToOneField is not solving the entire problem.
The below code really solved my problem.
If its not correct or can be done in a better way please let me know.
model.py
booked_by = models.OneToOneField(User)
views.py
class user_RedirectView(LoginRequiredMixin,RedirectView):
def get_redirect_url(self):
if user_info.objects.filter(booked_by=self.request.user).exists():
return reverse('Mel:user_update')
else:
return reverse('Mel:user_info_create')

Can't disable ForeignKey referential integrity check in Django 1.9

I have a model with two entities, Person and Code. Person is referenced by Code twice, a Person can be either the user of the code or the approver.
What I want to achieve is the following:
if the user provides an existing Person.cusman, no further action is needed.
if the user provides an unknown Person.cusman, a helper code looks up other attributes of the Person (from an external database), and creates a new Person entity.
I have implemented a function triggered by pre_save signal, which creates the missing Person on the fly. It works fine as long as I use python manage.py shell to create a Code with nonexistent Person.
However, when I try to add a new Code using the admin form or a CreateView descendant I always get the following validation error on the HTML form:
Select a valid choice. That choice is not one of the available choices.
Obviously there's a validation happening between clicking on the Save button and the Code.save() method, but I can't figure out which is it. Can you help me which method should I override to accept invalid foreign keys until pre_save creates the referenced entity?
models.py
class Person(models.Model):
cusman = models.CharField(
max_length=10,
primary_key=True)
name = models.CharField(max_length=30)
email = models.EmailField()
def __unicode__(self):
return u'{0} ({1})'.format(self.name, self.cusman)
class Code(models.Model):
user = models.ForeignKey(
Person,
on_delete=models.PROTECT,
db_constraint=False)
approver = models.ForeignKey(
Person,
on_delete=models.PROTECT,
related_name='approves',
db_constraint=False)
signals.py
#receiver(pre_save, sender=Code)
def create_referenced_person(sender, instance, **kwargs):
def create_person_if_doesnt_exist(cusman):
try:
Person = Person.objects.get(pk=cusman)
except Person.DoesNotExist:
Person = Person()
cr = CusmanResolver()
Person_details = cr.get_person_details(cusman)
Person.cusman = Person_details['cusman']
Person.name = Person_details['name']
Person.email = Person_details['email']
Person.save()
create_Person_if_doesnt_exist(instance.user_id)
create_Person_if_doesnt_exist(instance.approver_id)
views.py
class CodeAddForm(ModelForm):
class Meta:
model = Code
fields = [
'user',
'approver',
]
widgets = {
'user': TextInput,
'approver': TextInput
}
class CodeAddView(generic.CreateView):
template_name = 'teladm/code_add.html'
form_class = CodeAddForm
You misunderstood one thing: You shouldn't use TextField to populate ForeignKey, because django foreign keys are populated using dropdown/radio button to refer to the id of the object in another model. The error you got means you provided wrong information that doesn't match any id in another model(Person in your case).
What you can do is: not using ModelForm but Form. You might have some extra work to do after you call form.is_valid(), but at least you could code up your logic however you want.

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