I'm using a model formset to allow a user to dynamically add duplicate forms to a table(modbus registers since a device can have multiple registers).
The problem I'm having is that as soon as I save the formset(store to db), when I come back to the same page to create a new device with registers, django renders all the previously created forms instead only 1 empty form(then being able to add forms to that).
Here is an example after having created 3 forms in my formset(stored in db):
Here is what it should look like:
It should only display 1 empty form in my formset, the user can then dynamically add forms.
my view:
def create_modbus_view(request):
modbus_device = CreateModbusForm()
RegisterFormset = modelformset_factory(Register, form=ModbusRegistersForm)
register_forms = RegisterFormset()
return render(
request,
'app/create_modbus.html',
context_instance = RequestContext(request,
{
'title':'Create Modbus Device',
'tag': 'create_modbus',
'modbus_device': modbus_device,
'register_forms': register_forms
})
)
models:
class Register(models.Model):
ixRegister = models.AutoField(primary_key=True)
sRegisterName = models.CharField(max_length=100)
iStartingAddr = models.IntegerField()
bRange = models.BooleanField(default=False)
ixRegisterType = models.ForeignKey(RegisterType)
iOffset = models.IntegerField(blank=True, null=True)
class Meta:
db_table = 'TRegister'
class ModbusDevice(models.Model):
ixModbusDevice = models.AutoField(primary_key=True)
sModbusName = models.CharField(verbose_name='Device Name',max_length=100)
iPort = models.IntegerField(verbose_name='Port')
iSlave = models.IntegerField(verbose_name='Slave ID')
sIP = models.GenericIPAddressField(verbose_name='IP Address')
class Meta:
db_table = 'TModbusDevice'
form:
class ModbusRegistersForm(ModelForm):
ixRegisterType = ModelChoiceField(queryset=RegisterType.objects.all()),
bRange = BooleanField(required=False)
bRange.widget.attrs['data-form'] = 0
class Meta:
model = Register
fields = ['sRegisterName','iStartingAddr','bRange','ixRegisterType','iOffset']
widgets = {
'sRegisterName': TextInput(attrs={'placeholder': 'Register Name','class': 'form-control', 'data-form': '0'}),
'iStartingAddr': TextInput(attrs={'placeholder': 'Starting address','class': 'form-control','data-form': '0'}),
'iOffset': TextInput(attrs={'placeholder': 'Address offset','class': 'form-control','data-form': '0'}),
}
class CreateModbusForm(ModelForm):
class Meta:
model = ModbusDevice
fields = ['sModbusName','iPort', 'iSlave', 'sIP']
widgets = {
'sModbusName': TextInput(attrs={'placeholder': 'Device Name','class': 'form-control','id': 'device-name',}),
'iPort': TextInput(attrs={'placeholder': 'Port','class': 'form-control','id': 'port',}),
'iSlave': TextInput(attrs={'placeholder': 'Slave id','class': 'form-control','id': 'slave-id',}),
'sIP': TextInput(attrs={'placeholder': 'Modbus IP address','class': 'form-control','id': 'ip-address',})
}
this seems to work
django modelformset_factory sustains the previously submitted data even after successfully created the objects
seems i just have to prevent it from querying my tables
Related
I am trying to set initial values for my django model form
but when I try in my views.py:
add_contact_form = newContactForm(request.POST, initial={'relation':'Customer'})
It doesn't work. If I specify default values in the model they work fine.
Models.py:
class contact(models.Model):
name = models.CharField(max_length=20, blank=True)
email = models.EmailField(primary_key=True)
tel = PhoneField(null=True, blank=True)
contact_relations = [
('Supplier', 'Supplier'),
('Customer', 'Customer'),
('Other', 'Other'),
]
relation = models.CharField(max_length=50, choices=contact_relations)
Forms.py:
class newContactForm(forms.ModelForm):
class Meta:
model = contact
fields = [
'name',
'email',
'tel',
'relation',
]
widgets = {
'relation': forms.RadioSelect(),
}
Views.py:
def add_contact_view(request):
add_contact_form = newContactForm(request.POST, initial={'relation':'Customer'})
if add_contact_form.is_valid():
add_contact_form.save()
else:
add_contact_form = newContactForm()
context = {
"add_contact_form":add_contact_form,
}
return render(request, 'contacts/new_contact.html', context)
thats because you are not setting them when the page loads, you are initializing when the form is submitted.
def add_contact_view(request):
add_contact_form = newContactForm(request.POST)
if add_contact_form.is_valid():
add_contact_form.save()
else:
add_contact_form = newContactForm(initial={'relation':'Customer'})
context = {
"add_contact_form":add_contact_form,
}
return render(request, 'contacts/new_contact.html', context)
I want to design solution for ordering items. I have endpoint that create orders BUT I need to to have items object in the order. let me show you the code
class ItemModel(models.Model):
name = models.CharField(max_length=50)
price = models.FloatField()
discretion = models.CharField(max_length=500)
available = models.BooleanField(default=True)
class OrderModel(models.Model):
phone = models.CharField(max_length=20)
delevary_time = models.DateTimeField()
class CartModel(models.Model):
order = models.ForeignKey(OrderModel, on_delete=models.CASCADE, related_name='order_m')
item = models.ForeignKey(ItemModel, on_delete=models.CASCADE, related_name='item_m')
I need endpoint that create order to me. her what I did
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = CartModel
exclude = ['order',]
depth = 2
class OrderSerializer(serializers.ModelSerializer):
cart = serializers.SerializerMethodField()
class Meta:
model = OrderModel
fields = ['phone', 'state', 'delevary_time', 'cart']
def get_cart(self, obj):
cart = CartModel.objects.filter(order__id=obj.id)
serializer = CartSerializer(cart, many=True)
return serializer.data
this is the endpoint
router.register('order', OrderViewSet, 'api-order')
{
"phone": 124997988698,
"delevary_time": "2020-07-17T19:34:00",
"cart": [
{
"item": 1
},
{
"item": 2
}
]
}
when I post the json it don't save the cart it only save the oder phone and delevary_time. How I can save the cart at the same time
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = CartModel
exclude = ['order',]
depth = 2
class OrderSerializer(serializers.ModelSerializer):
order_m = CartSerializer(many=True) # adding this
class Meta:
model = OrderModel
fields = ['phone', 'state', 'delevary_time', 'order_m']
def create(self, validated_data):
cart_data = validated_data.pop('order_m')
order = OrderModel.objects.create(**validated_data)
for c in cart_data:
CartModel.objects.create(order=order, **c)
return order
I have 2 models:
class ModbusDevice(models.Model):
ixModbusDevice = models.AutoField(primary_key=True)
sModbusName = models.CharField(verbose_name='Device Name',max_length=100)
iPort = models.IntegerField(verbose_name='Port')
iSlave = models.IntegerField(verbose_name='Slave ID')
sIP = models.GenericIPAddressField(verbose_name='IP Address')
class Meta:
db_table = 'TModbusDevice'
class BACnetDevice(models.Model):
ixBACnetDevice = models.AutoField(primary_key=True)
ixModbusDevice = models.OneToOneField(ModbusDevice)
sIP = models.GenericIPAddressField(verbose_name='IP Address')
iPort = models.IntegerField(verbose_name='Port')
iSubnet = models.IntegerField(verbose_name='Subnet', blank=True)
bStatus = models.BooleanField(default=False)
class Meta:
db_table = 'TBACnetDevice'
As you can see each BACnetDevice is related to each ModbusDevice via one to one. What I'm trying to do is display a table with mixed fields from each model.
I want to display the ModbusDevice name along with sIP, iPort and iSubnet from my BACnetDevice model like this(somewhat what i had working):
I'm having difficulty with rendering the model's formset foreign key field
I've tried this so far in my view:
BACnetFormSet = inlineformset_factory(ModbusDevice, BACnetDevice, fields=('sIP','iPort','iSubnet',))
bacnet_forms = BACnetFormSet()
return render(
request,
'app/create_bacnet.html',
context_instance = RequestContext(request,
{
'title':'Create BACnet Device',
'tag': 'create_bacnet',
'bacnet_forms': bacnet_forms
})
)
How can I serialize related objects in DRF. Am having three models auth_user (User), ModelA, ModelB.
My models:
class ModelA(models.Model):
user = models.OneToOneField(auth_user, related_name = 'modelA')
name = models.CharField(max_length = 30)
class ModelB(models.Model):
owner = models.OneToOneField(auth_user)
user = models.OneToOneField(auth_user, related_name = 'modelB')
type = models.ForeignKey(ModelD)
cost = models.IntegerField()
class ModelD(models.Model):
type_desc = models.CharField(max_length = 40)
My serialilzers:
class A(serializers.ModelSerializer):
class Meta:
model = ModelA
fields = ('name', )
class B(serializers.ModelSerializer):
class Meta:
model = ModelB
fields = ('type', 'cost', )
class AuthUserSerilaizer(serializers.ModelSerializer):
userA = serializers.RelatedField(source = 'modelA')
userB = serializers.RelatedField(source = 'modelB')
class Meta:
model = User
fields = ('email', 'password', 'userA', 'userB', )
write_only_fields = ('password',)
#transaction.commit_manually
def restore_object(self, attrs, instance = None):
try:
user = User.objects.create_user(email = attrs.get('email'), password = attrs.get('password'))
modela = ModelA(user =user, name = attrs.get('name'))
modela.save()
transaction.commit()
return User(email = attrs.get('email'))
except Exception ,e:
transaction.rollback()
print repr(e)
JSON I'm passing
data = {'email':'123#gmail.com,
'password' : 'dummy',
'userA' : {'name' :'123'},
'userB':{'type':1,'cost':'100'}
Whenever am making a POST request the 'attrs' gets only email and password not userA and userB, why? How can I deserialize and create data serially in the respective tables.
try this in your view
from django.core.serializers.json import DjangoJSONEncoder
import json
response = json.dumps(data,cls=DjangoJSONEncoder)
return HttpResponse(response, mimetype="application/json")
and in success function you can access using
usera_name = response.userA.name
userb_type = response.userB.type
userb_cost = response.userB.cost
I'm saving a form, but there is one save() method that is outside the transaction. The save() method outside a transaction is the save() on the "BicycleAdCategoryForm".
Here is the code:
models.py
class Main(models.Model):
section = models.ForeignKey(Section)
user = models.ForeignKey(User)
title = models.CharField(max_length=250)
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.title
# To order in the admin by name of the section
class Meta:
ordering = ['date_inserted']
class BicycleAd(models.Model):
main = models.ForeignKey(Main)
bicycleadtype = models.ForeignKey(BicycleAdType)
bicycleaditemkind = models.ForeignKey(BicycleAdItemKind) # MPTT Model
bicycleadcondition = models.ForeignKey(BicycleAdCondition)
country = models.ForeignKey(GeonamesCountry)
city = models.ForeignKey(GeonamesLocal)
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now=True)
# To order in the admin by name of the section
class Meta:
ordering = ['date_inserted']
class BicycleAdCategoryType(models.Model):
n_bicycle_ad_category_type = models.CharField(max_length=100) # COMPRA, VENDA, TROCA
date_inserted = models.DateTimeField(auto_now_add=True)
date_last_update = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.n_bicycle_ad_category_type
# To order in the admin by name of the section
class Meta:
ordering = ['n_bicycle_ad_category_type']
forms.py
class MainForm(forms.ModelForm):
class Meta:
model = Main
exclude = ('user', 'section')
class BicycleAdForm(forms.ModelForm):
class Meta:
model = BicycleAd
exclude = ('main', 'bicycleadtype', 'bicycleaditemkind', 'bicycleadcondition', 'city') # DPS RETIRAR DAQUI A "CITY"
class BicycleAdCategoryForm(forms.ModelForm):
bicycleadcategorytype = forms.ModelMultipleChoiceField(queryset=BicycleAdCategoryType.objects.all(), required=False, widget=forms.CheckboxSelectMultiple) # Se retirar o widget fico uma SELECT box em q posso selecionar varias opcoes
class Meta:
model = BicycleAdCategory
exclude = ('bicyclead',)
def save(self, commit, rel_obj):
data = self.data.getlist('bicycleadcategorytype')
for item in data:
obj_bicycleadcategory = BicycleAdCategory()
obj_bicycleadcategory.bicyclead = rel_obj
obj_bicycleadcategory.bicycleadcategorytype = BicycleAdCategoryType.objects.get(pk=item)
obj_bicycleadcategory.save()
def clean_bicycleadcategorytype(self):
data = self.cleaned_data['bicycleadcategorytype']
try:
for item in data:
bicycleadcategorytype = BicycleAdCategoryType.objects.get(pk=item.pk)
return bicycleadcategorytype
except (KeyError, BicycleAdCategoryType.DoesNotExist):
raise forms.ValidationError('Invalid Bicycle Ad Category Type. Please try again.')
views.py
def submit_ad_view(request):
if request.method == 'POST':
model_main = Main()
model_main.section = Section.objects.get(pk=request.POST['section'])
model_main.user = request.user
model_bicyclead = BicycleAd()
model_bicyclead.bicycleadtype = BicycleAdType.objects.get(pk=2)
model_bicyclead.bicycleaditemkind = BicycleAdItemKind.objects.get(pk=4)
model_bicyclead.bicycleadcondition = BicycleAdCondition.objects.get(pk=2)
model_bicyclead.city = GeonamesLocal.objects.get(pk=4803854)
form_main = MainForm(request.POST, instance = model_main)
form_bicyclead = BicycleAdForm(request.POST, instance = model_bicyclead)
form_bicycleadcategory = BicycleAdCategoryForm(request.POST)
if form_main.is_valid() and form_bicyclead.is_valid() and form_bicycleadcategory.is_valid():
main_f = form_main.save()
bicyclead_f = form_bicyclead.save(commit=False)
bicyclead_f.main = main_f
bicyclead_f.save()
bicycleadcategory_f = form_bicycleadcategory.save(commit=False, rel_obj=model_bicyclead)
resultado = 'valid'
else:
resultado = 'n_valid'
return render_to_response('app/submit_ad.html', {'resultado': resultado}, context_instance=RequestContext(request))
I think main_f and bicyclead_f are inside a transaction but bicycleadcategory_f is outside a transaction. When bicycleadcategory_f fails, main_f and bicyclead_f are stored in the database.
Any clue on what I'm doing wrong?
Best Regards,
Django executes views using the commit_on_success decorator (or at least it behaves that way). If you're view crashes (uncaught exceptions), a rollback should take place. If some data is stored, and some is not there is a possibility that your DB engine does not support transactional processing.
Check out the django doc for more info
https://docs.djangoproject.com/en/dev/ref/databases/
For example, if you're using MySQL with MyISAM you may encounter some problems
edit:
Krzysiek Szularz: I guess everybody is using django TransactionMiddleware or simmilar things, so I skipped it - and mentioned only the logic layer.