Using inline formsets with manytomany relationship - django

I have AbstractUser and Relationship models. The user model has a manytomany field through relationship model
class User(AbstractUser):
username = models.CharField(
verbose_name="username", max_length=256, unique=True)
first_name = models.CharField(verbose_name="first name", max_length=30)
last_name = models.CharField(verbose_name="last name", max_length=30)
slug = models.SlugField(max_length=255, unique=True, blank=True)
date_joined = models.DateTimeField(
verbose_name="joined date", auto_now_add=True)
friends = models.ManyToManyField('self', through='Relationship', symmetrical=False,
related_name='following')
is_active = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
def __str__(self):
return str(self.username)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.username)
super().save(*args, **kwargs)
class Relationship(models.Model):
from_person = models.ForeignKey(
User, related_name='from_people', on_delete=models.CASCADE)
to_person = models.ForeignKey(
User, related_name='to_people', on_delete=models.CASCADE)
def __str__(self):
return f"from {self.from_person} to {self.to_person}"
How to create an inline formset with fields=['from_person' and 'to_person'] to assign users to each others
That is what I tried to do but I couldn't have both fields because of fk_name
Any help please!
def staff_profile_view(request):
user = User.objects.get_by_natural_key(request.user)
AssignFriendsFormSet = inlineformset_factory(
User, Relationship, fk_name='from_person', fields=('to_person', 'from_person',))
formset = AssignFriendsFormSet(
queryset=Relationship.objects.none(), instance=user)
if request.method == "POST":
formset = AssignFriendsFormSet(request.POST, instance=user)
if formset.is_valid():
formset.save()
return render(request, 'staff_profile.html',{"formset": formset})

An inline formset won't let you change the 'line' between models, so you can't include 'from_person' as a changeable field. In this case it looks like you're trying to get a list of people following the user/requester (the 'from_person') with the possibility of changing them so they don't follow the user anymore.
Inline formsets are just an abstraction, though - a shorthand for a particular type of queryset. You can achieve exactly the same effect through a normal formset, something like
AssignFriendsFormSet = modelformset_factory(Relationship, fields=('from_person', 'to_person'))
queryset = Relationship.objects.filter(from_person=user)
formset = AssignFriendsFormSet (
queryset=queryset,
)
The many-to-many field is really just a record in the through table, so you can update it there.

Related

Djnago Form getting Error while edit record

I am getting Issue while edit a record based on CHatquestion ID, if option is null then i need to add a record based on same chatquestion id, if chatqustion id exist in option it will work,
i am trying to multiple way to solve this issue but still can't find solution.
Models.py # thease are all 3 models
class Problem(models.Model):
Language = models.IntegerField(choices=Language_CHOICE, default=1)
type = models.CharField(max_length=500, null=True, blank=True)
def __str__(self):
return self.type
class ChatQuestion(models.Model): # Eding record based on chatquestion id
question = RichTextField(null=True, blank=True)
problem_id = models.ForeignKey(
Problem,
models.CASCADE,
verbose_name='Problem',
)
def __str__(self):
return self.question
is_first_question = models.BooleanField(default=False)
class Option(models.Model):
option_type = models.CharField(max_length=250, null=True, blank=True)
question_id = models.ForeignKey(
ChatQuestion,
models.CASCADE,
verbose_name='Question',
null=True,
blank=True
)
problem=models.ForeignKey(
Problem,
models.CASCADE,
verbose_name='Problem',
null=True,
blank=True
)
next_question_id = models.ForeignKey(ChatQuestion, on_delete=models.CASCADE, null=True, blank=True,
related_name='next_question')
def __str__(self):
return self.option_type
forms.py
class EditQuestionForm(forms.ModelForm):
class Meta:
model = ChatQuestion
fields =('question','problem_id')
class EditOptionForm(forms.ModelForm):
class Meta:
model = Option
fields =('option_type',)
views.py
def question_edit(request,id=None):
if id is not None:
queryset = get_object_or_404(ChatQuestion,pk=id)
queryset1=get_object_or_404(Option,question_id=queryset )
else:
queryset = None
queryset1 = None
if request.method=="POST":
form = EditQuestionForm(request.POST ,instance=queryset)
form1=EditOptionForm(request.POST, instance=queryset1)
if form.is_valid() and form1.is_valid():
question=form.cleaned_data['question']
option_type=form1.cleaned_data['option_type']
if id:
queryset.question=question
queryset.save()
queryset1.option_type=option_type
queryset1.save()
messages.success(request,'Sucessful')
return redirect('/fleet/list_chatbot')
else:
print(form.errors)
messages.error(request,'Please correct following',form.errors)
elif id:
form = EditQuestionForm(instance=queryset)
form1=EditOptionForm(instance=queryset1)
if not queryset1:
form1=EditOptionForm()
else:
form = EditQuestionForm()
form1=EditOptionForm()
context={
'form':form,
'form1':form1
}
return render(request,'chatbot/question_edit.html',context=context)

