Restrict django form ForeignKey dropdown by user - django

I have two models, Group, and List Item. List Items belong inside Groups:
class List_Item(models.Model):
name = models.CharField("List Item Name", max_length=200, unique = True)
group = models.ForeignKey(Group, verbose_name="Group")
creation_date = models.DateTimeField("Creation Date", default=datetime.now)
notes = models.TextField("Notes", blank=True)
user = models.ForeignKey(User, editable=False)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField("Group Name", max_length=200, unique = True)
notes = models.TextField("Notes", blank=True)
user = models.ForeignKey(User, editable=False)
def __unicode__(self):
return self.name
In my forms for List Items, a ModelForm has a dropdown for Groups. Currently, it lists all Groups, regardless of which user a Group belongs to. But I want to only display Groups that belong to the user logged in. How might I do this?

You would have to override the form field inside the init method. You could pass the logged in user to the form from the view and filter based on it
#form
class ListItemform(forms.ModelForm):
def __init__(self, *args, ** kwargs):
self.user = kwargs.pop('user', None)
super(ListItemform, self).__init__(*args, **kwargs)
self.fields['group'].queryset = Group.objects.filter(user = self.user)
#view
def displayform(request):
user = request.user
form = ListItemForm(user = user)
return ...

Related

Django: how to create groups?

EXAMPLE to elaborate my problem -> I am the user of the website and i want to create a group. While creating group the website asked me the group_name,group_description ,group_password (as i don't want the group to be public and a person if want to join the group should know the password). now i have given the name and the password to my friends and they can join the group by authenticating with the password of group to successfully join.
ISSUE i am facing -> i have created the password field in models.py. But the password is saved in the database as plane text but not something liked hashed django passwords. secondly, i want in the joining user to authenticate with the password in order to join the group.
models.py
class Group(models.Model):
admin = models.ForeignKey(to=Profile, related_name="admin", on_delete=models.CASCADE)
name = models.CharField(max_length=200, unique=True)
password = models.CharField(max_length=200, default='thinkgroupy')
slug = models.SlugField(allow_unicode=True, unique=True)
group_pic = models.ImageField(upload_to="users/group_images/%y/%m/%d",null=True)
about = models.CharField(max_length=255, null=True, blank=True)
about_html = models.TextField(editable=False, default='', blank=True)
created_at = models.DateTimeField(auto_now=True)
members = models.ManyToManyField(User, through="GroupMember")
def __str__(self):
return "%s" % self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
self.about_html = misaka.html(self.about)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("groups:single", kwargs={"slug": self.slug})
class Meta:
ordering = ["name"]
class GroupMember(models.Model):
group = models.ForeignKey(Group, related_name="memberships")
user = models.ForeignKey(User,related_name='user_groups')
def __str__(self):
return self.user.username
class Meta:
unique_together = ("group", "user")
views.py
class CreateGroup(LoginRequiredMixin, generic.CreateView):
fields = ("name", "description","password")
model = Group
class JoinGroup(LoginRequiredMixin, generic.RedirectView):
def get_redirect_url(self, *args, **kwargs):
return reverse("groups:single",kwargs={"slug": self.kwargs.get("slug")})
def get(self, request, *args, **kwargs):
group = get_object_or_404(Group,slug=self.kwargs.get("slug"))
try:
GroupMember.objects.create(user=self.request.user,group=group)
except IntegrityError:
messages.warning(self.request,("Warning, already a member of {}".format(group.name)))
else:
messages.success(self.request,"You are now a member of the {} group.".format(group.name))
return super().get(request, *args, **kwargs)

Django: Delete or empty content of a row in UpdateView

I'm looking to delete or empty a specific row in my table/model in my UpdateView. I have a team and employees in the team. I have made an update view that when "yes" is pressed, the team becomes archived. I want to additionally delete or empty the employee's numbers when doing so. How would I approach that?
I know it might be weird, but the idea is that the employee's numbers should be destroyed once the team is archived, while the rest of the data still stands.
Team Model
class Team(models.Model):
slug = models.SlugField(max_length=200)
teamname = models.CharField(max_length=50, help_text="Indtast holdnavn.", null=False, primary_key=True)
is_active = models.BooleanField(default=True)
Employee Model
class Employee(models.Model):
id = models.AutoField(primary_key=True)
slug = models.SlugField(max_length=200)
emp_num = models.IntegerField(help_text="Indtast medarbejderens MA-nummer. (F.eks 123456)")
firstname = models.CharField(max_length=30, help_text="Indtast medarbejderens fornavn.")
lastname = models.CharField(max_length=30, help_text="Indtast medarbejderens efternavn.")
teamname = models.ForeignKey('Hold', on_delete=models.CASCADE, null=True)
UpdateView
My updateView is using team, as its that model I'm updating.
class ArchiveHoldView(UpdateView):
template_name = 'evalsys/medarbejder/archive_hold.html'
model = Team
form_class = ArchiveForm
def archive_view_team_with_pk(self, slug=None):
if slug:
team = Team.objects.get(slug=slug)
else:
team = self.team
args = {'team': team}
return render(self, 'evalsys/medarbejder/archive_hold.html', args)
def get_context_data(self, **kwargs):
context = super(ArchiveHoldView, self).get_context_data(**kwargs)
context['is_active'] = Team.objects.get(slug=self.kwargs.get('slug'))
return context
def get_success_url(self):
return reverse_lazy("evalsys:home")
Update View form
class ArchiveForm(forms.ModelForm):
def save(self, *args, **kwargs):
self.instance.is_active = False
return super(ArchiveForm, self).save(*args, **kwargs)
is_active = BooleanField(required=False, widget=forms.HiddenInput())
class Meta:
model = Team
fields = ['is_active', ]
labels = {'is_active': 'Is Active'}

Set ManyToMany field in model save method

I have a problem, I try to save the model and only adds to 'members' the users that belong to the company set in the field 'company'.
This is my code:
class GroupFolderAccess(BaseModel):
name = models.CharField(max_length=128)
members = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='belongs')
company = models.ForeignKey('Company', on_delete=models.CASCADE, related_name='folders')
folder = models.ForeignKey('recourse.Folder', null=True, blank=True, on_delete=models.CASCADE, related_name='get_group')
def save(self, *args, **kwargs):
for member in self.members.all():
if self.company != member.company:
print(member)
self.members.remove(member)
return super(GroupFolderAccess, self).save(*args, **kwargs)
When I save, it displays users correctly, but does not remove them from the relationship.

