query in django model - django

I am using django and as I am pretty new I have some questions.
I have one model called Signatures and a ModelForm called SignatureForm in my models.py file:
class Signature(models.Model):
sig = models.ForeignKey(Device)
STATE = models.CharField(max_length=3, choices=STATE_CHOICES)
interval = models.DecimalField(max_digits=3, decimal_places=2)
verticies = models.CharField(max_length=150)
class SignatureForm(ModelForm):
class Meta:
model = Signature
widgets = {
'verticies': HiddenInput,
}
To use it, I wrote the following function in views.py:
def SigEditor(request):
# If the form has been sent:
if request.method == 'POST':
form = SignatureForm(request.POST)
# If it is valid
if form.is_valid():
# Create a new Signature object.
form.save()
return render_to_response('eQL/sig/form_sent.html')
else:
return render_to_response('eQL/sig/try_again.html')
else:
form = SignatureForm()
return render_to_response('eQL/sig/showImage.html', {'form' : form})
However, I don't want to save all the new signatures. I mean, if the user introduces a new signature of the device A and state B, I would like to check if I have some signature like that in my database, delete it and then save the new one so that I have only one signature saved for each device and state.
I have tried something like this before saving it but of course is not working:
q = Signature.objects.filter(sig = s, STATE = st)
if q.count != 0:
q.delete()
form.save()
can anyone help?? thanks!!

If you really do want to delete, why not?
Signature.objects.filter(sig=s, STATE=st).delete()
If you only ever want one combination of those items, you could use get_or_create, and pass in the instance to your ModelForm.
instance, created = Signature.objects.get_or_create(sig=s, STATE=st)
form = SignatureForm(request.POST, instance=signature)
# edit instance.
Or put it in your form save logic:
class SignatureForm(ModelForm):
def save(self, *args, **kwargs):
data = self.cleaned_data
instance, created = Signature.objects.get_or_create(sig=data['sig'], STATE=data['state'])
self.instance = instance
super(SignatureForm, self).save(*args, **kwargs)

Related

Inconsistent behavoiur of save(commit=False) for a ModelForm in Django 2.2

I have a ModelForm that selects one field and excludes the rest, one of which is a ForeignKey that I need to populate manually before saving the form.
I'm in the process of fixing a bug that one of my views has and I'm making use of the request.session object to store information so that the GET and POST method funcions will be in synced by the session in locating the model at hand instead of separately iterating though the database to pin-point what model object the submitted data should be saved for.
I'm making use of the form_object.save(commit=False) funcionality in other places of the same view and it works as I need but for some reason there is a section of the view where it just doesn't populate the extra field before calling the eventual save() method and I get an IntegrityError for that column in the database, even if it is not null=False in my model declaration right now (and I think it'd rather should be..).
So here's my ModelForm:
class PesoFormApertura(ModelForm):
peso_apertura = forms.DecimalField(min_value=0,required=True)
class Meta:
model = Peso
fields = ('peso_apertura',)
here's the Model itself:
class Peso(models.Model):
prodotto = models.ForeignKey(ProdottoPesato,on_delete=models.CASCADE)
peso_apertura = models.DecimalField(max_digits=8,decimal_places=2, blank=False, null=True)
peso_calcolato = models.DecimalField(max_digits=8,decimal_places=2, blank=True, null=True)
peso_chiusura = models.DecimalField(max_digits=8,decimal_places=2, blank=True, null=True)
data = models.DateField(auto_now_add=True, blank = False)
def __str__(self):
return "{} - {} - {}".format(self.prodotto.nome, self.prodotto.get_categoria_display(), self.data)
def save(self, *args, **kwargs):
if self.peso_apertura == 0:
prodotto_associato = ProdottoPesato.objects.get(pk = self.prodotto.pk)
if prodotto_associato.permanente == False:
prodotto_associato.delete()
self.delete()
else:
super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)
class Meta:
ordering = ['prodotto']
and here's the view part where the save() method is failing (where I placed a comment):
if not 'prodotto-da-correggere' in request.session:
for prodotto in tutti_prodotti:
pesi_questo_prodotto_oggi = prodotto.pesi_di_oggi()
for peso in pesi_questo_prodotto_oggi:
if peso.peso_apertura == None:
prodotto_da_elaborare = prodotto
peso_del_giorno = peso
break
if prodotto_da_elaborare:
finito = False
instance_peso = peso_del_giorno
form = PesoFormApertura(request.POST, instance = instance_peso)
if form.is_valid():
form.save(commit=False) # WORKS FINE
form.prodotto = prodotto_da_elaborare
form.save()
else:
form = PesoFormApertura(request.POST)
else: # HERE IS WHERE IT DOESN'T BEHAVE LIKE ABOVE
prodotto_da_elaborare = ProdottoPesato.objects.get(id=request.session['prodotto-da-correggere'])
peso_del_giorno = None
for peso in prodotto_da_elaborare.pesi_di_oggi():
if peso.peso_apertura == None or peso.peso_apertura > 0:
peso_del_giorno = peso
break
form_correzione = PesoFormApertura(request.POST, instance = peso_del_giorno)
if form_correzione.is_valid():
form_correzione.save(commit=False)
form_correzione.prodotto = prodotto_da_elaborare
form_correzione.save() # IT DOESN'T ADD THE INFORMATION TO THE COLUMN WHEN IT SAVES
request.session.flush()
The save() method works alright for the first part of the IF statement and just doesn't work for the rest of the snippet in the ELSE section.
So I'm wondering if the session has something to do with this.
When you call form.save() it returns the instance. You should modify and save that instance.
if form_correzione.is_valid():
peso = form_correzione.save(commit=False)
peso = prodotto_da_elaborare
peso.save()
You should change the other part of the view to use this approach as well. It looks like form.prodotto = prodotto_da_elaborare is having no effect, but you haven't noticed because prodotto is already set so you don't get an integrity error.