Custom "business" logic using pure Django

I am set on building a small website using django. What i am trying to do right now is using a CreateView based on a Model "Order", which one of its fields is another model "Customer".
The form itself works to create Orders, but im trying to find out how i can validate that the Customer that was selected is "enabled" (there is a status in the Customer model).
I was trying using the clean method but it doesnt even seem to be executing. I tried just raising the error on the clean, without validating anything, and still doesnt work. Any clue what might be wrong?
My Form:
class OrderForm(ModelForm):
def clean_customer(self, *args, **kwargs):
raise forms.ValidationError("This customer is banned.")
class Meta:
model = Order
fields = '__all__'
Relevant Models:
class Order(models.Model):
ORDER_STATUS = (('Pending Delivery', 'Pending Delivery'),
('Book on Customer', 'Book on Customer'),
('Overdue', 'Overdue'),
('Completed','Completed'))
customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL)
book = models.ForeignKey(Book, null=True, on_delete=models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True)
date_due = models.DateTimeField(null=True)
date_completed = models.DateTimeField(null=True, blank=True)
status = models.CharField(max_length=100, choices=ORDER_STATUS, null=True)
def get_absolute_url(self):
return reverse('orders')
class Customer(models.Model):
status = models.CharField(max_length=10, null = True, choices=STATUS_CHOICES)
name = models.CharField(max_length=200, null=True)
username = models.CharField(max_length=25, null = True)
email = models.EmailField(null=True)
def __str__(self):
return str(self.name)+" - " +str(self.username)
def get_absolute_url(self):
return reverse('customers')
The View:
class OrderCreateView(CreateView):
model = Order
fields = '__all__'
def form_valid(self, form):
return super().form_valid(form)

Display misconception in django-tables2

