Save another model's object in CreateView - django

I have 3 model:
class City(models.Model):
name = models.CharField()
class State(models.Model):
name = models.CharField()
class Role(models.Model):
CITY = 1
State = 2
NOACCESS = 0
VIEW = 1
UPDATE = 2
DELETE = 3
TYPE_CHOICES = (
(CITY, 'City'),
(STATE, 'State'),
)
ROLE_CHOICES = (
(NOACCESS, 'No access'),
(VIEW, 'View'),
(UPDATE, 'Update'),
(DELETE, 'Delete'),
)
obj_type = models.IntegerField(choices=TYPE_CHOICES)
obj_id = models.IntegerField(verbose_name="Object ID")
obj_role = models.IntegerField(choices=ROLE_CHOICES, default=NOACCESS)
obj_user = models.IntegerField()
I would like to save a role for each user in views.py:
class FormCreateView(CreateView):
form_class = City
def form_valid(self, form):
users = self.request.POST.getlist('access-users')
f.save()
for i in users:
role = RoleCreateView() # save a role for each user
role.type = 'city'
role.user = i
role.city = f.id
role.save()
return super(FormCreateView, self).form_valid(form)
How I can do this?

Related

apply a filter to the choices field of my model

Hi I have problems with some filters in django.
I have my own view where I can choose the day of the week which is a select choice field
once chosen it is saved in the db.
I would like to filter those already present so as not to repeat them if I had to choose another day.
Can anyone help me out please?
models.py
class Piano(models.Model):
nome_piano = models.CharField(max_length=100)
data_inizio = models.DateField()
data_fine = models.DateField()
utente_piano = models.ForeignKey(
User,
on_delete = models.CASCADE,
related_name = 'utente_piano'
)
def __str__(self):
return self.nome_piano
class Meta:
verbose_name = "Piano alimentare"
verbose_name_plural = "Piani alimentari"
class PianoSingleDay(models.Model):
giorni_settimana_scelta = [
("1","Lunedì"),
("2","Martedì"),
("3","Mercoledì"),
("4","Giovedì"),
("5","Venerdì"),
("6","Sabato"),
("7","Domenica")
]
giorni_settimana = models.CharField(
choices = giorni_settimana_scelta,
max_length = 300
)
single_piano = models.ForeignKey(
Piano,
on_delete = models.CASCADE,
related_name = 'single_piano'
)
def __str__(self):
return self.giorni_settimana
class Meta:
verbose_name = "Piano singolo"
verbose_name_plural = "Piani singoli"
views.py
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id = id, utente_piano = request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, prefix = 'giorno')
if giorno_form.is_valid():
day_piano = giorno_form.save(commit = False)
day_piano.single_piano = piano
day_piano.save()
return redirect('gestione-piano', id = piano.id)
else:
giorno_form = PianoSingleDayForm(prefix = 'giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)
forms.py
class PianoSingleDayForm(forms.ModelForm):
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
1
2
You can let the PianoSingleDayForm exclude the days that have already been selected for that Piano with:
class PianoSingleDayForm(forms.ModelForm):
def __init__(self, *args, piano=None, **kwargs):
super().__init__(*args, **kwargs)
if piano is not None:
days = set(PianoDaySingle.objects.filter(
single_piano=piano
).values_list('giorni_settimana', flat=True))
self.fields['giorni_settimana'].choices = [
(k, v)
for k, v in self.fields['giorni_settimana'].choices
if k not in days
]
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
We can then use this in the view by passing the Piano object to the form both in the GET and POST codepath:
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id=id, utente_piano=request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, piano=piano, prefix='giorno')
if giorno_form.is_valid():
giorno_form.instance.single_piano = piano
giorno_form.save()
return redirect('gestione-piano', id=piano.id)
else:
giorno_form = PianoSingleDayForm(piano=piano, prefix='giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)

Django rest framework test does not create instances in test database

I'm having an issue in DRF tests when creating instance of a model, the status code in response is 'HTTP_201_CREATED' but the instance it self does not exist in the testing db.
here is my model :
class Item(SafeDeleteModel):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_("Owner"))
name = models.CharField(_("Name"), max_length=150)
category = TreeForeignKey('merssis.ItemCategory', on_delete=models.SET_NULL, null=True, verbose_name=_("Category"))
fixed_price = models.FloatField(_("Fixed price"), default=0)
main_pic = ProcessedImageField(verbose_name=_("Main picture"), upload_to='item_pics', processors=[ItemWatermarker()],format='JPEG')
main_pic_thumbnail = ImageSpecField(source='main_pic',
processors=[ResizeToFill(384, 256)],
format='JPEG',
options={'quality': 100})
geo_location = models.PointField(srid=4326, null=True, blank=True, verbose_name=_("Geolocation"))
_safedelete_policy = SOFT_DELETE_CASCADE
def __str__(self):
return self.name
Serializer :
class ItemCreateSerializer(GeoFeatureModelSerializer):
PRICE_TYPE_CHOICES = (
('fixed', _('Fixed') ),
('open', _('Open') ),
)
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
price_type = serializers.ChoiceField(choices=PRICE_TYPE_CHOICES)
category = serializers.PrimaryKeyRelatedField(queryset=ItemCategory.objects.all(), many=False)#ItemCategorySerializer(many=False)
main_pic = serializers.ImageField(use_url='item_pics')
def validate(self, data):
user = self.context['request'].user
geo_data = data.get('geo_location')
#Validate fixed price value
if data['price_type'] == 'fixed':
if data.get('fixed_price') == None or int(data.get('fixed_price')) <= 0:
raise serializers.ValidationError({"fixed_price" :INVALIDE_PRICE_ERROR})
#Price type is open should explicitly set fixed price to 0
if data['price_type'] == 'open':
data['fixed_price'] = 0
#Validate geo_location
#geo_location post data form ====> {"type":"Point", "coordinates":[37.0625,-95.677068]}
if geo_data:
if not validate_in_country_location(user, geo_data):
raise serializers.ValidationError({"geo_location":OUTSIDE_COUNTRY_MSG})
return data
def create(self, validated_data):
#Remove price_type value since it is not a field in the model
#We used to determine th price type on the serializer only
validated_data.pop('price_type')
return Item(**validated_data)
class Meta:
model = Item
geo_field = 'geo_location'
fields = ( 'owner',
'name',
'price_type',
'category',
'fixed_price',
'main_pic',
'geo_location',
)
The view :
class ItemCreateAPIView(CreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemCreateSerializer
permission_classes = [permissions.IsAuthenticated]
def perform_create(self, serializer, *args, **kwargs):
self.check_object_permissions(self.request, self.request.user)
serializer.save()
The test case :
class ItemTestCase(APITestCase):
def test_create_new_item(self):
"""
Testing Add new item functionality
"""
self.client_1 = APIClient()
self.user_1 = create_new_user(email='tester1#gmail.com', username='tester_1', password='qsdf654654', gender='male')
self.client_1.login(username='tester_1',password='qsdf654654')
image_file = create_test_image()
category = ItemCategory.objects.create(name='SomeCat')
new_item_data = {
'name': 'New Item',
'price_type' : 'open',
'category': str(category.pk),
'main_pic': image_file,
}
response = self.client_1.post(url, new_item_data, format='multipart')
items = Item.objects.filter(name='New Item')
print(response.status_code)
self.assertEqual( response.status_code, status.HTTP_201_CREATED)
self.assertEqual( items.count(), 1)
and when i run the test i get '201' printed in console AND AssertionError: 0 != 1
i'm fvkin confused
In the serializer create() the object was never saved so change:
return Item(**validated_data)
to:
return Item.objects.create(**validated_data) # create the object

select filtering and removal if they are already present in the db

look at the picture before answering me.
that group2 is inside saved in the db with the button I open a modal that allows me to save other groups in the db and I would like that the same groups no longer appear in that select if I have already added them
form.py
class EserciziForm(forms.ModelForm):
class Meta:
model = models.DatiEsercizi
exclude = ['gruppo_single']
#fields = '__all__'
class GruppiForm(forms.ModelForm):
class Meta:
model = models.DatiGruppi
exclude = ['gruppi_scheda']
views.py
def creazione(request, nome):
scheda = get_object_or_404(Schede, nome_scheda = nome)
eserciziFormSet = formset_factory(EserciziForm, extra = 0)
if request.method == "POST":
gruppo_form = GruppiForm(request.POST, prefix = 'gruppo')
if gruppo_form.is_valid():
gruppo = gruppo_form.save(commit = False)
gruppo.gruppi_scheda = scheda
gruppoName = gruppo_form.cleaned_data['dati_gruppo']
gruppo.save()
esercizi_formset = eserciziFormSet(request.POST, prefix='esercizi')
for esercizi in esercizi_formset:
esercizi_instance = esercizi.save(commit = False)
esercizi_instance.gruppo_single = get_object_or_404(DatiGruppi, gruppi_scheda = scheda.id, dati_gruppo = gruppoName)
esercizi_instance.save()
return HttpResponseRedirect(request.path_info)
else:
gruppo_form = GruppiForm(prefix = 'gruppo')
esercizi_formset = eserciziFormSet(prefix='esercizi')
context = {'scheda' : scheda, 'gruppo_form' : gruppo_form, 'esercizi_formset': esercizi_formset}
return render(request, 'crea/passo2.html', context
models.py
class DatiGruppi(models.Model):
giorni_settimana_scelta = [
("LUNEDI","Lunedì"),
("MARTEDI","Martedì"),
("MERCOLEDI","Mercoledì"),
("GIOVEDI","Giovedì"),
("VENERDI","Venerdì"),
("SABATO","Sabato"),
("DOMENICA","Domenica")
]
giorni_settimana = MultiSelectField(choices = giorni_settimana_scelta,default = '-')
dati_gruppo = models.ForeignKey(
Gruppi,on_delete = models.CASCADE, related_name = 'dati_gruppo')
gruppi_scheda = models.ForeignKey(Schede,on_delete = models.CASCADE, related_name = 'gruppi_scheda')
class Schede(models.Model):
nome_scheda = models.CharField(max_length=100)
data_inizio = models.DateField()
data_fine = models.DateField()
utente = models.ForeignKey(User, on_delete = models.CASCADE,related_name = 'utente')
You can override a form field before instantiate it like this :
views.py
from django import forms
if request.method == "POST":
# Post logic here
else:
# We try to retrieve group that the current user is not yet in.
# Not your logic, but to sum up, you have to retrieve the groups
# which had not yet been added.
# Use a filter that permit you to retrieve only groups which had not yet been added.
group_to_add = Group.objects.filter(...)
GruppiForm.base_fields['group_field'] = forms.ModelChoiceField(
queryset=group_to_add)
# Instantiate the form now
# In this form, the choices are only those contained in the group_to_add queryset
form = GruppiForm(prefix = 'gruppo')

django-select2 not working with inlines in django-admin

Here are my models and admin classes:
---------------------Models-----------------------
from django.contrib.auth.models import User
class PurchaseOrder(models.Model):
buyer = models.ForeignKey(User)
is_debit = models.BooleanField(default = False)
delivery_address = models.ForeignKey('useraccounts.Address')
organisation = models.ForeignKey('useraccounts.AdminOrganisations')
date_time = models.DateTimeField(auto_now_add=True)
total_discount = models.IntegerField()
tds = models.IntegerField()
mode_of_payment = models.ForeignKey(ModeOfPayment)
is_active = models.BooleanField(default = True)
class Meta:
verbose_name_plural = "Purchase Orders"
def __unicode__(self):
return '%s' % (self.id)
----------------------------------Admin----------------------------------------
"""
This class is used to add, edit or delete the details of item purchased
"""
class PurchasedItemInline(admin.StackedInline):
form = ItemSelectForm
model = PurchasedItem
fields = ['parent_category', 'sub_category', 'item', 'qty', ]
extra = 10
class BuyerChoices(AutoModelSelect2Field):
queryset = User.objects.all()
search_fields = ['username__icontains', ]
class BuyerForm(ModelForm):
user_verbose_name = 'Buyer'
buyer = BuyerChoices(
label='Buyer',
widget=AutoHeavySelect2Widget(
select2_options={
'width': '220px',
'placeholder': 'Lookup %s ...' % user_verbose_name
}
)
)
class Meta:
model = PurchaseOrder
fields = '__all__'
"""
This class is used to add, edit or delete the details of items
purchased but buyer has not confirmed the items purchased, this class
inherits the fields of PurchaseOrder derscribing the delivery address of
buyer , is_debit , total discount , tds and mode of payment
"""
class PurchaseOrderAdmin(admin.ModelAdmin):
form = BuyerForm
#list_display = ['id','buyer','delivery_address','date_time','is_active']
inlines = [PurchasedItemInline]
# model = PurchaseOrder
#actions = [mark_active, mark_inactive]
#list_filter = ['date_time']
#search_fields = ['id']
list_per_page = 20
def response_add(self, request, obj, post_url_continue=None):
request.session['old_post'] = request.POST
request.session['purchase_order_id'] = obj.id
return HttpResponseRedirect('/suspense/add_distance/')
I am trying to implement django-select2, but when I use inlines in
PurchaseOrderAdmin it doesn't show the field where I have implemented
django-select2:
But when I remove inlines, it works fine:
Edit
Here is the ItemSelectForm
class ItemSelectForm(forms.ModelForm):
class Media:
js = (
'http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
'js/ajax.js',
)
try:
parent_category = forms.ModelChoiceField(queryset=Category.objects.\
filter(parent__parent__isnull=True).filter(parent__isnull=False))
sub_category_id = Category.objects.values_list('id',flat=True)
sub_category_name = Category.objects.values_list('name',flat=True)
sub_category_choices = [('', '--------')] + [(id, name) for id, name in
itertools.izip(sub_category_id, sub_category_name)]
sub_category = forms.ChoiceField(sub_category_choices)
except:
pass
item = forms.ModelChoiceField(queryset = Product.objects.all())
def __init__(self, *args, **kwargs):
super(ItemSelectForm, self).__init__(*args, **kwargs)
self.fields['parent_category'].widget.attrs={'class': 'parent_category'}
self.fields['sub_category'].widget.attrs={'class': 'sub_category'}
self.fields['item'].widget.attrs={'class': 'item'}
It worked for me by adding the following line in the static/suit/js/suit.js
Add:
(function ($) {
Suit.after_inline.register('init_select2', function(inline_prefix, row){
$(row).find('select').select2();
});

Django and ModelForm. How to change IntegerField to dropdown box

I have a model that looks like this
class RSVP (models.Model):
def __unicode__(self):
return self.firstName + " " + self.lastName
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=30)
rsvpID = models.CharField(max_length=9, unique = True)
allowedAdults = models.IntegerField(default = 2)
allowedChildren = models.IntegerField(default = 0)
adultsAttending = models.IntegerField(default = 0)
childrenAttending = models.IntegerField(default = 0)
and I have a ModelForm that looks like this
class RsvpForm(ModelForm):
class Meta:
model = RSVP
exclude= ('firstName', 'lastName', 'allowedAdults', 'allowedChildren')
What I would like to happen is that instead of a text field for the adultsAttending, a dropdown box with the values 0 to allowedAdults shows up. This is for a wedding rsvp site and I'd like to set the max number of +1's an invitee can bring on an individual basis
Any thoughts on how to go about this?
I'm thinking you want to fork the allowed children/ adults as well as the name to another model:
models.py
class Invited(models.Model):
f_name = models.CharField()
l_name = models.CharField()
allowed_adults = models.IntegerField()
allowed_children = models.IntegerField()
class RSVP(models.Model):
invited = models.ForeignKey(Invited)
adults_attending = models.IntegerField()
children_attending = models.IntegerField()
Then you would create the invited objects and assign the allowed adults and children. And the RSVP form would take those number into account when generating the choices for your drop down box.
The drop down can be implemented by overriding the IntegerField widget with a ChoiceField
forms.py
class InvitedForm(forms.ModelForm):
class Meta:
model = Invited
class RSVPForm(forms.ModelForm):
class Meta:
model = RSVP
exclude = ['invited',]
def __init__(self, *args, **kwargs):
max_adults = kwargs.pop('max_adults',2) #default to 2 if no max set
max_children = kwargs.pop('max_children',2) #default to 2 if no max set
super(RSVPForm, self).__init__(*args, **kwargs)
adult_choices = ( (x,str(x)) for x in range(max_adults+1)) )
children_choices = ( (x,str(x)) for x in range(max_children+1)) )
self.fields['adults_attending'] = forms.ChoiceField(choices = adult_choices)
self.fields['children_attending'] = forms.ChoiceField(choices = children_choices)
views.py
def rsvp_view(request, invited_id):
invited = get_object_or_404(Invited, pk=invited_id)
if request.method=='POST':
form = RSVPForm(request.POST, max_adults=invited.allowed_adults,
max_children=invited.allowed_children)
if form.is_valid():
rsvp = form.save(commit=False)
rsvp.invited = invited
rsvp.save()
return HttpResponse("Success")
else:
form = RSVPForm(max_adults=invited.allowed_adults, max_children=invited.allowed_children)
context = { 'form':form,
'invited':invited }
return render_to_response('rsvp.html', context,
context_instance=RequestContext(request))