I have one Category model that I'd like to use in other models instead of creating different models for each case.
Each model (Page, Article,...) has its own set of categories.
Table Category
id
content_type (Article, Page,...)
Table Page
id
category_id (form select filter with content_type Page)
Table Article
id
category_id (form select filter with content_type Article)
I can't use a polymorphic relationship since I don't have to store the id.
So how can I represent that in my models?
This is possible like this:
class Category(models.Model):
name = models.CharField(max_length=255)
class ContentTypes(models.TextChoices):
PAGE = 'Page'
ARTICLE = 'Article'
RECIPE = 'Recipe'
content_type = models.CharField(
max_length=64,
choices=ContentTypes.choices,
default=ContentTypes.PAGE,
)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Page(models.Model):
name = models.CharField(max_length=255)
category = models.ForeignKey(
Category,
null=True,
on_delete=models.SET_NULL,
limit_choices_to={'content_type': 'Page'},
)
def __str__(self):
return self.name
Related
I dont want any foreign keys directly in my users table, and by default, when I add a foreing key field in my custom User model, Django generate 2 tabels like this:
When I add a many-to-many field in my Company model I get the 3 desired tables but it's made possible for the same user be in two different companys.
class Company(models.Model):
class Meta:
verbose_name = 'Company'
verbose_name_plural = 'Companys'
ordering = ['name']
db_table = 'companys'
id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, unique=True, verbose_name='ID Empresa')
name = models.CharField(max_length=100, verbose_name='Nome')
users = models.ManyToManyField(User, related_name='company', verbose_name='Users')
def __str__(self):
return self.name
I want Django to generate an additional table with only the Foreing Keys of the two models but keep the behevior of a many-to-one relationship between the two. like this:
you can make your third table by using a separate model
class Company(models.Model):
class Meta:
verbose_name = 'Company'
verbose_name_plural = 'Companys'
ordering = ['name']
db_table = 'companys'
id = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, unique=True, verbose_name='ID Empresa')
name = models.CharField(max_length=100, verbose_name='Nome')
def __str__(self):
return self.name
class UserCompanyRelationModel(models.Model):
class Meta:
db_table = 'usr_comp'
user = models.OneToOneField(User, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
So i basically have a model called Designations that derives foreign keys from 3 other models (curricula, role and staff) and i am trying to save a new record into the Designations model, the code below shows the Designations and Staffs model. However, for the Curriculum and role models i will not be showing as you can assume PK 1 in Curriula and role models will be used as data in the curriculum and role fields in Designation model
class Designations(models.Model):
designation_id = models.AutoField(primary_key=True)
curriculum = models.ForeignKey(Curricula, on_delete=models.CASCADE)
role = models.ForeignKey(Roles, on_delete=models.CASCADE)
staff = models.ForeignKey(Staffs, on_delete=models.CASCADE)
class Meta:
db_table = "arc_designations"
unique_together = ('curriculum', 'role', 'staff')
verbose_name_plural = "Designations"
ordering = ['designation_id']
def __str__(self):
return '%s of %s %s (%s)' % (self.role.role_name,
self.curriculum.course_period.course.course_abbreviation,
self.curriculum.module_period.module.module_abbreviation,
self.staff.staff_full_name)
class Staffs(models.Model):
staff_id = models.AutoField(primary_key=True)
admission_number = models.CharField(max_length=5,
unique=True,
help_text="Enter 5 digits",
validators=[numeric_only, MinLengthValidator(5)])
staff_full_name = models.CharField(max_length=70,
help_text="Enter staff's full name",
validators=[letters_only])
created_by = UserForeignKey(auto_user_add=True,
editable=False,
related_name="staff_created_by",
db_column="created_by")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_by = UserForeignKey(auto_user=True,
editable=False,
related_name="staff_updated_by",
db_column="updated_by")
updated_at = models.DateTimeField(auto_now=True,
editable=False)
roles = models.ManyToManyField(Roles, through='Designations')
class Meta:
db_table = "arc_staffs"
verbose_name_plural = "Staffs"
ordering = ['staff_id']
def __str__(self):
return '%s (S%s)' % (self.staff_full_name, self.admission_number)
I have made a forms.py to get the admission_number(field in Staffs model)
class AssignRolesForm(forms.Form):
admission_no = forms.CharField(max_length=40,
widget=forms.TextInput(
attrs={'class': 'form-control', 'aria-describedby': 'add-btn'}))
Assuming that when i submit the form i would like for the admission_number entered in the form to reference into the Staffs model then get its PK to be saved into the staff field in Designations then as i said above, for the curriculum and role fields to referece PK 1 of their respective models. How would i write my function in views.py
**edit
I've tried writing out the view as suggested, heres the code below, currently i cant test my project so let me now if its correct
#require_POST
def setStaff(request):
form = AssignRolesForm(request.POST)
if form.is_valid():
Designations.staff = Staffs.objects.filter(admission_number=form.cleaned_data['admission_no'])
Designations.role = Roles.objects.get(pk=1)
Designations.curriculum = Curricula.objects.get(pk=1)
Designations.save()
return redirect('index')
Overriding the clean function on forms is probably where you want to put your logic. The django docs have a good example:
https://docs.djangoproject.com/en/2.0/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
I have a product model, category model and a product_category model for storing the product id to multiple categories.
models.py
class Product(models.Model):
title = models.CharField(max_length=255, blank=True)
slug = models.SlugField(_('Slug'), max_length=255, unique=False)
class Category(models.Model):
name = models.SlugField(_('Slug'), max_length=255, unique=False)
class ProductCategory(models.Model):
product = models.ForeignKey('catalogue.Product', verbose_name=_("Product"))
category = models.ForeignKey('catalogue.Category', verbose_name=_("Category"))
My serializers.py
class MyProductLinkCustomSerializer(ProductLinkSerializer):
class Meta(ProductLinkSerializer.Meta):
fields = ('url', 'id', 'product_id', 'title',)
views.py
class ProductListCustom(basic.ProductList):
def get_queryset(self):
category_id = self.request.query_params.get('category_id', None)
#filter products with this category_id, if someone provided category_id in url
return Product.objects.all()
serializer_class = MyProductLinkCustomSerializer
I want to list the products with category object for each product belongs to. Also I want to filter the products by the category_id it belongs.
Actually, I think you should consider: using models.ManyToManyField to link category and product.
class Product(models.Model):
title = models.CharField(max_length=255, blank=True)
slug = models.SlugField(_('Slug'), max_length=255, unique=False)
categories = models.ManyToManyField(Category, related_name='products')
Then, you can filter products like this:
Product.objects.filter(categories=category_id)
here is some useful example for ManyToManyField
Suppose I have the following models:
class Product(models.Model):
tags = models.CharField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
type = models.ForeignKey(ContentType, related_name='type')
class Flash(models.Model):
name = models.CharField(max_length=50)
class Lense(models.Model):
name = models.CharField(max_length=50)
Is it possible in django admin, instead of having pk to the type field on the Product form, to have all the forms that model with that pk has?
You didn't post ContentType model and you probably didn't set uncode for the model
class ContentType(models.Model):
title = models.CharField(max_length=200)
...
def __unicode__(self):
return self.title
If you do as above you will see Product titles instead of pk
I have a polling app with one of the models "Choice" consisting of 2 Foreign key fields linked to the "Person" model.
I wanted to automatically populate related "photo_other" field (with the image link) once I have selected the "name" of the person. "name" is also a Foreign Key Field linked with Choice model.
models.py
class Choice(models.Model):
name = models.ForeignKey(Person)
photo_other = models.ForeignKey(Person)
rating = models.DateTimeField(blank=True, null=True)
def __unicode__(self):
return smart_unicode(self.name)
class Person(models.Model):
name = models.CharField(max_length=250)
photo = models.ImageField(upload_to="photos")
pub_date = models.DateTimeField()
def __unicode__(self):
return smart_unicode(self.name)
Why do you want to store the same value in two different tables when they are connected through a foreign key? It just doesn't make sense.
class Choice(models.Model):
name = models.ForeignKey(Person)
rating = models.DateTimeField(blank=True, null=True)
#property
def photo_other(self):
return self.name.photo
class Person(models.Model):
name = models.CharField(max_length=250)
photo = models.ImageField(upload_to="photos")
pub_date = models.DateTimeField()
In order to make photo_other visible under the admin page of Choice model, you can do the following;
class ChoiceAdmin(admin.ModelAdmin):
list_display = ['name', 'rating', 'get_photo']
def get_photo(self, obj):
return obj.photo_other
get_photo.short_description = 'Photo'