How can I customize default to django REST serializer

http://www.django-rest-framework.org/api-guide/validators/#currentuserdefault
I wants to read default value from userprofile automatically. Right now the offical method support User and DateTime. But I want my customized value. How can I do that?
owner = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
This is my workaround. Copy the example from source code and place it here.
Hope near future it has friendly solution.
class CurrentBranchDefault:
def set_context(self, serializer_field):
self.user = serializer_field.context['request'].user
self.branch = self.user.userprofile.selected_branch
def __call__(self):
return self.branch
def __repr__(self):
return unicode_to_repr('%s()' % self.__class__.__name__)
class StaffOrderSerializer(serializers.ModelSerializer):
branch = serializers.HiddenField(default=CurrentBranchDefault())
If you want to calculate one hidden field, using other incoming fields in serializer,
than you need to use serializer_field.context['request'].data
This "data" will be validated before "set_context()", so you can use it in safe.
I hope it will help someone else.
class DefineNoteType:
def set_context(self, serializer_field):
# setting field "type", calculated by other serializer fields
data = serializer_field.context['request'].data
subscriber = data.get('subscriber', None)
connection = data.get('connection', None)
if subscriber:
self.type = 'subscriber_type'
elif connection:
self.type = 'connection_type'
else:
raise serializers.ValidationError('Custom error.')
def __call__(self):
return self.type
class NoteSerializer(serializers.ModelSerializer):
type = serializers.HiddenField(default=DefineNoteType())

ModelChoiceField in forms.Form won't validate if queryset is overridden

