none is saving in django admin - django

productscreate.html
<form data-bind="submit: save" method="post">
{% csrf_token %}
<table border="1">
<tr>
<td>Title:
<input type="text" name="title" id="title" data-bind="value: $data.title"></td>
<br>
</tr>
<tr>
<td>Description:
<textarea name="description" id="description" data-bind="value: $data.description">Description</textarea></td>
<br>
</tr>
<tr>
<td>Image:
<input type="file" name="image" id="image" ></td>
<br>
</tr>
<tr>
<td><button type="button" id="submit" data-bind="click: save">Submit</button></td>
</tr>
</table>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-min.js"></script>
<script>
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
</script>
<script>
var ViewModel = function () {
var self = this;
self.title = ko.observable("");
self.description = ko.observable("");
var FormData = {
title: self.title,
description: self.description,
};
console.log(FormData);
self.save = function () {
$.ajax({
type: "POST",
url: 'http://127.0.0.1:8000/productsadd',
data: FormData,
contentType: "application/json",
headers: {'X-CSRFToken': csrftoken},
cache: false,
enctype: "multipart/form-data",
//processData: false,
success: function (FormData) {
alert("successfull")
window.location = '{% url "productslist" %}';
},
error: function () {
alert("fail");
}
});
};
};
ko.applyBindings(new ViewModel())
</script>
views.py
class ProductsCreate(CreateView):
model = Products
template_name = "productscreate.html"
fields = ['title', 'description', 'image']
success_url=reverse_lazy('productslist')
def productsAdd(request):
if request.is_ajax and request.method == "POST":
product=Products()
product.title = request.POST.get('title')
product.description = request.POST.get('description')
# product.image = request.FILES['image']
product.save()
return render(request,'productslist.html')
else:
return render(request,'productscreate.html')
class ProductsDetailView(DetailView):
template_name = "productsdetail.html"
queryset = Products.objects.all()
context_object_name = 'products'
model = Products
models.py
class Products(models.Model):
title = models.CharField(max_length=200,null=True)
description = models.CharField(max_length=200,null=True)
image = models.FileField(blank=True)
def __str__(self):
return str(self.title)
When i create a product in form it save as none in django admin I don't know where is the issue
I have given html with knockout js and ajax,views and models
I want to submit title,description and image in django admin using form in createproduct html
Please help me to solve this
Thanks in advance

Related

How submit a query redirecting a form on django

