I need to customize the admin panel added to the model page related inputs from another model. But I can not figure out how to save them.
admin.py
class OrderAdmin(admin.ModelAdmin):
change_form_template = 'admin/testapp/order/change_form.html'
def change_view(self, request, object_id, extra_context=None):
order = Order.objects.get(id=object_id)
card_list = Card.objects.all().filter(type=order.type)
result = super(OrderAdmin, self).change_view(request, object_id, extra_context={
'card_list': card_list,
})
return result
change_form.html
{% for card in card_list %}
<input type="text" name="card-{{ card.id}}" value="{{ card.qty }}"></td>
{% endfor %}
How to save the changed values in the Card model?
I tried to do as described here:
https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#adding-custom-validation-to-the-admin
But self.cleaned_data does not include my data from inputs.
Thanks.
UPD: Well, I caught the data, but I think it's pretty messy way.
I'm hardly can imagine how I would calculate the id from inputs.
def save_model(self, request, obj, form, change):
request.POST['card-288']
Saving should be done in save_model. Your card_list data should also be would have been available in the form parameter if you had used django forms. Although you could still access it through request as you correctly pointed out.
You will also have to sanitize the data yourself, something that django forms does for your automatically.
You are getting exactly what you produced :), nothing unexpected there!
You must override clean (take a look here for instance) if you want some fields that you manually added in the change_list to be taken care of.
If you go that way, to retrieve the ID is up to you, but a simple split('-')[-1] would work.
This answers your specific need.
On the other side, I think your are not going the right way. The django admin is good enough to deal with ForeignKeys ManyToMany, so I see no need to do things yourself.
While you can get it working with the above hint, I suggest you start all over - if you want, a new SO question where you publish the initial Model and what exactly you are trying to achieve.
Related
I have a generic ListView which displays all objects from a model and I would like users to be able to choose one object for further processing by storing in session or in another model. What would be the best way to go about this?
views.py
class TranscriptListView(generic.ListView):
model = Transcript
template_name = 'transcript_list.html'
template
{% block content %}
<ul>
{% for transcript in transcript_list %}
<li>
{{transcript.name}}
<p>{{transcript.text}}</p>
</li>
{% endfor %}
</ul>
For selecting something to store in a session, I'd just do a
class SelectTranscriptView(SingleObjectMixin, View):
model = Transcript
def post(self, request, *args, **kwargs):
object = self.get_object()
request.session['selected_transcript'] = object.id
return redirect(...)
This view only accepts POST, since GET requests should be idempotent, i.e. they should not modify any state. Setting a session value is definitely modifying state. This means you'll need to use a form (or a JavaScript function) to POST data to the URL you hook this up to.
More importantly, though: Setting something in the session is not necessarily a good idea at all. Consider an advanced user deciding to open multiple tabs to your site, and trying to select one transcript for one tab, and another in the other tab. This won't be possible if you store the selected thing in the session! Instead, I'd design things so the ID of the object being edited or viewed is always in the URL (as happens with DetailViews and the ilk anyway).
I think this works, but I came across a couple of things before getting it to work that I want to understand better, so the question. It also looks like other people do this a variety of ways looking at other answers on stack overflow. What I am trying to avoid is having the user to have to select his username from the pulldown when creating a new search-profile. The search profile model is:
class Search_Profile(models.Model):
author_of_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,blank=True)
keyword_string = models.CharField(max_length=200)
other_stuff = models.CharField(max_length=200)
The form I ended up with was:
class Search_Profile_Form(ModelForm):
class Meta:
model = Search_Profile
fields = [ 'keyword_string', 'other_stuff']
Where I deliberately left out 'author_of_profile' so that it wouldn't be shown or need to be validated. I tried hiding it, but then the form would not save to the model because a field hadn't been entered. If I was o.k. with a pulldown I guess I could have left it in.
I didn't have any issues with the HTML while testing for completeness:
<form action="" method="POST">
{% csrf_token %}
{{ form.author_of_profile}}
{{ form.keyword_string }}
{{ form.other_stuff }}
<input type="submit" value="Save and Return to Home Page">
</form>
And the View is where I ended up treating the form and the model separated, saving the form first, then updating the model, which is where I think there might be some other way people do it.
def New_Profile(request):
if request.method=='POST':
form = Search_Profile_Form(request.POST)
if form.is_valid():
post=form.save(commit=False)
# here is where I thought I could update the author of profile field somehow with USER
# but If I include the author_of_profile field in the form it seems I can't.
post.save()
#So instead I tried to update the author_of profile directly in the model
current_profile=Search_Profile.objects.last()
current_profile.author_of_profile=request.user
current_profile.save()
return(redirect('home'))
else:
form=Search_Profile_Form()
return render(request, 'mainapp/New_Profile.html', {'form': form})
So a few questions:
For the Foreign Key in author_of_profile field, is it better to use blank=True, or null=True
I ended up using request.user rather than importing from django.contrib.auth.models import User is there any difference?
My real question though, is the above a reasonable way to get form data and update the database with that data and the user? Or am I missing some other way that is more build in?
post=form.save()
current_profile.author_of_profile=request.user
post.save()
return(redirect('home'))
try something like this. save the form to db then change the author again. save(commit=False) will not save the date to db immediately.
Around one year ago I started to write my first application in PyQt5, where there are many fields:
I know it's not good-looking, but the main point was to learn PyQt5.
Now I want to make it useable on mobile. Since there are many people after IT studies knowing Java, I think I have a better chance to get the first job knowing Django + Javascript/jQuery. Here is the question:
Each "F1, F2, F3" is a separate widget. The screen on a phone is small, so I think about displaying them one by one. Easiest approach is probably this way (.html), but maybe there is a better one:
{% for field in GoldArrays %}
<p>{{field.text}} <input type="number" name="textfield"> {{field.number}}</p>
{% endfor %}
It's for F3/F4 widget. 'text' will return 200zl, 100zl, etc, number is just a DecimalField.
The thing is I'm very fresh to web development and Django. As I understand I should create a separate template for each widget. I want to collect data from a widget after pressing "next" button and then store it to SQLite database, so the progress will be saved. Should I put sql queries in views.py? What should be in forms.py and models.py? An example of two user inputs is highly appreaciated.
Here is the next question... There is a decent chance, that I'll want to set some rules for many fields, like highlighting value so the user doesn't need to delete the value, or to automatically set 0 in case there is None as input. I know I can do that with JS later, but can I do it with Django? I hope to write a code, that is easy to maintain.
Help please :)
Using views (controllers in Django) you can add context data.
It has next structure:
{% for item in form_set %}
{{ item }}
{% endfor %}
Jinja2 is templating language, so all vars from backend you must write in brackets
{{ each_var_from_django }}
View will be next:
class CreateOrderView(LoginRequiredMixin, CreateView):
template_name = 'dashboard/index.html'
success_url = reverse_lazy('namespace:url')
def get_context_data(self, *args, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['form_set'] = Model.objects.filter()
return ctx
Say you already have a complex HTML form, possible from a designer, front end dev, etc. Is it common practice to not use dynamic forms (based on a Django form) for complicated forms?
I want to do something like this:
1.) Create custom HTML form.
2.) Catch form data through POST request, put it in an object/dictionary.
3.) Do some manipulations with that data to get it in a format acceptable by a Django form.
4.) Pass the manipulated data in to a form object, validate it, etc...
What is a clear solution to this problem? Should I be using Django's dynamic forms for everything? If not - how do I implement the above?
EDIT:
Part of my question has to do with using the forms ONLY for validation. I don't think I made this clear. Here is what I'm trying to do:
template.html
<form method="post">
{% csrf_token %}
<input class="foo" name="bar" type="text" value=""/>
<!-- Some more fields, not rendered through Django form -->
<button type="submit">Create Object</button>
</form>
As you can see, other than the csrf_token there is no Django code here. What I am trying to do in my view is catch the data in the POST in my view, make some changes to the data, then try to bind the new data to a form (not sure if it's possible):
views.py
def my_view(request):
# Some GET code
if request.method == 'POST':
form = ImportedForm(request.POST)
form.data['foo'] = "newValue"
# Now after changing the data, validate it...
If the form and model match nicely then I'll take advantage of the ModelForm functionality.
But most of the time it is not so tidy so, most typically, I do things in about this order:
create a django form with all the field definitions
create django GET view to serve the empty form
create an html template which serves the default html/form
test the blank form
create the POST routine to call validation and reserve the validated (erroneous) form
modify the django form to validate the fields
modify the html form to serve the error messages
test the validation and error messages
modify the POST routine to handle a valid form and do whatever it should do as a result (might involve a redirect and 'thanks' view/template)
Test the whole lot
let the designer loose on the templates
In truth the designer will be involved at some points earlier along the way but in theory I just get it all to work as a "white" then add all the fancy stuff after. That includes javascript validation (ie after all the above).
I ended up doing something like this. It is ugly, and may not be the proper way to do it, but it works...
if request.method == 'POST':
try:
# Create dictionary from POST data
data = {
'foo': request.POST['foo'],
'foobar': request.POST['foobar'],
}
except:
# Handle exceptions
form = ImportedForm(data)
if form.is_valid:
# Continue to validate and save
I have this models in Django:
News
Comments
Reactions
Relations are:
a News has various Comments
a Comment has various Reactions
The problem is the user (in request / session): the user may subscribe to a reaction, or a comment; he may be logged in or not. (it's a foo example, it doesn't have much sense)
I can't do in template:
{% for reaction in this_news.comments.reactions %}
{{ reaction.name }}
{% if reaction.user_subscribed %} #reaction.user_subscribed(request.user)...
You have subscribed this reaction!
{% endif %}
{% endfor %}
Problems are:
I can't call the method in the template with a parameter (see the comment above)
Models don't have access to request
Now i'm calling an init_user method in News Model, passing the request. Then i have the same method in Comment and Reaction model, and i have to set the user_subscribed property cycling the children of each model.
Isn't there a smarter way to do this?
EDIT: thanks to the Ignacio's hint about using custom tag i'm trying to do a generic mode to pass the user (avoiding the use of closures because i don't know how to use them atm):
def inject_user(parser, token):
try:
# split_contents() knows not to split quoted strings.
tag_name, method_injected, user = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError("%r tag requires exactly three arguments" % token.contents.split()[0])
return InjectUserNode(method_injected, user)
class InjectUserNode(template.Node):
def __init__(self, method_injected, user):
self.method_injected = template.Variable(method_injected)
self.user = template.Variable(user)
def render(self, context):
try:
method_injected = self.method_injected.resolve(context)
user = self.user.resolve(context)
return method_injected(user)
except template.VariableDoesNotExist:
return ''
When i use it {% inject_user object.method_that_receives_a_user request.user %} i come to this error 'str' object is not callable in method_injected(user); how i can fix that?
Write custom template tags that take the user and set a context variable to indicate presence or absence of the criterion.
I've resolved it in a less elegant way, but it worked for me.
I've created a sort of singleton in my User defined class, with a property that i set in every view i need it.
The property is User.current.
Then, inside the models, where i need that i get the current user looking in User.current.