I have a django ModelChoiceField that won't validate if I override the queryset.
class PersonalNote(forms.Form):
tile = ModelChoiceField(queryset=Tile.objects.none())
note = forms.CharField()
form = PersonalNote()
form.fields['tile'].queryset = Tile.objects.filter(section__xxx=yyy)
The form.is_valid() error is: "Select a valid choice. That choice is not one of the available choices".
If Tile.objects.none() is replaced with Tile.objects.all() it validates, but loads far too much data from the database. I've also tried:
class PersonalNote(forms.Form):
tile = ModelChoiceField(queryset=Tile.objects.none())
note = forms.CharField()
def __init__(self, *args, **kwargs):
yyy = kwargs.pop('yyy', None)
super(PersonalNote, self).__init__(*args, **kwargs)
if yyy:
self.fields['tile'].queryset = Tile.objects.filter(section__xxx=yyy)
What might be wrong here? Note the real application also overrides the label, but that does not seem to be a factor here:
class ModelChoiceField2(forms.ModelChoiceField):
def label_from_instance(self, obj):
assert isinstance(obj,Tile)
return obj.child_title()
After 2 hours I found the solution. Because you specified a queryset of none in the class definition, when you instantiate that PersonalNote(request.POST) to be validated it is referenceing a null query set
class PersonalNote(forms.Form):
tile = ModelChoiceField(queryset=Tile.objects.none())
note = forms.CharField()
To fix this, when you create your form based on a POST request be sure to overwrite your queryset AGAIN before you check is_valid()
def some_view_def(request):
form = PersonalNote(request.POST)
**form.fields['tile'].queryset = Tile.objects.filter(section__xxx=yyy)**
if form.is_valid():
#Do whatever it is
When you pass an empty queryset to ModelChoiceField you're saying that nothing will be valid for that field. Perhaps you could filter the queryset so there aren't too many options.
I also had this problem. The idea is to dynamically change the queryset of a ModelChoiceField based on a condition (in my case it was a filter made by another ModelChoiceField).
So, having the next model as example:
class FilterModel(models.Model):
name = models.CharField()
class FooModel(models.Model):
filter_field = models.ForeignKey(FilterModel)
name = models.CharField()
class MyModel(models.Model):
foo_field = models.ForeignKey(FooModel)
As you can see, MyModel has a foreign key with FooModel, but not with FilterModel. So, in order to filter the FooModel options, I added a new ModelChoiceField on my form:
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
# your code here
self.fields['my_filter_field'] = forms.ModelChoiceField(FilterModel, initial=my_filter_field_selected)
self.fields['my_filter_field'].queryset = FilterModel.objects.all()
Then, on your Front-End you can use Ajax to load the options of foo_field, based on the selected value of my_filter_field. At this point everyting should be working. But, when the form is loaded, it will bring all the posible options from FooModel. To avoid this, you need to dynamically change the queryset of foo_field.
On my form view, I passed a new argument to MyForm:
id_filter_field = request.POST.get('my_filter_field', None)
form = MyForm(data=request.POST, id_filter_field=id_filter_field)
Now, you can use that argument on MyForm to change the queryset:
class MyForm(forms.ModelForm):
# your code here
def __init__(self, *args, **kwargs):
self.id_filter_field = kwargs.pop('id_filter_field', None)
# your code here
if self.id_filter_field:
self.fields['foo_field'].queryset = FooModel.objects.filter(filter_field_id=self.id_filter_field)
else:
self.fields['foo_field'].queryset = FooModel.objects.none()

Saving form data rewrites the same row

i can't figure out how to save my form data creating a new row, when saving it just rewrites the data using the same 'id' and trhows me an error when there are multiple rows, this is my code:
models.py:
class Submitter(models.Model):
submitter=models.ForeignKey(User)
def __unicode__(self):
return self.submitter.username
class Store(models.Model):
creator=models.ForeignKey(Submitter)
name = models.CharField(_('name'),blank=True,max_length=30)
st = models.CharField(_('Street'),blank=True,max_length=30)
sub_date = models.DateField(_('Visit Date'),)
def __str__(self):
return u'%s-%s-%s'%(self.creator,self.name,self.sub_date)
views.py:
def StoreSave(request):
if request.method == 'POST':
form = StoreForm(request.POST)
if form.is_valid():
submitter, dummy= Creator.objects.get_or_create(creator=request.user)
store, created = Store.objects.get_or_create(
submitter=submitter
)
store.name = form.cleaned_data['name']
store.st = form.cleaned_data['st']
store.visit_date = form.cleaned_data['visit_date']
store.save()
return HttpResponseRedirect('/user/%s/' % request.user.username)
else:
form = StoreForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('store/create_store.html', variables)
If you want to create a new row, create it. :-) Like
store = Store(submitter=submitter,
name=form.cleaned_data['name'],
st=form.cleaned_data['st'],
store.visit_date=form.cleaned_data['visit_date'])
store.save()
Now you use get_or_create method which tries to find a row with given parameters, so that's why you updating it. And this method throws an error when there are multiple rows, yes, it's its normal behavior.
By the way it's better to place this saving code in form's method (save for example).
P. S. Just noticed you don't have visit_date field in your model, I think you meant sub_date.
Instead of using get_or_create you can simply use create
Store.objects.create(
submitter=submitter,
name=form.cleaned_data['name'],
st=form.cleaned_data['st'],
visit_date=form.cleaned_data['visit_date']
)
More information about the differences can be found Django Model() vs Model.objects.create()