I'm trying to send a value from my index to a list page where I have some filters. I can send the value but it take a MultiValueDictKeyError.
I use Djagno 3.1.7, jQuery and Ajax for this exercise. I think the error is in the Ajax because it returns value "all" and the button value.
This is my index form html:
<form action="wallacar_app/lista/" method="GET" class="trip-form">
<label for="tipos">Tipo</label><br>
{% for tipo in tipos %}
<button name="type_car" value="{{ tipo.type_car }}" id="{{ tipo.type_car }}" class="form-control px-3 btn-primary btn">{{ tipo.type_car }}</option>
{% endfor %}
</form>
This is my list.html:
<div class="col-sm-2 col-2">
<div class="form-group">
<label for="type_car">TIPO DE COCHE</label>
<select class="form-control" id="type_car"
url = "{%url 'wallacar_app:get_type' %}">
<option value='all' selected>TODOS LOS TIPOS</option>
</select>
</div>
</div>
<table class="table table-bordered"
id="list_data" data-toggle="table" url = "{% url 'wallacar_app:listing' %}">
<thead>
<tr>
<th style="text-align: center;background-color: #007bff;" data-field="brand">RESULTADOS</th>
</tr>
</thead>
<tbody id="listing">
</tbody>
</table>
The Ajax code for list.html:
$('#type_car').on('change', function () {
// get the api data of updated variety
if(this.value)
send_data['type_car'] = this.value;
else
if(this.value == "all")
send_data['type_car'] = "";
else
send_data['type_car'] = this.value;
getAPIData();
});
function getType() {
// fill the options of provinces by making ajax call
// obtain the url from the provinces select input attribute
let url = $("#type_car").attr("url");
// makes request to getProvince(request) method in views
$.ajax({
method: 'GET',
url: url,
data: {},
success: function (result) {
type_option = "<option value='all' selected>TODOS LOS TIPOS</option>";
$.each(result["type_car"], function (a, b) {
type_option += "<option>" + b + "</option>"
});
$("#type_car").html(type_option)
},
error: function(response){
console.log(response)
}
});
}
My urls.py:
urlpatterns = [
path('lista/', CocheList),
path("listado_coches/", CocheListing.as_view(), name = 'listing'),
path("ajax/type/", getType, name = 'get_type'),
]
My views.py:
def CocheList(request):
return render(request,'wallacar_app/cars.html', {})
class CocheListing(ListAPIView):
pagination_class = StandardResultsSetPagination
serializer_class = CocheSerializers
def get(self, request):
if request.method == "GET" and request.GET['type_car']:
return render(request, 'wallacar_app/cars.html')
def get_queryset(self):
queryList = Coche.objects.all()
type_car = self.request.query_params.get('type_car',None)
if type_car:
queryList = queryList.filter(type_car = type_car)
def getBrand(request):
if request.method == "GET" and request.is_ajax():
brand = Coche.objects.order_by('brand').values_list('brand').distinct()
brand = [i[0] for i in list(brand)]
data = {'brand':brand}
return JsonResponse(data, status = 200)
def getType(request):
if request.method == "GET" and request.GET['type_car']:
type_car = Coche.objects.filter(type_car=request.GET['type_car']).order_by('type_car').values_list('type_car').distinct()
type_car = [i[0] for i in list(type_car)]
data = {'type_car':type_car}
#return JsonResponse(data,status=200)
return render(request, 'wallacar_app/cars.html', data)
elif request.method == "GET" and request.is_ajax() and not request.GET['type_car']:
type_car = Coche.objects.exclude(type_car__isnull=True).exclude(type_car__exact='').order_by('type_car').values_list('type_car').distinct()
type_car = [i[0] for i in list(type_car)]
data = {'type_car':type_car}
return JsonResponse(data,status=200)

Initialize a formset

