I have the below models:
# Child
class Media (models.Model):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=128,unique=True)
file = models.FileField()
enabled = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
# Parent
class Gallery(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=128,unique=True)
description = models.TextField(max_length=254,null=True)
medias = models.ManyToManyField(Media,related_name='medias')
enabled = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "gallery"
verbose_name_plural = "galleries"
def __str__(self):
return self.name
I would like to be able to sort the child table by setting it in junction table; therefore not affecting the child table. I'm thinking of setting position field in junction table, is manually adding it in DB the only way of doing that? I'm fairly new to Django and I'm sorry in advance if this happens to be just a basic question.
Usual ManyToMany doesn't work here, because association table should contain order. So, this case you have to bring through to the mix:
class Gallery(models.Model):
medias = models.ManyToManyField('Media',related_name='medias', through='ChildGallery')
Where ChildGallery is a join model:
class ChildGallery(models.Model):
child = models.ForeignKey(Child)
gallery = models.ForeignKey(Gallery)
order = models.IntegerField()
class Meta:
ordering = ['order']
I don't know how you would like to implement order, but if it's just a number, you could use IntegerField as I showed above.
P.S. Note I wrapped all association models in quotes (like 'Child' not Child). It allows to break circular dependencies, so I recommend to use this way
Related
I have Three model defined. I want to filter Get specific user and get all related fields in the result set. For example, I want to get supplierInfo and company info of that user.
class User(AbstractBaseUser):
user_email= models.EmailField(unique=True, max_length=254)
user_id = models.AutoField(primary_key=True)
staff=models.BooleanField(default=True)
admin=models.BooleanField(default=True)
role_id=models.IntegerField(default=0)
supplier=models.ForeignKey(Supplier, on_delete=models.CASCADE) ....
class Company(models.Model):
company_name= models.CharField(('company name'), max_length=255, blank=True)
company_id = models.AutoField(primary_key=True)
class Meta:
verbose_name = ('company')
verbose_name_plural = ('company')
db_table = "company"
def __str__(self):
return self.company_name
class Supplier(models.Model):
supplier_name= models.CharField(('supplier name'), max_length=255, blank=True)
supplier_id = models.AutoField(primary_key=True)
company=models.ForeignKey(Company, on_delete=models.CASCADE)
class Meta:
verbose_name = ('supplier')
verbose_name_plural = ('supplier')
db_table = "supplier"
def __str__(self):
return self.supplier_name
I Have tried this
userInfo=User.objects.filter(user_id__exact=user.user_id).get()
userRelated= Supplier.objects.filter(supplier_id__exact=userInfo.supplier_id).get()
companyRelated=Company.objects.filter(company_id__exact=userRelated.company_id).get()
I am getting expected result But I dont think it is the best way. I want to merge three queries and get the result in one object . I am new in django so please help me out.
You can create a one to one relationship by defining a foreign key.
https://docs.djangoproject.com/en/3.0/topics/db/examples/one_to_one/
The documentation is really well written and i suggest you take a look for yourself.
If you do this you will have access to the related table when using the typical django orm methods.
I am trying to create a Many to Many relation with a model in between, I have a Client model, and a Zone model, each client may have access to different zones, and each zone may have multiple clients.
Therefore I created a model called Access Permission, that stores said relation, and I want to show a dropdown selector in the post form that shows the existing clients and zones, or to ask for the Id of an existing object, instead of showing the form to create new ones.
These are my models:
class Zone(models.Model):
name = models.TextField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class Client(models.Model):
name = models.TextField()
birthDate = models.DateField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class AccessPermission(models.Model):
idClient = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
idZone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
And these my current serializers:
class ZoneSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Zone
fields = ('name',)
class ClientSerializer(serializers.HyperlinkedModelSerializer):
zones = ZonesSerializer(source='accesspermission_set', many=True, read_only=True)
class Meta:
model = Client
fields = ('name', 'birthDate', 'zones')
class AccessPermissionSerializer(serializers.ManyRelatedField):
idClient = ClientSerializer(many=False)
idZone = ZoneSerializer(many=False)
class Meta:
model = AccessPermission
fields = ('idClient', 'idZone')
Is there any way to ask for the Id of an existing object, or show the existing ones, instead of the fields to create new ones?
You can do it like:
models
class AccessPermission(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
zone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
serializers
class AccessPermissionSerializer(serializers.ManyRelatedField):
id = serializers.IntegerField(read_only=True)
client_id = serializers.PrimaryKeyRelatedField(
queryset=Client.objects.all(), source='client', allow_null=False, required=True
)
zone_id = serializers.PrimaryKeyRelatedField(
queryset=Zone.objects.all(), source='zone', allow_null=False, required=True
)
class Meta:
model = AccessPermission
fields = (
'id', 'client_id', 'zone_id'
)
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.
I have a scenario where I need to move the data from one model (Old model where some data already exist) to another model and in turn to another model if necessary.how can I add this process in migration file so,that I can accomplish the requirement with just python manage.py migrate command.
this is the model where All the old items exist:
class UserFavorite(CreatedAtMixin):
user = models.ForeignKey('auth.User')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
objects = UserFavoriteManager()
def __str__(self):
try:
return str(self.content_object)
except AttributeError:
return 'None'
class Meta:
get_latest_by = "date_added"
unique_together = ("user", "content_type", "object_id")`
Here is the model where I need to insert item first, per item in above model:
class CollectionItem(models.Model):
sort_number=models.PositiveIntegerField(blank=True,null=True)
type=models.CharField(max_length=20,null=False, blank=False)
item_type = models.ForeignKey(ContentType, limit_choices_to=models.Q(app_label='news', model='News') | models.Q(app_label='work', model='Work') | models.Q(app_label='collection', model='Quote'))
item_id = models.PositiveIntegerField()
item = generic.GenericForeignKey('item_type', 'item_id')
class Meta:
verbose_name = "Collection Item"
verbose_name_plural = "Collection Items"
def __str__(self):
return self.item.title
then I need to insert that into:
class Collections(CreatedAtMixin):
user = models.ForeignKey('auth.User', related_name='collections_user')
collection_place=models.ForeignKey('companies.CompanyOffice',related_name='collections_place',null=True)
collection_name = models.CharField(max_length=40,null=False, blank=False)
description = models.TextField(null=True, blank=True)
items=models.ManyToManyField('collection.CollectionItem')
def __str__(self):
return self.collection_name
class Meta:
unique_together = ("user","collection_name")
verbose_name = "Collection"
verbose_name_plural = "Collections"
ordering = [ '-created_at']
get_latest_by = "created_at"
First write your new models and create a schema migration.
Then create a data migration and write the required code to transfert your old models data to the new models (hint: if possible, also write the code to revert your migration).
Finally - assuming the old models are not used anymore -, remove the old models code and create a last schema migration.
The details are all documented in the above links, and what's left is specific to your application so we cannot help further.
I have 3 inherited classes (Fitters -> Workers -> Staffs) connected with tables in my Database (class names in the plural, but that's not important now).
User can add/edit/remove only Fitters. The Workers and Staffs tables are updated automatically (cascaded).
It works fine: when I add new Fitter, all changes come to all tables in database. But when I want to edit any Fitter via Django admin tool, I go to edit Fitter page and I see incorrectly filled fields.
For example:
In Staffs table I have "John Smith" with id=41
In Workers table I have the record with id=21 and ForeignKey=41 (to John Smith)
In Fitters table I have the record with id=5 and ForeignKey=21 (to record in Workers table)
When I go to edit Fitter "John Smith" page, I see all fields filled by "Kevin Thomas" (id=21 in Staffs table!).
So, Django misses the Workers table and goes directly to the Staffs table.
How can I fix it?
Here is my draft code:
class Staffs(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=135, blank=True)
surname = models.CharField(max_length=135, blank=True)
def __unicode__(self):
return self.name + " " + self.surname
class Meta:
db_table = u'staffs'
class Workers(Staffs):
idWorker = models.AutoField(primary_key=True, db_column='id')
staffs_idstaff = models.OneToOneField('Staffs', db_column='Staffs_idstaff', parent_link=True)
brigades_idbrigade = models.ForeignKey('Brigades', db_column='Brigades_idBrigade')
def __unicode__(self):
return self.staffs_idstaff.name + " " + self.staffs_idstaff.surname
class Meta:
db_table = u'workers'
class Fitters(Workers):
idFitter = models.AutoField(primary_key=True, db_column='id')
qualification = models.CharField(max_length=135, blank=True)
workers_idworker = models.OneToOneField('Workers', db_column='Workers_idWorker', parent_link=True)
def __unicode__(self):
staff = self.workers_idworker.staffs_idstaff
return staff.name + " " + staff.surname
class Meta:
db_table = u'fitters'
EDIT1:
I tried to change my code like this:
class Staffs(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=135, blank=True)
surname = models.CharField(max_length=135, blank=True)
class Meta:
db_table = u'staffs'
class Workers(Staffs):
idWorker = models.AutoField(primary_key=True)
brigades_idbrigade = models.ForeignKey('Brigades')
class Meta:
db_table = u'workers'
class Fitters(Workers):
idFitter = models.AutoField(primary_key=True)
qualification = models.CharField(max_length=135, blank=True)
class Meta:
db_table = u'fitters'
It's pretty simple now. I synced my database, but I have the absolutely same problem!
EDIT2:
Part of my admin.py file:
from django.contrib import admin
from appclient.models import *
admin.site.register(Fitters)
admin.site.register(Staffs)
admin.site.register(Workers)
...
SOLUTION:
Solution is I don't need use my own id's and ForeignKey's for each model. Djando automatically creates special field for each model and uses it as an id (PrimaryKey) and for link to the parent tables (ForeignKey).
Here is solution:
class Staffs(models.Model):
name = models.CharField(max_length=135, blank=True)
surname = models.CharField(max_length=135, blank=True)
class Meta:
db_table = u'staffs'
class Workers(Staffs):
brigades_idbrigade = models.ForeignKey('Brigades')
class Meta:
db_table = u'workers'
class Fitters(Workers):
qualification = models.CharField(max_length=135, blank=True)
class Meta:
db_table = u'fitters'
Thanks to everyone who helped me.
This does seem somewhat strange. However, as far as I understand, Django will automatically setup the required one-to-one mappings between parents and children, when using multi-table inheritance. As you have also set these up manually, it might very well be that some kind of inconsistency is introduced due this.
If you take a look directly in the database, are the two different one-to-one relations consistent?
What happens if you remove the explicit one-to-one fields from your models?