Django ModelForm Validation using non form data

I'm new to Django (1.9.6) and I'm trying to understand if it is possible to validate a field on a ModelForm that needs to reference information that is contained in a Foreign Key from the referenced model.
How can I validate that the value a user inputs for "num_tickets" on the OrderForm is less than or equal to the "tickets_remaining" field on the Event class which is connected through a foreign key relationship?
I don't want to expose the Event field from the Order class on the OrderForm as the user has already accessed the specific event page, and has already selected to purchase tickets.
Models.py
class Order(models.Model):
first_name = models.CharField('First Name', max_length=120,null=False, blank=False)
last_name = models.CharField('Last Name', max_length=120, null=False, blank=False)
email = models.EmailField('Email', null=False, blank=False)
event = models.ForeignKey(Event)
num_tickets = models.PositiveIntegerField('Tickets', null=False, blank=False, validators=[MinValueValidator(0)])
total_price = models.DecimalField('Total', max_digits=8, decimal_places=2, default=0.0)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
class Event(models.Model):
event_name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=8, decimal_places=2, default=00.00, validators=[MinValueValidator(0)])
tickets_remaining = models.PositiveIntegerField(default=300)
Forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['first_name', 'last_name', 'email', 'num_tickets']
def clean_num_tickets(self):
tickets = self.cleaned_data["num_tickets"]
# validation Logic. Want to ensure a user cannot purchase more
# tickets than what an event has for "tickets_remaining"
return tickets
You don't show how you're associating the order with the event in the first place. If you haven't done that, then your problem is wider than just validating the tickets available.
I would recommend passing that Event from the view into the form instantiation. You can then use it both to associate the order with that event, and to validate the tickets.
class OrderForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event', None)
super(OrderForm, self).__init__(*args, **kwargs)
def clean_num_tickets(self):
tickets = self.cleaned_data["num_tickets"]
if tickets > self.event.tickets_remaining:
raise ValidationError('Too many tickets')
return tickets
def save(self, commit=False):
order = super(OrderForm, self).save(commit=False)
order.event = self.event
if commit:
order.save()
return commit
Now pass the event into the form when instantiating it:
form = OrderForm(request.POST, event=event)

Django form objects filter

I want to associate the drop-down lists material and category
models
class Demande_Expertise(models.Model):
user = models.ForeignKey(User)
material = models.ForeignKey("Material")
categorie = models.ForeignKey("Category")
class Category(models.Model):
name = models.CharField(_('name'), max_length=50)
slug = models.SlugField()
expert = models.ForeignKey(Expert, null=True, blank=True, default = None)
class Material(models.Model):
name = models.CharField(_('name'), max_length=50)
description = models.TextField(_('description'), blank=True)
slug = models.SlugField()
category = models.ForeignKey(Category, verbose_name=_('category'))
forms
class Demande_ExpertiseForm(forms.ModelForm):
class Meta:
model = Demande_Expertise
def __init__(self, *args, **kwargs):
super(Demande_ExpertiseForm, self).__init__(*args, **kwargs)
self.fields['material'].queryset = Material.objects.filter(category=Category)
no error but filtering don't work.
how to filter name of the model Category?
You can filter a relation in a queryset by a field by using double underscores (so category__name in this case) and passing in whatever you want to filter it by.
class Demande_ExpertiseForm(forms.ModelForm):
class Meta:
model = Demande_Expertise
def __init__(self, *args, **kwargs):
super(Demande_ExpertiseForm, self).__init__(*args, **kwargs)
self.fields['material'].queryset = Material.objects.filter(category__name="name to filter")
In this case it will filter all of the Material objects to those which have a Category set to exactly name to filter. You can learn more by reading the Django documentation on retrieving objects.