I have two models connected by manytomany relationship and I am trying to use formset to create a dynamic form. I am able to save the form but the problem arise when I am trying to edit the saved instance, I don't know how to properly pass the instance to the formset such that it shows the instance data in form for editing
Here are the details:
Models.py
class Player(models.Model):
pname = models.CharField(max_length=50)
hscore = models.IntegerField()
age = models.IntegerField()
def __str__(self):
return self.pname
class Team(models.Model):
tname = models.CharField(max_length=100)
player= models.ManyToManyField(Player)
def __str__(self):
return self.tname
Forms.py
class PlayerForm(forms.ModelForm):
class Meta:
model = Player
fields = '__all__'
PlayerFormset= formset_factory(PlayerForm)
class TeamForm(forms.ModelForm):
player= PlayerFormset()
class Meta:
model = Team
fields = '__all__'
exclude = ["player"]
Views.py
def team(request):
if request.POST:
form = TeamForm(request.POST)
form.player_instances = PlayerFormset(request.POST)
if form.is_valid():
team= Team()
team.tname= form.cleaned_data['tname']
team.save()
if form.player_instances.cleaned_data is not None:
for item in form.player_instances.cleaned_data:
player = Player()
player.pname= item['pname']
player.hscore= item['hscore']
player.age= item['age']
player.save()
team.player.add(player)
team.save()
else:
form = TeamForm()
return render(request, 'packsapp/employee/new.html', {'form':form})
def updateTeam(request,pk):
team = Team.objects.get(id=pk)
form = TeamForm(instance=team)
// something here to initialize the formset ??
if request.method == "POST":
form = TeamForm(request.POST, instance=team)
if form.is_valid():
form.save()
context = {'form': form}
return render(request, 'packsapp/employee/new.html', context)
Html
<html>
<head>
<title>gffdfdf</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="/static/jquery.formset.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<form id="myForm" action="" method="post" class="">
{% csrf_token %}
<h2> Team</h2>
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% endfor %}
{{ form.player.management_form }}
<h3> Product Instance(s)</h3>
<table id="table-product" class="table">
<thead>
<tr>
<th>player name</th>
<th>highest score</th>
<th>age</th>
</tr>
</thead>
{% for player in form.player %}
<tbody class="player-instances">
<tr>
<td>{{ player.pname }}</td>
<td>{{ player.hscore }}</td>
<td>{{ player.age }}</td>
<td><input id="input_add" type="button" name="add" value=" Add More "
class="tr_clone_add btn data_input"></td>
</tr>
</tbody>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary">save</button>
</form>
</div>
<script>
var i = 1;
$("#input_add").click(function () {
$("tbody tr:first").clone().find(".data_input").each(function () {
if ($(this).attr('class') == 'tr_clone_add btn data_input') {
$(this).attr({
'id': function (_, id) {
return "remove_button"
},
'name': function (_, name) {
return "name_remove" + i
},
'value': 'Remove'
}).on("click", function () {
var a = $(this).parent();
var b = a.parent();
i = i - 1
$('#id_form-TOTAL_FORMS').val(i);
b.remove();
$('.player-instances tr').each(function (index, value) {
$(this).find('.data_input').each(function () {
$(this).attr({
'id': function (_, id) {
console.log("id", id)
var idData = id;
var splitV = String(idData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + index + "-" + tData
},
'name': function (_, name) {
console.log("name", name)
var nameData = name;
var splitV = String(nameData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + index + "-" + tData
}
});
})
})
})
} else {
$(this).attr({
'id': function (_, id) {
console.log("id", id)
var idData = id;
var splitV = String(idData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + i + "-" + tData
},
'name': function (_, name) {
console.log("name", name)
var nameData = name;
var splitV = String(nameData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + i + "-" + tData
}
});
}
}).end().appendTo("tbody");
$('#id_form-TOTAL_FORMS').val(1 + i);
$("tbody tr:last :input").each(function () {
$(this).attr({
'id': function (_, id) {
return id.replace(/\d/g, i)
},
'name': function (_, name) {
return name.replace(/\d/g, i)
},
})
})
i++;
});
</script>
</body>
</html>
update:
Use modelformset_factory in the views directly:
def post(request):
tform = TeamForm()
pform = modelformset_factory(Player, form=PlayerForm, extra = 1)
pform = pform(request.POST or None, queryset = Player.objects.filter(id__isnull = True))
if request.method == 'POST':
t = Team()
tform = TeamForm(request.POST, instance=t)
if tform.is_valid() and pform.is_valid():
tform.save()
instances = pform.save(commit=False)
for i in instances:
player = Player()
player.pname = i.pname
player.hscore = i.age
player.age = i.hscore
player.save()
t.player.add(player)
t.save()
return redirect('/exams/dashboard/')
else:
print('invalid data')
return render(request, 'team/team_create.html', {'exform': tform, 'exformset': pform})
def update(request, pk = None):
team = Team.objects.get(id = pk)
tform = TeamForm(instance = team)
pform = modelformset_factory(Player, form=PlayerForm, extra=0)
print("players", Player.objects.filter(team=team))
pform = pform(request.POST or None, queryset=Player.objects.filter(team=team))
if request.method == 'POST':
tform = TeamForm(request.POST, instance=team)
print("tform ", tform)
print("pform ", pform)
if tform.is_valid() and pform.is_valid():
tform.save()
instances = pform.save(commit=False)
for i in instances:
player = Player()
player.pname = i.pname
player.hscore = i.age
player.age = i.hscore
player.save()
t.player.add(player)
t.save()
return redirect('/exams/dashboard/')
else:
print('invalid data')
return render(request, 'team/team_create.html', {'exform': tform, 'exformset': pform})
The TeamForm has to set the queryset of the PlayerFormset.
The following shows how.
class TeamForm(forms.ModelForm):
player= PlayerFormset()
class Meta:
model = Team
fields = '__all__'
exclude = ["player"]
def __init__(self,*args, **kwargs):
super(TeamForm,self).__init__(*args,**kwargs)
self.player = PlayerFormSet(queryset=Players.objects.filter(team=self.instance)
Information from the documentation:
https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#changing-the-queryset
maybe also worth a look:
https://stackoverflow.com/a/34323401/13168118
EDIT:
your PlayerFormset should be created with a modelformset_factory like:
PlayerFormset = modelformset_factory(Player, form=PlayerForm)
modelformset documentation: https://docs.djangoproject.com/en/2.2/ref/forms/models/#modelformset-factory

Edit a formset in django

In my django app I am trying to understand many to many relationship and I am using formset to store the data like this:
Views.py
def Team_Form(request):
if request.POST:
form = TeamForm(request.POST)
form.player_instances = PlayerFormset(request.POST)
if form.is_valid():
team= Team()
team.tname= form.cleaned_data['tname']
team.save()
if form.player_instances.cleaned_data is not None:
for item in form.player_instances.cleaned_data:
player = Player()
player.pname= item['pname']
player.hscore= item['hscore']
player.age= item['age']
player.save()
team.player.add(player)
team.save()
else:
form = TeamForm()
return render(request, 'packsapp/employee/new.html', {'form':form})
Models.py
class Player(models.Model):
pname = models.CharField(max_length=50)
hscore = models.IntegerField()
age = models.IntegerField()
def __str__(self):
return self.pname
class Team(models.Model):
tname = models.CharField(max_length=100)
player= models.ManyToManyField(Player)
def __str__(self):
return self.tname
Forms.py
class PlayerForm(forms.Form):
pname = forms.CharField()
hscore= forms.IntegerField()
age = forms.IntegerField()
PlayerFormset= formset_factory(PlayerForm)
class TeamForm(forms.Form):
tname= forms.CharField()
player= PlayerFormset()
HTML
<html>
<head>
<title>gffdfdf</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="/static/jquery.formset.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<form id="myForm" action="" method="post" class="">
{% csrf_token %}
<h2> Team</h2>
{% for field in form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% endfor %}
{{ form.player.management_form }}
<h3> Product Instance(s)</h3>
<table id="table-product" class="table">
<thead>
<tr>
<th>player name</th>
<th>highest score</th>
<th>age</th>
</tr>
</thead>
{% for player in form.player %}
<tbody class="player-instances">
<tr>
<td>{{ player.pname }}</td>
<td>{{ player.hscore }}</td>
<td>{{ player.age }}</td>
<td><input id="input_add" type="button" name="add" value=" Add More "
class="tr_clone_add btn data_input"></td>
</tr>
</tbody>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary">save</button>
</form>
</div>
<script>
var i = 1;
$("#input_add").click(function () {
$("tbody tr:first").clone().find(".data_input").each(function () {
if ($(this).attr('class') == 'tr_clone_add btn data_input') {
$(this).attr({
'id': function (_, id) {
return "remove_button"
},
'name': function (_, name) {
return "name_remove" + i
},
'value': 'Remove'
}).on("click", function () {
var a = $(this).parent();
var b = a.parent();
i = i - 1
$('#id_form-TOTAL_FORMS').val(i);
b.remove();
$('.player-instances tr').each(function (index, value) {
$(this).find('.data_input').each(function () {
$(this).attr({
'id': function (_, id) {
console.log("id", id)
var idData = id;
var splitV = String(idData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + index + "-" + tData
},
'name': function (_, name) {
console.log("name", name)
var nameData = name;
var splitV = String(nameData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + index + "-" + tData
}
});
})
})
})
} else {
$(this).attr({
'id': function (_, id) {
console.log("id", id)
var idData = id;
var splitV = String(idData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + i + "-" + tData
},
'name': function (_, name) {
console.log("name", name)
var nameData = name;
var splitV = String(nameData).split('-');
var fData = splitV[0];
var tData = splitV[2];
return fData + "-" + i + "-" + tData
}
});
}
}).end().appendTo("tbody");
$('#id_form-TOTAL_FORMS').val(1 + i);
$("tbody tr:last :input").each(function () {
$(this).attr({
'id': function (_, id) {
return id.replace(/\d/g, i)
},
'name': function (_, name) {
return name.replace(/\d/g, i)
},
})
})
i++;
});
</script>
</body>
</html>
What I failed to understand is that how to edit the formset that I just Saved or to better phrase the question, How to pass the saved instance to the formset to edit it ?
Update:
I tried the modelformset_factory and it fetches all the objects from Player in post as well as update
Forms.py
PlayerFormset= modelformset_factory(Player, fields=('pname','hscore','age'))
Screenshot:
While tried to edit team Matt:
Many to many here means that one player can be in several team and also that one team can have many players.
To resolve your problem you have to create an other view, (link to the same form) that will display your form but already fill.
In your function pk for your team.
def updateTeam(request,pk):
team = Team.objects.get(id=pk)
form = TeamForm(instance=team)
if request.method == "POST":
form = TeamForm(request.POST, instance=team)
if form.is_valid():
form.save()
context = {'form': form}
return render(request, 'accounts/order_form.html', context)
That should resolve your problem !
Do not hesitate if you have any questions
If you want that, then you have to pass the filled-in form back to the template. A good example of this in the docs is https://docs.djangoproject.com/en/3.0/topics/forms/formsets/#using-a-formset-in-views-and-templates. In your code this would look like this (haven't tried in with a template):
def team_view(request):
PlayerFormset = formset_factory(PlayerForm)
if request.POST:
form = TeamForm(request.POST)
form.player_instances = PlayerFormset(request.POST)
if form.is_valid():
team = Team()
team.tname = form.cleaned_data['tname']
team.save()
if form.player_instances.cleaned_data is not None:
for item in form.player_instances.cleaned_data:
player = Player()
player.pname= item['pname']
player.hscore= item['hscore']
player.age= item['age']
player.save()
team.player.add(player)
team.save()
else:
form = TeamForm()
return render(request, 'packsapp/employee/new.html', {'form': form})
I have changed a couple of things. First of all, use lowercase for function based views, and try not to use the name 'form' in a view. Furthermore, notice the indentation: the 'if form.player_instances.cleaned_data...' has an extra indent. There is not much use checking players if there is no team, you will not be able to save the (non-existent) team. Then: the 'return'-statement is now on the same level as the first if/else statement. In your version there is no return after saving the form. By doing this, the filled-in form (from the if-part of the statement) is returned in the context-variable. It is then the job of the template to decide what to do with it. In the else-case, an empty form is returned.
I've noticed that this project is apparently a tutorial, there are at least two related questions on StackOverflow: Django Dynamic form for manytomany relationship and How can i save django dynamic formset data using forms and views. Maybe you can learn from those.
Additionally to the answer https://stackoverflow.com/a/61185348/13168118 of Matthieu-OD
you could change the
PlayerFormset= formset_factory(PlayerForm)
to a
modelformset_factory
https://docs.djangoproject.com/en/3.0/ref/forms/models/#django.forms.models.modelformset_factory
and in the init method of the 'TeamForm' you should be able to adjust the queryset of the modelformset to only show the players of this team
if you don't adjust it every player will be shown
EDIT:
i would also suggest that you use modelforms since your forms are for models:
https://docs.djangoproject.com/en/3.0/topics/forms/modelforms/#modelform
i also found this question which seems to be similar:
Django ModelForm for Many-to-Many fields

How to refresh the selection box when new option is added in Django?

I have a form with a selection box related to a foreign key (for example, category). And on the same page, I have another link that opens a new page to add a new instance of the foreign key. Once the new instance is added, how can I update the current form to add the new option, and preserve the text in the text field (just like how the admin page behaves)?
Here are some of my code snippets:
update_post.html:
...
<form method="post" novalidate action='.'>
{% csrf_token %}
{% include 'base_form.html' with form=form %}
# button to add a category
{% trans "Add category" %}
<button type="submit" class="btn btn-primary" name="publish" value={% trans 'Publish' %}>{% trans 'Publish' %}</button>
</form>
...
create_category.html:
...
<form action="./{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" method="post" novalidate>
{% csrf_token %}
{% include 'base_form.html' with form=form %}
<button type="submit" class="btn btn-primary" value={% trans 'Create' %}>{% trans 'Create' %}</button>
</form>
...
views.py:
...
class PostUpdate(UpdateView):
template_name = 'update_post.html'
success_url = '/'
model = Post
fields = ['title', 'body', 'category']
class CategoryCreate(CreateView):
template_name = 'create_category.html'
model = Category
fields = ['name']
def get_success_url(self):
if 'next' in self.request.GET:
return self.request.GET.get('next')
else:
return reverse('index')
...
What I want to do is that when a new category is added, it becomes available in the update_post page right away, and any changes to the body field are preserved.
I have done this yesterday inspired by django admin ForeignKey popup window add.my condition is a goods has goodcategory and i can add/edit/delet goodscategory in goods's add/update view and the result add/edit/delet goodcategory will sync to goods's add/update view.Here is a demo,which popup is support by layui.
as you can see i can add\change\delete ForeignKey without refresh the parent page.
first custom a new Field to ForeignKey which will receieve add_url\update_url\delete_url:
class ForeignKeyWidget(Select):
template_name = 'widgets/foreign_key_select.html'
def __init__(self, url_template, *args, **kw):
super(ForeignKeyWidget, self).__init__(*args, **kw)
# Be careful that here "reverse" is not allowed
self.url_template = url_template
def get_context(self, name, value, attrs):
context = super(ForeignKeyWidget, self).get_context(name, value, attrs)
context['add_url'] = self.url_template
context['update_url'] = self.url_template
context['delete_url'] = self.url_template + 'lang_delete/'
return context
second is custom a widget for your custom field which can popup add/update category windows and use ajax to delete category:
foreign_key_select.html:
{% include "django/forms/widgets/select.html" %}
<style>
#{{ widget.attrs.id }}_add, #{{ widget.attrs.id }}_change, #{{ widget.attrs.id }}_delete {
margin-top: 10px;
padding: 0 10px;
height: 25px;
line-height: 25px;
}
</style>
<a class="layui-btn layui-btn-mini" id="{{ widget.attrs.id }}_add">
add
</a>
<a class="layui-btn layui-btn-mini layui-btn-disabled" id="{{ widget.attrs.id }}_change">
change
</a><a class="layui-btn layui-btn-mini layui-btn-disabled" id="{{ widget.attrs.id }}_delete">
delete
</a>
<script>
$('#{{ widget.attrs.id }}_add').click(function () {
var index = layui.layer.open({
title: "add_category",
type: 2,
area: ['700px', '500px'],
content: "{{ add_url }}" + '?popup=1&to_field={{ widget.attrs.id }}',
success: function (layer, index) {
}
});
});
$("#{{ widget.attrs.id }}_change").click(function () {
var id = $('#{{ widget.attrs.id }}').val();
if (id) {
var index = layui.layer.open({
title: "change_category",
type: 2,
area: ['700px', '500px'],
content: '{{ update_url }}' + id + '?popup=1&to_field={{ widget.attrs.id }}',
success: function (layer, index) {
}
});
}
});
$("#{{ widget.attrs.id }}_delete").click(function () {
var id = $('#{{ widget.attrs.id }}').val();
var value = $('#{{ widget.attrs.id }} option[value=' + id + ']').text();
var indexGood = value.lastIndexOf('>');
var valueN = indexGood > 0 ? value.substring(indexGood + 1, value.length) : value;
if (id) {
layer.confirm('corform delete' + valueN + ' ?', {icon: 3, title: 'delete'}, function (index) {
$.ajax({
type: "POST",
data: {},
url: '{{ delete_url }}' + id + '/',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
},
success: function (data, textStatus) {
layer.close(index);
$('#{{ widget.attrs.id }} option[value=' + data.id + ']').remove();
$("#{{ widget.attrs.id }}_change,#{{ widget.attrs.id }}_delete").addClass('layui-btn-disabled');
return false;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
layer.alert('delete failed' + XMLHttpRequest.responseText)
}
});
});
}
});
function {{ widget.attrs.id }}_isDisabled() {
if ($('#{{ widget.attrs.id }}').val()) {
$("#{{ widget.attrs.id }}_change,#{{ widget.attrs.id }}_delete").removeClass('layui-btn-disabled');
} else {
$("#{{ widget.attrs.id }}_change,#{{ widget.attrs.id }}_delete").addClass('layui-btn-disabled');
}
}
$('#{{ widget.attrs.id }}').change(function () {
{{ widget.attrs.id }}_isDisabled();
});
{{ widget.attrs.id }}_isDisabled();
</script>
third is use your custom field for category in your forms.py:
class GoodsForm(ModelForm):
def __init__(self, *args, **kwargs):
super(GoodsForm, self).__init__(*args, **kwargs)
self.fields['category'].widget.attrs.update({'class': 'form-control'})
self.fields['title'].widget.attrs.update({'class': 'form-control'})
self.fields['content'].widget.attrs.update({'class': 'form-control'})
class Meta:
model = Goods
fields = ['category', 'title', 'content']
widgets = {
'category': ForeignKeyWidget(url_template=reverse_lazy('goods_category_ajax_create')),
}
and new a goodcategory form is forms.py
class GoodsCategoryForm(TranslatableModelForm):
def __init__(self, *args, **kwargs):
super(GoodsCategoryForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'class': 'form-control'})
self.fields['cover'].widget.attrs.update({'class': 'form-control'})
self.fields['parent'].widget.attrs.update({'class': 'form-control'})
class Meta:
model = GoodsCategory
fields = ['name', 'cover', 'parent']
four is handle request in your views.py:
class GoodsCategoryAjaxCreateView(BaseContextMixin, IsStaffUserMixin, CreateView):
form_class = GoodsCategoryForm
template_name = 'goods_category_ajax/create.html'
def get_context_data(self, **kwargs):
if 'to_field' in self.request.GET:
kwargs['to_field'] = self.request.GET['to_field']
return super(GoodsCategoryAjaxCreateView, self).get_context_data(**kwargs)
def form_valid(self, form):
self.object = form.save()
context = {'op': 'create', 'id': self.object.id, 'value': self.object.__str__()}
if 'to_field' in self.request.GET:
context['to_field'] = self.request.GET['to_field']
return TemplateResponse(self.request, 'goods_category_ajax/success.html', context=context)
class GoodsCategoryAjaxUpdateView(BaseContextMixin, IsStaffUserMixin, UpdateView):
model = GoodsCategory
form_class = GoodsCategoryForm
slug_field = 'id'
context_object_name = 'goods_category'
template_name = 'goods_category_ajax/update.html'
def get_context_data(self, **kwargs):
if 'to_field' in self.request.GET:
kwargs['to_field'] = self.request.GET['to_field']
return super(GoodsCategoryAjaxUpdateView, self).get_context_data(**kwargs)
def form_valid(self, form):
self.object = form.save()
context = {'op': 'create', 'id': self.object.id, 'value': self.object.__str__()}
if 'to_field' in self.request.GET:
context['update'] = self.request.GET['to_field']
return TemplateResponse(self.request, 'goods_category_ajax/success.html', context=context)
class GoodsCategoryAjaxLangDeleteView(BaseContextMixin, IsStaffUserMixin, FakeDeleteView):
model = GoodsCategory
slug_field = 'id'
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
data = {'op': 'delete', 'id': self.object.id, 'value': self.object.__str__()}
self.object.delete()
return JsonResponse(data=data)
urls.py:
url(r'^ajax/$', GoodsCategoryAjaxCreateView.as_view(), name='goods_category_ajax_create'),
url(r'^ajax/(?P<slug>\d+)/$', GoodsCategoryAjaxUpdateView.as_view(), name='goods_category_ajax_update'),
url(r'^ajax/lang_delete/(?P<slug>\d+)/$', GoodsCategoryAjaxLangDeleteView.as_view(),
name='goods_category_ajax_lang_delete'),
five is your add popup windows will open url handle by GoodsCategoryAjaxCreateView and the return template is:
{% extends "manage/base.html" %}
{% block main %}
<form id='goods_category_ajax_create' class="form-horizontal" enctype="multipart/form-data"
action="{% url 'goods_category_ajax_create' %}{% if to_field %}?to_field={{ to_field }}{% endif %}"
method="post">
{% include 'manage/widgets/form.html' %}
<div class="form-group">
<div class="col-sm-offset-1 col-sm-10">
<input class="layui-btn layui-btn-normal" type="submit" value="add_category"/>
</div>
</div>
</form>
{% endblock %}
you submit a new category with modelform and createview,when the form is_vaild a success.html will be return by TemplateResponse(as you can see in GoodsCategoryAjaxCreateView form_valid),and the point is success.html is nothing but a script that can close popup window and insert new option to the to_field element in parent window.here is success.html:
{% extends "manage/base.html" %}
{% block main %}
<script>
var to_field = '#{{ to_field }}', op = '{{ op }}', id = '{{ id }}', value = '{{ value }}';
if (to_field) {
switch (op) {
case 'create':
if (id) {
var index = parent.layer.getFrameIndex(window.name); //get current iFrame index
parent.layer.close(index); //close
$option = '<option value=' + id + ' selected>' + value + '</option>';
$(to_field, window.parent.document).append($option);
$(to_field + '_change,' + to_field + '_delete', window.parent.document).removeClass('layui-btn-disabled');
}
break;
case 'update':
if (id) {
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
$(to_field + ' option[value=' + id + ']', window.parent.document).html(value);
}
break;
}
}
</script>
{% endblock %}

GeoDjango - how to save GMap marker's coordinates into model

models.py:
class Location(models.Model):
name = models.CharField(max_length=100, verbose_name=u"Location", default=u'')
coords = gis_models.PointField(u"lng/lat", srid=4326, blank=True, null=True)
views.py:
class AddLocationPageView(CreateView):
model = Location
form_class = LocationForm
template_name = 'add_location.html'
forms.py:
class LocationForm(forms.ModelForm):
class Meta:
model = Location
fields = ['name'] # there is no 'coords'
add_location.html:
<form action="" method="POST" enctype="multipart/form-data">{% csrf_token %}
<div id="map-add-location" ></div> # place for GMap
<div>
{{ form.as_p }}
<button type="submit">Add</button>
</div>
</form>
js:
$(document).ready(function(){
var mapOptions = ...
map = new google.maps.Map($('#map-add-location')[0], mapOptions);
map.addListener('click', function(e){
placeMarker(e.latLng, map);
var position = marker.getPosition();
var lat_input = $('<input type="hidden" name="lat"/>');
var lng_input = $('<input type="hidden" name="lng"/>');
$(lat_input).insertBefore($('#id_name'));
$(lng_input).insertBefore($('#id_name'));
$(lat_input).val(position.lat());
$(lng_input).val(position.lng());
});
var marker;
function placeMarker(latLng, map) {
marker = new google.maps.Marker({
position: latLng,
map: map,
});
return marker
}
});
I am confused. I do not understand what I should do further.
Please, help.. how can I save the lat and lng values in the 'coords' field of Location model ?
Thanks!!!