Change Field of Foreign Key Object

I have the following problem.
I have a model Towar:
class Towar(models.Model):
nrSeryjny = models.CharField(max_length=100)
opis = models.CharField(max_length=255)
naStanie = models.NullBooleanField(null=True)
def __unicode__(self):
return "%s" % self.opis
def lowerName(self):
return self.__class__.__name__.lower()
def checkState(self):
return self.naStanie
def changeState(self,state):
self.naStanie=state
class Meta:
ordering=['nrSeryjny']
app_label = 'baza'
permissions=(("view_towar","mozna miec podglad dla towar"),)
and another model, Wypozyczenie, which is linked to Towar by a foreign key relationship:
class Wypozyczenie(models.Model):
dataPobrania = models.DateField()
pracownik = models.ForeignKey(User,null=True)
kontrahent = models.ForeignKey(Kontrahenci,null=True)
towar = models.ForeignKey(Towar,null=True)
objects = WypozyczenieManager()
default_objects = models.Manager()
ZwrotyObjects = WypozyczenieZwrotyManager()
def lowerName(self):
return self.__class__.__name__.lower()
def __unicode__(self):
if self.towar == None:
return "Dla:%s -- Kto:%s -- Kiedy:%s -- Co:%s" % (self.kontrahent,self.pracownik,self.dataPobrania,"Brak")
else:
return "Dla:%s -- Kto:%s -- Kiedy:%s -- Co:%s" % (self.kontrahent,self.pracownik,self.dataPobrania,self.towar)
class Meta:
ordering = ['dataPobrania']
app_label = 'baza'
permissions = (("view_wypozyczenie","mozna miec podglad dla wypozyczenie"),)
and a view to add models:
def modelAdd(request,model,modelForm):
mod = model()
if request.user.has_perm('baza.add_%s' % mod.lowerName()):
if request.method == 'POST':
form=modelForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/'+ mod.lowerName() + '/')
else:
form = modelForm()
v = RequestContext(request,{'form':form})
return render_to_response('add_form.html',v)
What I want is that when I add Wypozyczenie and save it, then the Towar that is stored by Wypozyczenie changes its naStanie field from True to False.
Greets
If you want to always keep those two in sync you can override Wypozyczenie's save() method.
class Wypozyczenie(models.Model):
...
def save(self):
self.towar.naStanie = False
self.towar.save()
Alternatively, you can also override ModelForm's save() method.
What have you tried?
Can't you just put
myinstance = form.save()
towar = myinstance.towar
towar.naStanie = False
toware.save()
instead of your simple call to form.save() in your view.
You can use signals emitted when saving your Wypozyczenie object. It might be a little "cleaner" than overriding save(), especially when it's useful to re-use the function for other models:
#receiver(models.signals.post_save, sender=Wypozyczenie)
def after_wypozyczenie_save(sender, instance, created, **kwargs):
# `instance` is your saved Wypozyczenie object, you can
# access all it's fields here:
instance.towar.naStanie = False
instance.towar.save()
# It's also possible to do different action on the first save
# and on subsequent updates:
#
# if created:
# ...
# else:
# ...
There are other signals sent before saving or on deletion. Django documentation on signals is quite helpful here.