I am working on a set of product / category relationships in a Django application.
A product can belong to any category and needs to be ordered within that category, I am trying to do this using a Many to Many relationship with a "through=" option.
When a POST request is made via Ajax it takes the form of b'ordered_products=4&ordered_products=5', I received an error straight after the forms __init__ call that "5 is not one of the available choices" where 5 is the valid id of anOrderedCategoryManagedProduct object.
models.py
class Category(models.Model):
name = models.CharField(max_length=128)
slug = models.SlugField(max_length=128, unique=True)
class Product(models.Model):
name = models.CharField(max_length=128)
category_management = models.ManyToManyField(
Category,
related_name="category_managed_products",
through="OrderedCategoryManagedProduct",
blank=True,
verbose_name="Category Management",
)
class OrderedCategoryManagedProduct(SortableModel):
category = models.ForeignKey(
Category, on_delete=models.CASCADE, related_name="cm_products"
)
product = models.ForeignKey(
Product, on_delete=models.CASCADE, related_name="cm_categories"
)
class Meta:
ordering = ["sort_order"]
def get_ordering_queryset(self):
return self.product.category_management()
class SortableModel(models.Model):
sort_order = models.IntegerField(db_index=True, null=True)
class Meta:
abstract = True
views.py
# POST = <QueryDict: {'ordered_products': [5, 4]}>
#staff_member_required
#permission_required("menu.manage_menus")
def ajax_reorder_menu_items(request, category_pk):
category = get_object_or_404(Category, pk=category_pk)
form = ReorderCategoryProductsForm(request.POST, instance=category)
status = 200
ctx = {}
if form.is_valid():
form.save()
elif form.errors:
status = 400
ctx = {"error": form.errors}
return JsonResponse(ctx, status=status)
forms.py
class ReorderCategoryProductsForm(forms.ModelForm):
ordered_products = OrderedModelMultipleChoiceField(
queryset=OrderedCategoryManagedProduct.objects.none()
)
class Meta:
model = Category
fields = ["id"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance:
self.fields["ordered_products"].queryset = self.instance.cm_products.all()
pass
def save(self):
for sort_order, category in enumerate(self.cleaned_data["ordered_products"]):
category.cm_products.sort_order = sort_order
category.save()
return self.instance
class OrderedModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def clean(self, value):
qs = super().clean(value)
keys = list(map(int, value))
return sorted(qs, key=lambda v: keys.index(v.pk))
Big thanks to the #django IRC channel for the help on this, if anyone suffers the same problem the correct code was as follows:
class ReorderCategoryProductsForm(forms.ModelForm):
ordered_products = OrderedModelMultipleChoiceField(
queryset=OrderedCategoryManagedProduct.objects.all()
)
class Meta:
model = Category
fields = ["id"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance:
self.fields["ordered_products"].queryset = self.instance.cm_products.all()
pass
def save(self):
for sort_order, ocmp in enumerate(self.cleaned_data["ordered_products"]):
ocmp.sort_order = sort_order
ocmp.save()
return self.instance
Related
I designed a database for my django ecommerce project but it have some problems, the goal of
the this design is to have products with different specifications for example a mobile cell has it's own properties and a television too,
it is my models.py:
'''
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
from django.shortcuts import reverse
from model_utils import FieldTracker
from . import uploaders
class Category(MPTTModel):
name = models.CharField(max_length=50, unique=True)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True,
related_name='children')
slug = models.SlugField(max_length=75, unique=True)
tracker = FieldTracker(fields=['name'])
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
category_names = [self.name]
node = self
while node.parent:
node = node.parent
category_names.append(node.name)
return ' / '.join(category_names[::-1])
def get_absolute_url(self):
return reverse('product_by_category', args=(self.slug,))
class ProductType(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class ProductSpecifications(models.Model):
name = models.CharField(max_length=50)
product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE,
related_name='specifications')
class Meta:
unique_together = ('name', 'product_type')
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=100, unique=True)
product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE,
related_name='products')
category = models.ForeignKey(Category, on_delete=models.CASCADE,
related_name='products')
price = models.PositiveBigIntegerField()
discount_price = models.PositiveBigIntegerField(null=True, blank=True)
description = models.TextField(null=True, blank=True)
image = models.ImageField(upload_to=uploaders.product_img_uploader)
slug = models.SlugField(max_length=150, unique=True)
tracker = FieldTracker(fields=['slug', 'name', 'product_type'])
def __str__(self):
return self.name
def set_discount(self, percentage):
self.discount_price = self.price * (1 - percentage)
self.save()
#property
def is_discounted(self):
return bool(self.discount_price)
def remove_discount(self):
self.discount_price = None
self.save()
class ProductSpecificationValue(models.Model):
specification = models.ForeignKey(ProductSpecifications, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE,
related_name='specifications')
value = models.CharField(max_length=75, null=True, blank=True)
def __str__(self):
return ''
class Meta:
unique_together = ('specification', 'product')
'''
And admin.py:
'''
from django.contrib import admin
from django.http import HttpResponseRedirect
from mptt.admin import MPTTModelAdmin
from .models import *
from .forms import ProductSpecForm
#admin.register(Category)
class CategoryAdmin(MPTTModelAdmin):
readonly_fields = ('slug',)
class SpecificationInline(admin.TabularInline):
model = ProductSpecifications
extra = 2
#admin.register(ProductType)
class ProductTypeAdmin(admin.ModelAdmin):
inlines = (SpecificationInline,)
class SpecificationValueInline(admin.TabularInline):
model = ProductSpecificationValue
# form = ProductSpecForm
# fields = ('specification', 'value')
# readonly_fields = ('specification',)
#
# def has_add_permission(self, request, obj):
# return False
#
# def has_delete_permission(self, request, obj=None):
# return False
#admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
inlines = (SpecificationValueInline,)
readonly_fields = ('slug',)
# def response_post_save_add(self, request, obj):
# return HttpResponseRedirect(
# reverse("admin:%s_%s_change" % (self.model._meta.app_label,
# self.model._meta.model_name), args=(obj.id,)))
'''
the problem is in product admin panel when you want to add or change a product, I want the select box for specification in SpecificationValueInline form show me only specifications related to the product type not all specifications in db, the lines that I commented in admin.py with some signals and a form was my approach to solve this issue i dont know if it was the best help me please!
signals.py:
'''
from django.dispatch import receiver
from django.db.models.signals import pre_save, post_save
from .models import Category, Product, ProductSpecificationValue, ProductSpecifications
#receiver(pre_save, sender=Product)
#receiver(pre_save, sender=Category)
def initialize_slug(sender, instance, *args, **kwargs):
if (not instance.slug) or (instance.tracker.has_changed('name')):
instance.slug = instance.name.replace(' ', '_')
#receiver(post_save, sender=Product)
def initialize_specifications(sender, instance, created, **kwargs):
if created:
product_type = instance.product_type
for specification in product_type.specifications.all():
ProductSpecificationValue.objects.create(product=instance,
specification=specification)
elif instance.tracker.has_changed('product_type'):
ProductSpecificationValue.objects.filter(product=instance).delete()
product_type = instance.product_type
for specification in product_type.specifications.all():
ProductSpecificationValue.objects.create(product=instance,
specification=specification)
#receiver(post_save, sender=ProductSpecifications)
def add_new_specs_to_related_products(sender, instance, created, **kwargs):
if created:
product_type = instance.product_type
for product in product_type.products.all():
ProductSpecificationValue.objects.create(specification=instance,
product=product)
'''
forms.py:
'''
from django import forms
from django.forms import ModelChoiceField
from .models import ProductSpecificationValue, Product
class ProductSpecForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if hasattr(self.instance, 'product'):
self.fields['specification'] = ModelChoiceField(
queryset=self.instance.product.product_type.specifications.all())
class Meta:
model = ProductSpecificationValue
fields = ('specification', 'value')
'''
you can use formfield_for_foreignkey in SpecificationValueInline
class SpecificationValueInline(admin.TabularInline):
model = ProductSpecificationValue
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "specification":
product_id = request.resolver_match.kwargs.get('object_id')
productType = Product.objects.get(id = product_id).product_type
kwargs["queryset"] = ProductSpecification.objects.filter(product_type=productType)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
mohsen ma answer was usefull I made some changes and it got better but I still doubt it it is enough or best practice, if user changes the product type he/she should stay on change page to fill the specification idk how:
'''
#receiver(post_save, sender=Product)
def sync_specs_with_type(sender, instance, created, **kwargs):
if created or instance.tracker.has_changed('product_type'):
if not created:
instance.specifications.all().delete()
for spec in instance.product_type.specifications.all():
ProductSpecificationValue.objects.create(product=instance, specification=spec)
class SpecificationValueInline(admin.TabularInline):
model = ProductSpecificationValue
extra = 0
def formfield_for_foreignkey(self, db_field, request, **kwargs):
product_id = request.resolver_match.kwargs.get('object_id')
if product_id and db_field.name == "specification":
product_type = Product.objects.get(id=product_id).product_type
kwargs["queryset"] = ProductSpecifications.objects.filter(product_type=product_type)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
#admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
readonly_fields = ('slug',)
inlines = (SpecificationValueInline,)
def response_post_save_add(self, request, obj):
messages.add_message(request, messages.INFO, 'set you product specifications')
return HttpResponseRedirect(
reverse("admin:%s_%s_change" % (self.model._meta.app_label, self.model._meta.model_name), args=(obj.id,)))
def get_inlines(self, request, obj):
if obj:
return super().get_inlines(request, obj)
return ()
'''
I have been attempting to import data into my Django project using Django import-export. I have two models Ap and Job, Job has a FK relationship with Ap. Using the Admin, I can select the file and the type, CSV. So far my program seems to run, but gets hung up on the FK. I'm close, something is off and causing the import script to fail.
Models.py
class Ap(models.Model):
line_num = models.IntegerField()
vh = models.IntegerField()
vz = models.IntegerField()
status = models.CharField(
choices=statuses, default="select", max_length=40)
classified = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Job(models.Model):
aplink = models.ForeignKey(Ap, related_name=(
"job2ap"), on_delete=models.CASCADE)
job_num = models.IntegerField()
description = models.CharField(max_length=200)
category = models.CharField(
choices=categories, default="select", max_length=40)
status = models.CharField(
choices=statuses, default="select", max_length=40)
dcma = models.BooleanField(default=False),
due_date = models.DateField(blank=True),
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
views.py
class ImportView(View):
def get(self, request):
form = ImportForm()
return render(request, 'importdata.html', {'form': form})
def post(self, request):
form = ImportForm(request.POST, request.FILES)
job_resource = JobResource()
data_set = Dataset()
if form.is_valid():
file = request.FILES['import_file']
imported_data = data_set.load(file.read())
result = job_resource.import_data(
data_set, dry_run=True) # Test the data import
if not result.has_errors():
job_resource.import_data(
data_set, dry_run=False) # Actually import now
else:
form = ImportForm()
return render(request, 'importdata.html', {'form': form})
resource.py
class CharRequiredWidget(widgets.CharWidget):
def clean(self, value, row=None, *args, **kwargs):
val = super().clean(value)
if val:
return val
else:
raise ValueError('this field is required')
class ForeignkeyRequiredWidget(widgets.ForeignKeyWidget):
def clean(self, value, row=None, *args, **kwargs):
if value:
print(self.field, value)
return self.get_queryset(value, row, *args, **kwargs).get(**{self.field: value})
else:
raise ValueError(self.field + " required")
class JobResource(resources.ModelResource):
aplink = fields.Field(column_name='aplink', attribute='aplink', widget=ForeignkeyRequiredWidget(Ap,'id'),
saves_null_values=False)
job_num = fields.Field(saves_null_values=False, column_name='job_num', attribute='job_num',
widget=widgets.IntegerWidget())
description = fields.Field(column_name='description', attribute='description', saves_null_values=False,
widget=CharRequiredWidget())
class Meta:
model = Job
fields = ('aplink', 'job_num', 'description',)
clean_model_instances=True
admin.py
class JobResource(resources.ModelResource):
class Meta:
model=Job
fields=('aplink','job_num','description',)
class JobAdmin(ImportExportModelAdmin):
resource_class = JobResource
admin.site.register(Job, JobAdmin)
CSV file, data to import. I have tried leaving the first column empty, as will as putting the Id of the only Ap stored in the table ie 1. I have also tried hard coding the line_num, which is 1200 the first column as well.
CSV file for importing data:
Date importing errors:
In your resources, while defining fields, you need to include id field in the list. So change JobResource to the following:
class JobResource(resources.ModelResource):
class Meta:
model = Job
fields = ('id', 'aplink', 'job_num', 'description')
If you have defined a custom id field, then you will need to provide:
import_id_fields = ('your_id_field')
I am quite new with Django and I need help.
My problem is quite similar what Mike had in his case:
UpdateView not populating form with existing data, but I have not found solution yet.
My goal is to view owner dropdown selection list only those users who are members of the organization.
models.py
# organizations.models.py
...
from accounts.models import User
from core.models import TimeStampModel
...
class Organization(TimeStampModel, models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(
verbose_name=_('Name'),
max_length=255,
unique=True
)
code = models.CharField(
verbose_name=_('Code'),
max_length=255,
null=True,
blank=True
)
owner = models.ForeignKey(
User,
on_delete=models.PROTECT,
verbose_name=_('Owner'),
related_name='owner',
help_text=_('Organization Owner and Contact Person'),
)
slug = models.SlugField(verbose_name=_('Organization key'), unique=True)
...
class Meta:
verbose_name = _('Organization')
verbose_name_plural = _('Organization')
ordering = ['name', 'code']
def __str__(self):
return f'{self.name}, {self.code}'
# Create automatically slug value from organization name field.
# In case similar is exist then add extra count digit end of slug.
def _get_unique_slug(self):
slug = slugify(self.name)
unique_slug = slug
num = 1
while Organization.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, num)
num += 1
return unique_slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self._get_unique_slug()
self.next_update = timezone.now() + relativedelta(
months=self.update_interval)
super(Organization, self).save(*args, **kwargs)
def get_absolute_url(self):
kwargs = {
'slug': self.slug
}
return reverse('organization_main_page', kwargs=kwargs)
class OrganizationMembers(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
organization = models.ForeignKey(
Organization,
on_delete=models.CASCADE,
verbose_name=_('Organization')
)
member = models.ForeignKey(
User,
on_delete=models.CASCADE,
verbose_name=_('Member'),
null=True,
blank=True
)
organization_admin = models.BooleanField(
verbose_name=_('Organization admin'),
default=False
)
class Meta:
verbose_name = _('Organization: Member')
verbose_name_plural = _('Organization: Members')
ordering = ['organization', 'member']
unique_together = ('organization', 'member')
def __str__(self):
return f'{self.member}'
def get_absolute_url(self):
kwargs = {
'slug': self.slug
}
return reverse('organization_detail', kwargs=kwargs)
forms.py
# organizations.forms.py
....
from accounts.models import User
from .models import Organization, OrganizationMembers
...
class OrganizationUpdateForm(forms.ModelForm):
class Meta:
model = Organization
fields = '__all__'
exclude = ('date_created', 'created_by', 'created_by_id',
'last_updated', 'last_updated_by', 'last_updated_by_id',
'next_update', 'slug')
# Restrict user selection lists to view only members of the organization
def __init__(self, *args, **kwargs):
inst = kwargs.get('instance', None)
super(OrganizationUpdateForm, self).__init__(*args, **kwargs)
self.fields['owner'].queryset = OrganizationMembers.objects.\ # <--- !!!
filter(organization_id=inst.id)
In the forms.py, if I comment out self.field['owner]... line, then owner field will show saved value from database, but then I can see all users in the dropdown list. When queryset is enabled then selection list show correct users, but saved value is not visible.
views.py
# organizations.views.py
from .forms import OrganizationUpdateForm
from accounts.models import User
from .models import Organization, OrganizationMembers
class OrganizationUpdateView(LoginRequiredMixin, UpdateView):
model = Organization
form_class = OrganizationUpdateForm
template_name = 'organizations/organization_update.html'
success_url = reverse_lazy('organizations')
# Save data and set current user to last updated by fields
def form_valid(self, form):
object = form.save(commit=False)
object.last_updated_by = self.request.user.get_full_name()
object.last_updated_by_id = self.request.user
return super(OrganizationUpdateView, self).form_valid(form)
def get_queryset(self):
criteria1 = Q(owner=self.request.user)
criteria2 = Q(organizationmembers__member=self.request.user)
criteria3 = Q(organizationmembers__organization_admin=1)
org_list = Organization.objects.\
filter(criteria1 | (criteria2 & criteria3)).distinct()
if org_list.count() != 0:
return org_list
else:
raise Http404('You don\'t have permissions!')
In Mikes case Chiheb has commented that "With UpdateView it's a little bit tricky. So, in order to initialize your form's data, you need to do it in the view itself not in the form."
What is the reason that cannot add filter to UpdateView?
Please can someone help me to solve my problem. Thanks.
UPDATE
Not filtered. Value from database is visible
Not filtered. Dropdown list show all users in the system
Filter enabled. Value is not visible
Filter enabled. Dropdown list show correct valeus
The problem is that owner in your models is a FK to User model, but you are filtering queryset in form by OrganizationMembers. Make it the same and the problem should be gone.
I have a linked model:
class Children(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
child_name = models.CharField(max_length=150, null=True, blank=True)
slug = AutoSlugField(populate_from='child_name')
blood_group = models.CharField(max_length=5, blank=True)
class Meta:
unique_together = ('slug', 'person')
def get_absolute_url(self):
return self.person.get_absolute_url()
def get_delete_url(self):
return reverse(
'member:children-delete',
kwargs={
'person_slug': self.person.slug,
'children_slug': self.slug})
def get_update_url(self):
return reverse(
'member:children-update',
kwargs={
'person_slug': self.person.slug,
'children_slug': self.slug})
my forms.py:
class ChildrenForm( SlugCleanMixin, forms.ModelForm):
class Meta:
model = Children
exclude = ('person',)
def clean(self):
cleaned_data = super().clean()
slug = cleaned_data.get('slug')
person_obj = self.data.get('person')
exists = (
Children.objects.filter(
slug__iexact=slug,
person=person_obj,
).exists())
if exists:
raise ValidationError(
"Children with this Slug "
"and Person already exists.")
else:
return cleaned_data
def save(self, **kwargs):
instance = super().save(commit=False)
instance.person = (
self.data.get('person'))
instance.save()
self.save_m2m()
return instance
views.py:
class ChildrenCreate( ChildrenFormMixin, ChildrenGetObjectMixin,
PersonContextMixin,CreateView):
template_name = 'member/children_form.html'
model = Children
form_class = ChildrenForm
class ChildrenUpdate(ChildrenFormMixin, ChildrenGetObjectMixin,
PersonContextMixin,UpdateView):
template_name = 'member/children_form.html'
model = Children
form_class = ChildrenForm
slug_url_kwarg = 'children_slug'
class ChildrenDelete(ChildrenFormMixin,ChildrenGetObjectMixin,
PersonContextMixin,DeleteView):
model = Children
slug_url_kwarg = 'children_slug'
def get_success_url(self):
return (self.object.person
.get_absolute_url())
my utils.py:
class ChildrenFormMixin():
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
if self.request.method in ('POST', 'PUT'):
self.person = get_object_or_404(
Person,
slug__iexact=self.kwargs.get(
self.person_slug_url_kwarg))
data = kwargs['data'].copy()
data.update({'person': self.person})
kwargs['data'] = data
return kwargs
class ChildrenGetObjectMixin():
def get_object(self, queryset=None):
person_slug = self.kwargs.get(
self.person_slug_url_kwarg)
children_slug = self.kwargs.get(
self.slug_url_kwarg)
return get_object_or_404(
Children,
slug__iexact=children_slug,
person__slug__iexact=person_slug)
class PersonContextMixin():
person_slug_url_kwarg = 'person_slug'
person_context_object_name = 'person'
def get_context_data(self, **kwargs):
person_slug = self.kwargs.get(
self.person_slug_url_kwarg)
person = get_object_or_404(
Person, slug__iexact=person_slug)
context = {
self.person_context_object_name:
person,
}
context.update(kwargs)
return super().get_context_data(**context)
The children created more than one for same name of same parents. When I tried to edit children it gives "get() returned more than one Children -- it returned 2!" error. In traceback, it said, 'person__slug__iexact=person_slug' is the direct causes of this traceback.
In the form, I added clean method to catch the error and maintain uniqueness of children name of same parents but it not worked. Could I get suggestions where I do wrong?
Edit:
my Person model:
class Person(models.Model):
name = models.CharField(max_length=250)
slug = AutoSlugField(populate_from='name')
birth_date = models.DateField(null=True, blank=True)
blood_group = models.CharField(max_length=5)
present_address = models.CharField(max_length=250, blank=True)
permanent_address = models.CharField(max_length=250, blank=True)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
related_name='member_persons')
class Meta:
ordering = ['name']
unique_together = ['name', 'birth_date']
I believe you are using AutoSlugField from django-autoslug, and you trying to get by non-unique field. AutoSlugField won't make your field unique by default, from docs:
AutoSlugField can also perform the following tasks on save:
populate itself from another field (using populate_from),
use custom slugify function (using slugify or Settings), and
preserve uniqueness of the value (using unique or unique_with).
None of the tasks is mandatory, i.e. you can have auto-populated non-unique fields, manually entered unique ones (absolutely unique or within a given date) or both.
So quick fix would be slug = AutoSlugField(populate_from='child_name', unique=True)
UPDATE(Since you posted your Person model)
The problem is the same and solution is the same.
Explanation:
For example you have two Person objects:
id name slug birth_date
1 alex alex 10.10.2016
2 alex alex 10.10.2015
This won't violate unique_together = ['name', 'birth_date']
And you got two Children objects:
id name slug person_id
1 john john 1
2 john john 2
And that won't violate unique_together = ('slug', 'person') neither
Then you are making query
get_object_or_404(
Children,
slug__iexact='john',
person__slug__iexact='alex')
Which would match two objects. So you got problem. Quick fix would be to make slug unique=True.
I am writing code in Django for Engineering College:
1) College has Engineering Branches like Computer Engg, Mech Engg, Chemical Engg.
2) Now each Branch will have different classes like for Frst year enginnering in computer has to classes say, FYCO1 and FYCO2
3) I have created different users for each head of the department(HOD) and following models:
class M_Branch(models.Model):
Branch_ID = models.CharField(max_length=20)
Branch_Name= models.CharField(max_length=50)
def __str__(self):
return self.Branch_Name
class M_Academic_year(models.Model):
Academic_year = models.CharField(max_length=20)
def __str__(self):
return self.Academic_year
class M_Class(models.Model):
Branch_ID = models.ForeignKey(M_Branch)
Academic_Year = models.ForeignKey(M_Academic_year)
Class_ID = models.CharField(max_length=20)
Class_Name = models.CharField(max_length=20)
def __str__(self):
return self.Class_Name
4) Now each HOD (user) must be able to add a class for only his own department(branch),HOW TO ACHIEVE THIS FUNCTIONALITY???
Note: I have not written any views,(and don't want to do so). I am using Django's default admin
view
To read only branch of HOD in M_ClassAdmin first make a relation between HOD and Branch For this, make changes In Model.py as
from django.contrib.auth.models import User
Add Hod Field as
HOD = models.ForeignKey(User)
to store HOD and Branch relation
Now Model.py willbe...
class M_Branch(models.Model):
HOD = models.ForeignKey(User)
Branch_ID = models.CharField(max_length=20)
Branch_Name= models.CharField(max_length=50)
def __str__(self):
return self.Branch_Name
class M_Academic_year(models.Model):
Academic_year = models.CharField(max_length=20)
def __str__(self):
return self.Academic_year
class M_Class(models.Model):
Branch_ID = models.ForeignKey(M_Branch)
Academic_Year = models.ForeignKey(M_Academic_year)
Class_ID = models.CharField(max_length=20)
Class_Name = models.CharField(max_length=20)
def __str__(self):
return self.Class_Name
Then in admin.py Override get_queryset and formfield_for_foreignkey
class M_ClassAdmin(admin.ModelAdmin):
def get_queryset(self, request):
print("Query SET")
qs = super(M_ClassAdmin, self).get_queryset(request)
if request.user.is_superuser:
return qs
user = User.objects.get(username=request.user.username)
branch = M_Branch.objects.get(HOD = user)
print("Branch_ID_id",branch)
return qs.filter(Branch_ID_id=branch)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
print("I am in func::")
if db_field.name == "Branch_ID":
print("db_field.name",db_field.name)
user = User.objects.get(username=request.user.username)
if not user.is_superuser:
print('user=',user)
branch = M_Branch.objects.get(HOD = user)
print('branch = ',branch)
'''if user=='E0711001':
kwargs["queryset"] = M_Branch.objects.filter(Branch_ID='B101')
#elif user=='E0711002':
else:
kwargs["queryset"] = M_Branch.objects.filter(Branch_ID='B102')'''
#kwargs["queryset"] = M_Branch.objects.filter(Branch_ID=user.branch.id)
kwargs["queryset"] = M_Branch.objects.filter(Branch_Name=branch)
return super(M_ClassAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
fields = ['Branch_ID','Academic_Year','Class_Name']
list_filter = ['Academic_Year','Class_Name']
search_fields = ['Branch_ID','Academic_Year','Class_Name']
list_display = ('Class_Name','Branch_ID','Academic_Year')
admin.site.register(M_Class,M_ClassAdmin)