So Create_Watchlist is a model with a Foreignkey to the User Model and 'ticker' is a CharField of Create_Watchlist. Here is my views.py function for the approach
def watchlist_one(request, pk):
Create_Watchlist.objects.get(id=pk)
list_ticker = list(Create_Watchlist.objects.all().values_list('ticker', flat=True))
At the moment list_ticker equals ['AAPL, BTC']
I want to access in this case 'AAPL' and 'BTC' as different list objects, because I want to make an API request with each list item. The list_ticker variable changes with the users input from a form . So there could be smt like ['AAPL, BTC'], but as well smt like ['FB'] (etc.)
If I've made a mistake here, an explanation of how to deal with query sets and data types would also help me!
Thanks a lot :)
Related
I'm looking at this tutorial from the Mozilla library. I want to create a list view in admin based on a database relationship. For example I have a Vehicle model and a statusUpdate model. Vehicle is a single instance with many statusUpdates. What I want to do is select the most recent statusUpdate (based on the dateTime field I have created) and have that data available to me in the list view.
The tutorial mentions:
class Vehicle(models.Model):
class statusUpdate(models.Model):
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
Question: How could I do a list view with model relationships and be able to filter by fields on the child relationship and pass to the view?
Here's what I wanted in a Class Based View (CBV), my explanation of my issue was not very clear.
def get_context_data(self, **kwargs):
get_context_data is a way to get data that is not normally apart of a generic view. Vehicle is already provided to the View because its the model defined for it, if you wanted to pass objects from a different model you would need to provide a new context, get_context_data is the way to do this. statusUpdate is a model with a foreign key to Vehicle. Full example below.
class VehicleDetail(generic.DetailView):
model = Vehicle
template_name = 'fleetdb/detail.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(VehicleDetail, self).get_context_data(**kwargs)
context['updates'] = statusUpdate.objects.filter(vehicle_id=1).order_by('-dateTime')[:5]
return context
I don't think that solves your problem entirely. You used this:
context['updates'] = statusUpdate.objects.filter(vehicle_id=1).order_by('-dateTime')[:5]
This will only result in a list of statusUpdates where vehicle_id is set to 1. The part I was struggling with is how to get the primary key (in your case the actual vehicle_id). I found this solution:
vehicle_id = context['vehicle'].pk # <- this is the important part
context['updates'] = statusUpdate.objects.filter(vehicle_id=vehicle_id).order_by('-dateTime')[:5]
I discovered the context object and it contains the data which has already been added (thus you need to call super before using it). Now that I write it down it seems so obvious, but it took me hours to realize.
Btw. I am pretty new to Django and Python, so this might be obvious to others but it wasn't to me.
I know that many questions exist about this same topic, but i am confused on one point.
My intent is to show two ModelChoiceFields on the form, but not directly tie them to the Game model.
I have the following:
forms.py
class AddGame(forms.ModelForm):
won_lag = forms.ChoiceField(choices=[('1','Home') , ('2', 'Away') ])
home_team = forms.ModelChoiceField(queryset=Player.objects.all())
away_team = forms.ModelChoiceField(queryset=Player.objects.all())
class Meta:
model = Game
fields = ('match', 'match_sequence')
Views.py
def game_add(request, match_id):
game = Game()
try:
match = Match.objects.get(id=match_id)
except Match.DoesNotExist:
# we have no object! do something
pass
game.match = match
# get form
form = AddGame(request.POST or None, instance=game)
form.fields['home_team'].queryset = Player.objects.filter(team=match.home_team )
# handle post-back (new or existing; on success nav to game list)
if request.method == 'POST':
if form.is_valid():
form.save()
# redirect to list of games for the specified match
return HttpResponseRedirect(reverse('nine.views.list_games'))
...
Where i am confused is when setting the queryset filter.
First i tried:
form.home_team.queryset = Player.objects.filter(team=match.home_team )
but i got this error
AttributeError at /nine/games/new/1
'AddGame' object has no attribute 'home_team'
...
so i changed it to the following: (after reading other posts)
form.fields['home_team'].queryset = Player.objects.filter(team=match.home_team )
and now it works fine.
So my question is, what is the difference between the two lines? Why did the second one work and not the first? I am sure it is a newbie (i am one) question, but i am baffled.
Any help would be appreciated.
Django Forms are metaclasses:
>>> type(AddGame)
<class 'django.forms.forms.DeclarativeFieldsMetaclass'>
They basically create a form instance according to the information given in its definition. This means, you won't get exactly what you see when you define the AddGame form. When you instantiate it, the metaclass will return the proper instance with the fields provided:
>>> type(AddGame())
<class 'your_app.forms.AddGame'>
So, with the instance, you can access the fields by simply doing form.field. In fact, it is a bit more complicated than that. There are two types of fields you can access. With form['field'] you'll be accessing a BoundField. Which is used for output and raw_input.
By doing form.fields['fields'] you'll be then accessing to a field that python can understand. This is because if the from already got any input, there's where validation and data conversion take places (in fact, those are the fields used for this, the general process of validation is a bit more complicated).
I hope this might clear a little the issue for you but as you may see, the whole form's API is really big and complicated. Is very simple for end-users but it has a lot of programming behind the curtains :)
Reading the links provides will help clear your doubts and will improve your knowledge about this very useful topic and Django in general.
Good luck!
UPDATE: By the way, if you want to learn more about Python's Metaclasses, this is a hell of an answer about the topic.
In you views.py, you have this line:
form = AddGame(request.POST or None, instance=game)
So form is a Form object of class AddGame (Side note: you should change the name to AddGameForm to avoid confusion).
Since home_team is a field in AddGame class, it's not an attribute in form object. That's why you can't access it via form.home_team.
However, Django Form API provides fields attribute to any form object, which is a dict contains all form fields. That's why you can access form.fields['home_team'].
And finally since home_team is a ModelChoiceField, it can contain a queryset attribute, that's why you can access form.fields['home_team'].queryset
Let's say we have an app called Closet and it has some models:
# closet.models.py
class Outfit(models.Model):
shirt = models.ForeignKey(Shirt)
pants = models.ForeignKey(Trouser)
class Shirt(models.Model):
desc = models.TextField()
class Trouser(models.Model):
desc = models.TextField()
class Footwear(models.Model):
desc = models.TextField
Using generic detail view, it's easy to make the URL conf for details on each of those:
#urls.py
urlpatterns = patterns('',
url(r'^closet/outfit/(?P<pk>\d+)$', DetailView(model=Outfit), name='outfit_detail'),
url(r'^closet/shirt/(?P<pk>\d+)$', DetailView(model=Shirt), name='shirt_detail'),
url(r'^closet/trouser/(?P<pk>\d+)$', DetailView(model=Trouser), name='trouser_detail'),
url(r'^closet/footwear/(?P<pk>\d+)$', DetailView(model=Footwear), name='footwear_detail'),
)
What I'd like to do next is define the views that will create a new object of each type. I would like to do this with an extended version of CreateView which will be able to handle data on pre-populated fields.
Specifically, I want the following behavior:
If I visit /closet/outfit/new I want to get a standard ModelForm for the Outfit model with everything blank and everything editable.
If I visit /closet/outfit/new/?shirt=1 I want to see all the fields I saw in case 1) but I want the shirt field to be pre-populated with the shirt with pk=1. Additionally, I want the shirt field to be displayed as un-editable. If the form is submitted and is deemed to be invalid, when the form is redisplayed I want the shirt field to continue to be un-editable.
If I visit /closet/outfit/new/?shirt=1&trouser=2 I want to see all the fields I saw in case 1) but now both the shirt and trouser fields should be preopoulated and uneditable. (I.e. only the footwear field should be editable.)
In general, is this possible? I.e. can the querystring modify the structure of the displayed form in this way? I want to accomplish this in the DRYest way possible. My gut tells me this should be doable with class based views and perhaps would involve model_form_factory but I can't get the logic straight in my mind. In particular, I wasn't sure whether it was possible to have the class-based-view access the request.REQUEST (i.e. the request.POST or request.GET parameters) at the time that the ModelForm is being constructed.
Perhaps its possible only if I use different querystring keywords for the locked fields. I.e. perhaps the URL's need to be: /closet/outfit/new/?lock_shirt=1 and /closet/outfit/new?lock_shirt=1&lock_trouser=2. Perhaps if its done that way the POST handler would be handed both a list of locked fields (for the purposes of form display in the browser) along with a regular list of all the model fields for the purpose of actually creating the object.
Why do I want this: In the template for the footwear_detail I would want to be able to make a tag like
<a href="{% url outfit_new %}?footwear={{object.pk}}>Click to create a new outfit with this footwear!</a>
In general, it would be really useful to be able to make links to forms whose "structure" (not just values) changes depending on the querystring passed.
Responding to the great suggestion from Berislav Lopac:
So I went ahead and did:
class CreateViewWithPredefined(CreateView):
def get_initial(self):
return self.request.GET
This gets me 90% of what I need. But let me flesh out the situation a bit more. Say I add two fields to the Outfit model: headgear = models.ManyToManyField('headgear') and awesomeness_rating = models.FloatField().
Two problems:
If I visit /closet/outfit/new/?awesomeness_rating=10 then my form pre-fills with [u'10'] instead of just filling with 10. Is there a filter I should use in my template or a bit of processing I can add to my view to make the formatting more appropriate?
If I want to pre-specify a few pieces of headwear, what is the right format to pass what feels like a python list in through a query string? I.e. should I do /closet/outfit/new/?headgear=1,2,3? If so, will Django correctly figure out that I'd like to pre-select the 3 pieces of headgear with those ID's?
Continuing to work on this...
class CreateViewWithPredefined(CreateView):
def get_initial(self):
initial = super(CreateView, self).get_initial()
for k, v in self.request.GET.iterlists():
if len(v) > 1:
initial.update({ k : v })
else:
initial.update({ k : v[0] })
return initial
This seems to kill 2 birds with one stone: numerical data gets coerced from unicode to numerical and it flattens lists when possible (as intended). Need to check if this works on multi-valued fields.
It's self.request, anywhere in a CBV. :-)
OK, let me make this answer more comprehensive. Basically, what you want is the get_initial method, which is contributed by the FormMixin. Override it to populate the initial values for your fields.
I'm trying to restrict the selectable values of a 'persons' field in a particular form.
I have a TaskPerson model that has two foreign keys: one for 'task' one for 'person'.
In my form, the persons field should allow the user to select one or more persons, but only those persons which match a certain task.
I've attempted this:
persons = [tp.person for tp in TaskPerson.objects.filter(task=thistask)]
form.fields["persons"].queryset = persons
This list comprehension gives me the correct person objects I require, but my form doesn't display at all, presumably because it gives me only a standard python list.
I had a look over the docs, but I'm not quite sure how to progress. Could someone please advise how I can correctly display my form?
Many thanks
You can easily get a QuerySet of Person objects by following the reverse relationship to TaskPerson
http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
form.fields['field'].queryset = Person.objects.filter(taskperson__task=thistask)
Here, I am a bit confused with forms in Django. I have information for the form(a poll i.e the poll question and options) coming from some db_table - table1 or say class1 in models. Now the vote from this poll is to be captured which is another model say class2. So, I am just getting confused with the whole flow of forms, here i think. How will the data be captured into the class2 table?
I was trying something like this.
def blah1()
get_data_from_db_table_1()
x = blah2Form()
render_to_response(blah.html,{...})
Forms have nothing to do with models in Django. They are just class meant to get informations from a dictionary (often request.POST) and check if each data linked to a key match a type and a format (e.g: is this a string of the form "bla#foo.tld").
You can ask django to create a form from a model, and in that case it will do its checking job, then if the data match, it will create a model, fill it and save it.
If a form is not created from a model, it will do nothing but checking. It will save nothing.
If it is created from a model, it will create a new instance of this particular model instance and save it.
If you want something more complicated, like, pre fill a form from various models or according to some conditions, or, say, you need to save several models according to the result of one form, you must do it manually.