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.
Related
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?
I'm using django_filters for an advanced search and select2Widget to display the options of a foreign key field.
The proper values load but whenever I submit the form I get an error message: Select a valid choice. That choice is not one of the available choices.
The error might seem pretty obvious but I can't find out how to solve it. Any suggestions?
filters.py
class MyFilter(django_filters.FilterSet):
b = django_filters.ModelChoiceFilter(
queryset=ModelA.objects.values_list('b__name', flat=True)
widget=Select2Widget()
)
class Meta:
model = ModelA
fields = ('b',)
models.py
class ModelA(models.Model):
b = models.ForeignKey('ModelB', on_delete=models.CASCADE)
class ModelB(models.Model):
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
AS user #dirkgroten pointed out in a comment to the question, the following line looks strange:
queryset=ModelA.objects.values_list('b__name', flat=True)
This way the widget has no way of knowing the pk of each element of the list (since it only return the names). That might couse that the view cannot save a selected ModelB instance, since it does not know the selected pk.
Ah, you might also want to use ModelB instead of ModelA
Try changing it to something like this
queryset=ModelB.objects.values('pk', 'b__name')
or even this
queryset=ModelB.objects.all()
and let us know if that works.
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')
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.
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)