After creating a custom user model in my app, I have a studentProfile that inherits from the user model, which also contains avatar, semester, and dept_name. which works fine. However, when I was trying to display this studentProfile data using django-tables2, all rows keeps showing "-" and the ID been captured is from user model instead of studentProfile.
The weirdiest thing is i can get all the values from user model
correctly even when studentProfile is my table model for
django-tables2
I don't know what I am doing wrongly. Any help is really appreciated
my model definitions are as follow
class DepartmentData(models.Model):
fid = models.ForeignKey(FacultyData, on_delete=models.CASCADE)
dept_name = models.CharField(max_length=50)
created_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.dept_name
class User(AbstractBaseUser):
# add additional fields here
user_id = models.CharField(max_length=15, unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
active = models.BooleanField(default=True)# can login
staff = models.BooleanField(default=False) # staff user non superuser
admin = models.BooleanField(default=False) # superuser
USER_TYPE_CHOICES = (
(1, 'student'),
(2, 'lecturer'),
(3, 'bursary'),
(4, 'system'),
(5, 'admin'),
)
user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES)
USERNAME_FIELD = 'user_id'
REQUIRED_FIELDS = ['first_name', 'last_name', 'user_type']
objects = UserManager()
def __str__(self):
return self.user_id
def get_full_name(self):
return self.first_name + " " + self.last_name
def get_user_type(self):
return self.user_type
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
class StudentProfile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
semester = models.ForeignKey(SemesterData, on_delete=models.SET_NULL, null=True)
dept_name = models.ForeignKey(DepartmentData, on_delete=models.SET_NULL, null=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
def __str__(self):
return self.user.first_name
class SemesterData(models.Model):
sid = models.ForeignKey(SessionData, on_delete=models.CASCADE)
semester_name = models.CharField(max_length=50)
def __str__(self):
return self.semester_name
def current(self):
if SettingsData.objects.all().count():
st = SettingsData.objects.get(id=1)
if self.id == st.current_id:
return "Current Session-Semester"
else:
return format_html('{}', reverse('system:current_session_semester', args=[self.id]),
'Set Current')
else:
return format_html('{}', reverse('system:current_session_semester', args=[self.id]),
'Set Current')
here is my table.py
class StudentTable(tables.Table):
user_id = tables.Column(attrs = {'th': {'class': 'danger'}})
first_name = tables.Column(attrs = {'th': {'class': 'danger'}})
last_name = tables.Column(attrs = {'th': {'class': 'danger'}})
avatar = tables.Column(accessor ="user", verbose_name = "ass" )
active = tables.Column(attrs = {'th': {'class': 'danger'}})
last_login = tables.Column(attrs = {'th': {'class': 'danger'}})
edit_Action = tables.LinkColumn('system:semester_edit', text='Edit', args=[A('pk')],attrs={'a':{'class':'btn btn-info btn-sm'}, 'td':{'align': 'center'}, 'th': {'class': 'danger'}}, orderable=False)
class Meta:
model = StudentProfile
attrs = {'class':'table table-hover table-bordered table-responsive'}
sequence = ('user_id', 'first_name', 'last_name', 'avatar')
exclude = {'id', 'user', 'password', 'staff', 'admin'}
empty_text = _("There are no students yet")
template_name = 'django_tables2/bootstrap4.html'
I would love to get the department_name, semester_name as well as fields in the studentProfile which is serving as my table model
You are seeing empty values for all fields with your current configuration because you're trying to access fields user_id, first_name and last_name which are not fields of the StudentProfile model, but rather fields of the User model (to which StudentProfile is related by user field).
That being said, you should access those fields via the user relation, something like this:
class StudentTable(tables.Table):
user_id = tables.Column(accessor='user.user_id', ...)
first_name = tables.Column(accessor='user.first_name', ...)
last_name = tables.Column(accessor='user.last_name', ...)
...
As far as the DepartmentData and SemesterData relations go, I'm not sure why aren't they displayed by default, since they are fields of the StudentProfile model, and they aren't excluded via the exclude property on the Meta. You can maybe try to explicitly list them in the fields property and see if that helps.

how to pass the an authenticated user to forms.py in django

I have a django app with which every registered user can create categories. For the authentication I am using django-all-auth. My models.py looks like this:
class Profile(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
create_date = models.DateTimeField('date added', auto_now_add=True)
modify_date = models.DateTimeField('date modified', default=timezone.now)
class Category(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
name = models.CharField(max_length=200, unique=True)
create_date = models.DateTimeField('date added', auto_now_add=True)
modify_date = models.DateTimeField('date modified', default=timezone.now)
On the index page the user can see the created categories and create new ones.
The views.py:
def CategoryView(request):
user = 0
if request.user.is_authenticated():
user = request.user
form = CategoryNameForm()
form.user = user
context = {
'categories': Category.objects.all(),
'form': form,
'user':user,
}
if request.method == 'POST':
form = CategoryNameForm(request.POST)
form.user = user
if form.is_valid():
form.save()
return render(request, 'myapp/index.html',context)
forms.py:
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name',)
The authentication works. So I was thinking to just put pass the user field into the form :
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name','user',)
hide it and then, just select it via JS since the user is in the context. I was just wondering if there is an easier way. This form.user = user for some reason didn't work, I get a NOT NULL constraint failure
There are couple of ways but here is one:
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name',) # take out user you don't need it here
def save(self, **kwargs):
user = kwargs.pop('user')
instance = super(CategoryNameForm, self).save(**kwargs)
instance.user = user
instance.save()
return instance
Then in view:
if form.is_valid():
form.save(user=request.user, commit=False)
Make sure your CategoryView is only accessible by authenticated user. Otherwise you will still get NOT NULL constraint failure for user.

django : How to declare a foreign key of another foreignkey

I have a model with:
class Material(models.Model):
name = models.CharField(_('name'), max_length=50)
description = models.TextField(_('description'), blank=True)
user = models.ForeignKey(User, default=None, blank= True, null = True)
class Essai_Temperature(models.Model):
name = models.ForeignKey(Material, verbose_name=_('name'))
nature_unit = models.ForeignKey(Property, verbose_name=_('category'))
user= models.ForeignKey(Material, related_name="user_set", default='0')
admin:
class Essai_TemperatureAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(Essai_TemperatureAdmin, self).queryset(request)
current_user = request.user
if current_user.is_superuser:
return qs
else:
return qs.filter(user=current_user)
How to return qs.filter(user=current_user)?
in Essai_Temperature the field user don't work
How can I have access to the field user in Material?
You're thinking about this in completely the wrong way. The foreign key from Essai is to Material, not to User, so you should call it material (and drop the related_name, which is wrong and confusing).
Now you can follow the relationship:
qs.filter(material__user=current_user)